use lib display text to display help messages (FS#10099).
[kugel-rb.git] / apps / plugins / clix.c
blob78bfdb8fdff98956a8562564835d164f463d5d10
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 #define CLIX_BUTTON_QUIT BUTTON_POWER
144 #define CLIX_BUTTON_CLICK BUTTON_MENU
146 #elif (CONFIG_KEYPAD == MROBE500_PAD)
147 #define CLIX_BUTTON_QUIT BUTTON_POWER
149 #else
150 #error "no keymap"
151 #endif
153 #ifndef CLIX_BUTTON_CLICK
154 #define CLIX_BUTTON_CLICK BUTTON_CENTER
155 #endif
157 #define HIGHSCORE_FILE PLUGIN_GAMES_DIR "/clix.score"
158 #define NUM_SCORES 5
159 struct highscore highest[NUM_SCORES];
161 #define NUM_LEVELS 9
162 #define BLINK_TICKCOUNT 25
163 #define MARGIN 5
165 #if (LCD_WIDTH >= LCD_HEIGHT)
166 #define BOARD_WIDTH 18
167 #define BOARD_HEIGHT 12
168 #else
169 #define BOARD_WIDTH 12
170 #define BOARD_HEIGHT 18
171 #endif
173 #if (LCD_WIDTH >= 306 && LCD_HEIGHT>= 204)
174 #define CELL_SIZE 16
176 #elif (LCD_WIDTH >= 270 && LCD_HEIGHT>= 180)
177 #define CELL_SIZE 14
179 #elif (LCD_WIDTH >= 234 && LCD_HEIGHT>= 156)
180 #define CELL_SIZE 12
182 #elif (LCD_WIDTH >= 198 && LCD_HEIGHT>= 132)
183 #define CELL_SIZE 10
185 #elif (LCD_WIDTH >= 162 && LCD_HEIGHT>= 108)
186 #define CELL_SIZE 8
188 #elif (LCD_WIDTH >= 126 && LCD_HEIGHT>= 84)
189 #define CELL_SIZE 6
191 #elif (LCD_WIDTH >= 60)
192 #define CELL_SIZE 4
193 #endif
195 #define XYPOS(x,y) ((y) * BOARD_WIDTH + x)
196 #define XOFS LCD_WIDTH/2-(BOARD_WIDTH * (CELL_SIZE + 1)/2)
197 #define YOFS (LCD_HEIGHT+10)/2-(BOARD_HEIGHT * (CELL_SIZE + 1)/2)
200 struct clix_game_state_t {
201 int level; /* current level */
202 int score; /* current game score */
203 int x,y; /* current positions of the cursor */
204 int board[BOARD_WIDTH * BOARD_HEIGHT]; /* play board*/
205 /* state of selected fields,maybe we can store this in the play board too */
206 bool board_selected[ BOARD_WIDTH * BOARD_HEIGHT];
207 int selected_count;
208 int status;
209 bool blink; /* true if selected CELLS are currently white */
212 /* game state enum */
213 enum {
214 CLIX_GAMEOVER = -1,
215 CLIX_CONTINUE,
216 CLIX_CLEARED
219 /* cell color enum */
220 enum {
221 CC_BLACK = -1,
222 CC_BLUE,
223 CC_GREEN,
224 CC_RED,
225 CC_YELLOW,
226 CC_ORANGE,
227 CC_CYAN,
228 CC_BROWN,
229 CC_PINK,
230 CC_DARK_BLUE,
231 CC_DARK_GREEN
234 /* display the highscore list and highlight the last one */
235 static void clix_show_highscores(int position)
237 int i, w, h;
238 char str[30];
240 #ifdef HAVE_LCD_COLOR
241 rb->lcd_set_background(LCD_BLACK);
242 rb->lcd_set_foreground(LCD_WHITE);
243 #endif
244 rb->button_clear_queue();
245 rb->lcd_clear_display();
247 rb->lcd_setfont(FONT_UI);
248 rb->lcd_getstringsize("High Scores", &w, &h);
249 /* check wether it fits on screen */
250 if ((4*h + h*(NUM_SCORES-1) + MARGIN) > LCD_HEIGHT) {
251 rb->lcd_setfont(FONT_SYSFIXED);
252 rb->lcd_getstringsize("High Scores", &w, &h);
254 rb->lcd_putsxy(LCD_WIDTH/2-w/2, MARGIN, "High Scores");
255 rb->lcd_putsxy(LCD_WIDTH/4-w/4,2*h, "Score");
256 rb->lcd_putsxy(LCD_WIDTH*3/4-w/4,2*h, "Level");
258 for (i = 0; i<NUM_SCORES; i++)
260 #ifdef HAVE_LCD_COLOR
261 if (i == position) {
262 rb->lcd_set_foreground(LCD_RGBPACK(245,0,0));
264 #endif
265 rb->snprintf (str, sizeof (str), "%d)", i+1);
266 rb->lcd_putsxy (MARGIN,3*h + h*i, str);
267 rb->snprintf (str, sizeof (str), "%d", highest[i].score);
268 rb->lcd_putsxy (LCD_WIDTH/4-w/4,3*h + h*i, str);
269 rb->snprintf (str, sizeof (str), "%d", highest[i].level);
270 rb->lcd_putsxy (LCD_WIDTH*3/4-w/4,3*h + h*i, str);
271 if(i == position) {
272 #ifdef HAVE_LCD_COLOR
273 rb->lcd_set_foreground(LCD_WHITE);
274 #else
275 rb->lcd_hline(MARGIN, LCD_WIDTH-MARGIN, 3*h + h*(i+1));
276 #endif
279 rb->lcd_update();
280 rb->button_get(true);
281 rb->lcd_setfont(FONT_SYSFIXED);
284 /* recursive function to check if a neighbour cell is of the same color
285 if so call the function with the neighbours position
287 static void clix_set_selected(struct clix_game_state_t* state,
288 const int x, const int y)
290 state->selected_count++;
291 state->board_selected[ XYPOS( x, y)] = true;
292 int current_color = state->board[ XYPOS( x, y)];
294 if( (x - 1) >= 0 &&
295 state->board[ XYPOS( x - 1, y)] == current_color &&
296 state->board_selected[ XYPOS(x - 1, y)] == false)
297 clix_set_selected( state, x - 1, y);
299 if( (y + 1) < BOARD_HEIGHT &&
300 state->board[ XYPOS( x, y + 1)] == current_color &&
301 state->board_selected[ XYPOS(x, y + 1)] == false)
302 clix_set_selected( state, x, y + 1);
304 if( (x + 1) < BOARD_WIDTH &&
305 state->board[ XYPOS( x + 1, y)] == current_color &&
306 state->board_selected[ XYPOS(x + 1, y)] == false)
307 clix_set_selected( state, x + 1, y);
309 if( (y - 1) >= 0 &&
310 state->board[ XYPOS( x, y - 1)] == current_color &&
311 state->board_selected[ XYPOS(x, y - 1)] == false)
312 clix_set_selected( state, x, y - 1);
315 /* updates "blinking" cells by finding out which one is a valid neighbours */
316 static void clix_update_selected(struct clix_game_state_t* state)
318 int i;
320 for( i = 0; i < BOARD_WIDTH * BOARD_HEIGHT; ++i)
322 state->board_selected[i] = false;
324 state->selected_count = 0;
326 /* recursion starts here */
327 clix_set_selected( state, state->x, state->y);
330 /* inits the board with new random colors according to the level */
331 static void clix_init_new_level(struct clix_game_state_t* state)
333 int i;
334 int r;
336 state->y = BOARD_HEIGHT / 2;
337 state->x = BOARD_WIDTH / 2;
339 rb->srand( *rb->current_tick);
340 /* create a random colored board, according to the current level */
341 for(i = 0; i < BOARD_HEIGHT * BOARD_WIDTH; ++i)
343 r = rb->rand() % (state->level + 1);
344 state->board[i] = r;
348 /* this inits the game state structure */
349 static void clix_init(struct clix_game_state_t* state)
351 state->level = 1;
352 state->score = 0;
353 state->blink = false;
354 state->status = CLIX_CONTINUE;
356 clix_init_new_level(state);
358 clix_update_selected(state);
361 /* Function for drawing a cell */
362 static void clix_draw_cell(struct clix_game_state_t* state, const int x, const int y)
364 int realx = XOFS;
365 int realy = YOFS;
367 realx += x * (CELL_SIZE + 1);
368 realy += y * (CELL_SIZE + 1);
370 if (state->blink && state->board_selected[ XYPOS( x, y)]) {
371 rb->lcd_set_foreground(LCD_WHITE);
372 } else {
373 switch (state->board[ XYPOS( x, y)])
375 case CC_BLUE:
376 rb->lcd_set_foreground( LCD_RGBPACK( 25, 25, 255));
377 break;
378 case CC_GREEN:
379 rb->lcd_set_foreground( LCD_RGBPACK( 25, 255, 25));
380 break;
381 case CC_RED:
382 rb->lcd_set_foreground( LCD_RGBPACK( 255, 25, 25));
383 break;
384 case CC_YELLOW:
385 rb->lcd_set_foreground( LCD_RGBPACK( 225, 225, 25));
386 break;
387 case CC_ORANGE:
388 rb->lcd_set_foreground( LCD_RGBPACK( 230, 140, 15));
389 break;
390 case CC_CYAN:
391 rb->lcd_set_foreground( LCD_RGBPACK( 25, 245, 230));
392 break;
393 case CC_BROWN:
394 rb->lcd_set_foreground( LCD_RGBPACK(139, 69, 19));
395 break;
396 case CC_PINK:
397 rb->lcd_set_foreground( LCD_RGBPACK(255, 105, 180));
398 break;
399 case CC_DARK_GREEN:
400 rb->lcd_set_foreground( LCD_RGBPACK( 0, 100, 0));
401 break;
402 case CC_DARK_BLUE:
403 rb->lcd_set_foreground( LCD_RGBPACK( 280, 32, 144));
404 break;
405 default:
406 rb->lcd_set_foreground( LCD_BLACK);
407 break;
411 rb->lcd_fillrect( realx, realy, CELL_SIZE, CELL_SIZE);
413 /* draw cursor */
414 if ( x == state->x && y == state->y) {
415 rb->lcd_set_foreground( LCD_WHITE);
416 rb->lcd_drawrect( realx - 1, realy - 1, CELL_SIZE + 2, CELL_SIZE + 2);
420 /* main function of drawing the whole board and score... */
421 static void clix_draw(struct clix_game_state_t* state)
423 int i,j;
424 char str[30];
426 /* Clear screen */
427 rb->lcd_clear_display();
428 rb->lcd_set_foreground( LCD_WHITE);
430 rb->lcd_putsxy( MARGIN, MARGIN, "Score:");
431 rb->snprintf( str, sizeof(str), "%d", state->score);
432 rb->lcd_putsxy( 43, MARGIN, str);
433 #if LCD_WIDTH <= 100
434 rb->lcd_putsxy( 75, MARGIN, "L:");
435 rb->snprintf( str, sizeof(str), "%d", state->level);
436 rb->lcd_putsxy( 90, MARGIN, str);
437 #else
438 rb->lcd_putsxy( 75, MARGIN, "Level:");
439 rb->snprintf( str, sizeof(str), "%d", state->level);
440 rb->lcd_putsxy( 113, MARGIN, str);
441 #endif
442 for( i = 0; i < BOARD_WIDTH; ++i)
444 for( j = 0; j < BOARD_HEIGHT; ++j)
446 clix_draw_cell( state, i, j);
450 rb->lcd_update();
453 static void clix_move_cursor(struct clix_game_state_t* state, const bool left)
455 int x, y;
457 x = state->x;
460 y = state->y;
461 while(state->board[ XYPOS( x, y)] == CC_BLACK && y < BOARD_HEIGHT) y++;
462 if (y < BOARD_HEIGHT) {
463 state->y = y;
464 state->x = x;
466 else
468 if (left) {
469 if( x >= 0)
470 x--;
471 else
472 y = state->y;
474 else
476 if( x < BOARD_WIDTH - 1)
477 x++;
478 else
479 x = 0;
482 } while ( y != state->y);
486 /* returns the color of the given position, if out of bounds return CC_BLACK */
487 static int clix_get_color(struct clix_game_state_t* state, const int x, const int y)
489 if( x >= 0 && x < BOARD_WIDTH && y >= 0 && y < BOARD_HEIGHT)
490 return state->board[XYPOS( x, y)];
491 else
492 return CC_BLACK;
495 static int clix_clear_selected(struct clix_game_state_t* state)
497 int i, j, x, y;
499 state->status = CLIX_CLEARED;
501 /* clear the selected blocks */
502 for( i = 0; i < BOARD_WIDTH; ++i)
504 for( j = 0; j < BOARD_HEIGHT; ++j)
506 if( state->board_selected[ XYPOS( i, j)] )
508 state->board_selected[ XYPOS( i, j)] = false;
509 state->board[ XYPOS( i, j)] = CC_BLACK;
514 /* count score */
515 state->score += state->selected_count * state->level;
516 state->selected_count = 0;
518 /* let blocks falling down */
519 for( i = BOARD_WIDTH - 1; i >= 0; --i)
521 for( j = BOARD_HEIGHT - 1; j >= 0; --j)
523 y = j;
524 while( (y + 1) < BOARD_HEIGHT &&
525 state->board[ XYPOS( i, y + 1)] == CC_BLACK
527 y++;
529 if (y != j) {
530 state->board[ XYPOS( i, y)] = state->board[ XYPOS( i, j)];
531 state->board[ XYPOS( i, j)] = CC_BLACK;
536 /* move columns to left side */
537 for( i = 0; i < BOARD_WIDTH; ++i)
539 x = i;
540 while( (x - 1) >= 0 &&
541 state->board[ XYPOS( x - 1, BOARD_HEIGHT - 1)] == CC_BLACK
543 x--;
544 if (x != i)
546 for( j = 0; j < BOARD_HEIGHT; ++j)
548 state->board[ XYPOS( x, j)] = state->board[ XYPOS( i, j)];
549 state->board[ XYPOS( i, j)] = CC_BLACK;
554 if(state->board[ XYPOS( 0, BOARD_HEIGHT - 1)] != CC_BLACK)
555 state->status = CLIX_CONTINUE;
557 if (state->status != CLIX_CLEARED) {
558 /* check if a move is still possible, otherwise the game is over.
559 tart from the left bottom, because there are the last fields
560 at the end of the game.
562 for( i = 0; i < BOARD_WIDTH; ++i)
564 for( j = BOARD_HEIGHT - 1; j >= 0; --j)
566 int color = state->board[ XYPOS( i, j)];
567 if (color != CC_BLACK) {
568 if (color == clix_get_color( state, i - 1, j) ||
569 color == clix_get_color( state, i + 1, j) ||
570 color == clix_get_color( state, i, j - 1) ||
571 color == clix_get_color( state, i, j + 1)
574 /* end the loop, but in a diffrent way than usually*/
575 i = BOARD_WIDTH + 1;
576 j = -2;
581 /* if the loops ended without a possible move, the game is over */
582 if( i == BOARD_WIDTH && j == -1)
583 state->status = CLIX_GAMEOVER;
585 /* set cursor to the right position */
586 if (state->status == CLIX_CONTINUE) {
587 clix_move_cursor( state, true);
588 clix_update_selected( state);
592 return state->status;
595 static bool clix_help(void)
597 #define WORDS (sizeof help_text / sizeof (char*))
598 static char *help_text[] = {
599 "Clix", "", "Aim", "",
600 "Remove", "all", "blocks", "from", "the", "board", "to", "achieve",
601 "the", "next", "level.", "You", "can", "only", "remove", "blocks,",
602 "if", "at", "least", "two", "blocks", "with", "the", "same", "color",
603 "have", "a", "direct", "connection.", "The", "more", "blocks", "you",
604 "remove", "per", "turn,", "the", "more", "points", "you", "get."
606 static struct style_text formation[]={
607 { 0, TEXT_CENTER|TEXT_UNDERLINE },
608 { 2, C_RED },
609 { -1, 0 }
611 int button;
613 rb->lcd_setfont(FONT_UI);
614 rb->lcd_set_foreground(LCD_WHITE);
615 if (display_text(WORDS, help_text, formation, NULL))
616 return true;
617 do {
618 button = rb->button_get(true);
619 if ( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
620 return true;
621 } while( ( button == BUTTON_NONE )
622 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
623 rb->lcd_setfont(FONT_SYSFIXED);
624 return 0;
627 static bool _ingame;
628 static int clix_menu_cb(int action, const struct menu_item_ex *this_item)
630 if(action == ACTION_REQUEST_MENUITEM
631 && !_ingame && ((intptr_t)this_item)==0)
632 return ACTION_EXIT_MENUITEM;
633 return action;
636 static int clix_menu(struct clix_game_state_t* state, bool ingame)
638 rb->button_clear_queue();
639 int choice = 0;
641 _ingame = ingame;
643 MENUITEM_STRINGLIST (main_menu, "Clix Menu", clix_menu_cb,
644 "Resume Game",
645 "Start New Game",
646 "Help",
647 "High Score",
648 "Playback Control",
649 "Quit");
651 while (true) {
652 switch (rb->do_menu(&main_menu, &choice, NULL, false)) {
653 case 0:
654 return 0;
655 case 1:
656 clix_init(state);
657 return 0;
658 case 2:
659 if (clix_help())
660 return 1;
661 break;
662 case 3:
663 clix_show_highscores(NUM_SCORES);
664 break;
665 case 4:
666 playback_control(NULL);
667 break;
668 case 5:
669 case MENU_ATTACHED_USB:
670 return 1;
671 default:
672 break;
677 static int clix_handle_game(struct clix_game_state_t* state)
679 if (clix_menu(state, 0))
680 return 1;
682 int button;
683 int blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
684 int position;
686 int time;
687 int start;
688 int end;
689 int oldx, oldy;
691 while(true)
693 if (blink_tick < *rb->current_tick) {
694 state->blink = state->blink ? false : true;
695 blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
698 time = 6; /* number of ticks this function will loop reading keys */
699 start = *rb->current_tick;
700 end = start + time;
701 while(end > *rb->current_tick)
703 oldx = state->x;
704 oldy = state->y;
706 rb->button_get_w_tmo(end - *rb->current_tick);
707 button = rb->button_status();
708 rb->button_clear_queue();
709 #ifdef HAVE_TOUCHSCREEN
710 if(button & BUTTON_TOUCHSCREEN)
712 int x = rb->button_get_data() >> 16;
713 int y = rb->button_get_data() & 0xffff;
715 x -= XOFS;
716 y -= YOFS;
717 if(x >= 0 && y >= 0)
719 x /= CELL_SIZE + 1;
720 y /= CELL_SIZE + 1;
722 if(x < BOARD_WIDTH && y < BOARD_HEIGHT
723 && state->board[XYPOS(x, y)] != CC_BLACK)
725 if(state->x == x && state->y == y)
726 button = CLIX_BUTTON_CLICK;
727 else
729 state->x = x;
730 state->y = y;
735 #endif
736 switch( button)
738 #ifndef HAVE_TOUCHSCREEN
739 #ifdef CLIX_BUTTON_SCROLL_BACK
740 case CLIX_BUTTON_SCROLL_BACK:
741 #endif
742 case CLIX_BUTTON_UP:
743 if( state->y == 0 ||
744 state->board[ XYPOS( state->x, state->y - 1)] ==
745 CC_BLACK
747 state->y = BOARD_HEIGHT - 1;
748 else
749 state->y--;
751 clix_move_cursor(state, true);
752 break;
753 case CLIX_BUTTON_RIGHT:
754 if( state->x == (BOARD_WIDTH - 1))
755 state->x = 0;
756 else
757 state->x++;
759 clix_move_cursor(state, false);
760 break;
761 #ifdef CLIX_BUTTON_SCROLL_FWD
762 case CLIX_BUTTON_SCROLL_FWD:
763 #endif
764 case CLIX_BUTTON_DOWN:
765 if( state->y == (BOARD_HEIGHT - 1))
766 state->y = 0;
767 else
768 state->y++;
770 clix_move_cursor( state, true);
771 break;
772 case CLIX_BUTTON_LEFT:
773 if( state->x == 0)
774 state->x = BOARD_WIDTH - 1;
775 else
776 state->x--;
778 clix_move_cursor(state, true);
780 break;
781 #endif
782 case CLIX_BUTTON_CLICK:
784 if (state->selected_count > 1) {
785 switch( clix_clear_selected( state))
787 case CLIX_CLEARED:
788 state->score += state->level * 100;
789 clix_draw( state);
790 if (state->level < NUM_LEVELS) {
791 rb->splash(HZ*2, "Great! Next Level!");
792 state->level++;
793 clix_init_new_level( state);
794 clix_update_selected( state);
796 else {
797 rb->splash(HZ*2, "Congratulation!!!");
798 rb->lcd_clear_display();
799 rb->splash(HZ*2, "You have finished the game.");
800 if (clix_menu(state, 0))
801 return 1;
803 break;
804 case CLIX_GAMEOVER:
805 clix_draw( state);
806 rb->splash(HZ*2, "Game Over!");
807 rb->lcd_clear_display();
808 if (highscore_would_update(state->score,
809 highest, NUM_SCORES)) {
810 position=highscore_update(state->score,
811 state->level, "",
812 highest,NUM_SCORES);
813 if (position == 0) {
814 rb->splash(HZ*2, "New High Score");
816 clix_show_highscores(position);
818 if (clix_menu(state, 0))
819 return 1;
820 break;
821 default:
822 rb->sleep(10); /* prevent repeating clicks */
823 break;
827 break;
828 case CLIX_BUTTON_QUIT:
829 if (clix_menu(state, 1) != 0) {
830 rb->button_clear_queue();
831 return 1;
833 break;
834 default:
836 break;
839 if( (oldx != state->x || oldy != state->y) &&
840 state->board_selected[ XYPOS( oldx, oldy)] !=
841 state->board_selected[ XYPOS( state->x, state->y)]
844 clix_update_selected(state);
846 clix_draw(state);
847 rb->sleep(time);
852 /* this is the plugin entry point */
853 enum plugin_status plugin_start(const void* parameter)
855 (void)parameter;
857 rb->lcd_set_backdrop(NULL);
858 rb->lcd_set_foreground(LCD_WHITE);
859 rb->lcd_set_background(LCD_BLACK);
860 rb->lcd_setfont(FONT_SYSFIXED);
861 #ifdef HAVE_TOUCHSCREEN
862 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
863 #endif
865 highscore_load(HIGHSCORE_FILE, highest, NUM_SCORES);
867 struct clix_game_state_t state;
868 clix_handle_game( &state);
870 highscore_save(HIGHSCORE_FILE, highest, NUM_SCORES);
872 return PLUGIN_OK;