Bump plugin API version. This should have been done in r24587. Also, because the...
[kugel-rb.git] / apps / plugins / clix.c
blob6fa6931300ffd0bd90ca6bea62186ef1249f90d4
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 #else
170 #error "no keymap"
171 #endif
173 #ifndef CLIX_BUTTON_CLICK
174 #define CLIX_BUTTON_CLICK BUTTON_CENTER
175 #endif
177 #define HIGHSCORE_FILE PLUGIN_GAMES_DIR "/clix.score"
178 #define NUM_SCORES 5
179 struct highscore highest[NUM_SCORES];
181 #define NUM_LEVELS 9
182 #define BLINK_TICKCOUNT 25
183 #define MARGIN 5
185 #if (LCD_WIDTH >= LCD_HEIGHT)
186 #define BOARD_WIDTH 18
187 #define BOARD_HEIGHT 12
188 #else
189 #define BOARD_WIDTH 12
190 #define BOARD_HEIGHT 18
191 #endif
193 #if (LCD_WIDTH>=480)
194 #if (LCD_WIDTH/BOARD_WIDTH) > (LCD_HEIGHT/BOARD_HEIGHT)
195 #define CELL_SIZE (LCD_HEIGHT/BOARD_HEIGHT)
196 #else
197 #define CELL_SIZE (LCD_WIDTH/BOARD_WIDTH)
198 #endif
200 #elif (LCD_WIDTH >= 306 && LCD_HEIGHT>= 204)
201 #define CELL_SIZE 16
203 #elif (LCD_WIDTH >= 270 && LCD_HEIGHT>= 180)
204 #define CELL_SIZE 14
206 #elif (LCD_WIDTH >= 234 && LCD_HEIGHT>= 156)
207 #define CELL_SIZE 12
209 #elif (LCD_WIDTH >= 198 && LCD_HEIGHT>= 132)
210 #define CELL_SIZE 10
212 #elif (LCD_WIDTH >= 162 && LCD_HEIGHT>= 108)
213 #define CELL_SIZE 8
215 #elif (LCD_WIDTH >= 126 && LCD_HEIGHT>= 84)
216 #define CELL_SIZE 6
218 #elif (LCD_WIDTH >= 60)
219 #define CELL_SIZE 4
220 #endif
222 #define XYPOS(x,y) ((y) * BOARD_WIDTH + x)
223 #define XOFS LCD_WIDTH/2-(BOARD_WIDTH * (CELL_SIZE + 1)/2)
224 #define YOFS (LCD_HEIGHT+10)/2-(BOARD_HEIGHT * (CELL_SIZE + 1)/2)
227 struct clix_game_state_t {
228 int level; /* current level */
229 int score; /* current game score */
230 int x,y; /* current positions of the cursor */
231 int board[BOARD_WIDTH * BOARD_HEIGHT]; /* play board*/
232 /* state of selected fields,maybe we can store this in the play board too */
233 bool board_selected[ BOARD_WIDTH * BOARD_HEIGHT];
234 int selected_count;
235 int status;
236 bool blink; /* true if selected CELLS are currently white */
239 /* game state enum */
240 enum {
241 CLIX_GAMEOVER = -1,
242 CLIX_CONTINUE,
243 CLIX_CLEARED
246 /* cell color enum */
247 enum {
248 CC_BLACK = -1,
249 CC_BLUE,
250 CC_GREEN,
251 CC_RED,
252 CC_YELLOW,
253 CC_ORANGE,
254 CC_CYAN,
255 CC_BROWN,
256 CC_PINK,
257 CC_DARK_BLUE,
258 CC_DARK_GREEN
261 /* recursive function to check if a neighbour cell is of the same color
262 if so call the function with the neighbours position
264 static void clix_set_selected(struct clix_game_state_t* state,
265 const int x, const int y)
267 state->selected_count++;
268 state->board_selected[ XYPOS( x, y)] = true;
269 int current_color = state->board[ XYPOS( x, y)];
271 if( (x - 1) >= 0 &&
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) < BOARD_HEIGHT &&
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);
281 if( (x + 1) < BOARD_WIDTH &&
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) >= 0 &&
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);
292 /* updates "blinking" cells by finding out which one is a valid neighbours */
293 static void clix_update_selected(struct clix_game_state_t* state)
295 int i;
297 for( i = 0; i < BOARD_WIDTH * BOARD_HEIGHT; ++i)
299 state->board_selected[i] = false;
301 state->selected_count = 0;
303 /* recursion starts here */
304 clix_set_selected( state, state->x, state->y);
307 /* inits the board with new random colors according to the level */
308 static void clix_init_new_level(struct clix_game_state_t* state)
310 int i;
311 int r;
313 state->y = BOARD_HEIGHT / 2;
314 state->x = BOARD_WIDTH / 2;
316 rb->srand( *rb->current_tick);
317 /* create a random colored board, according to the current level */
318 for(i = 0; i < BOARD_HEIGHT * BOARD_WIDTH; ++i)
320 r = rb->rand() % (state->level + 1);
321 state->board[i] = r;
325 /* this inits the game state structure */
326 static void clix_init(struct clix_game_state_t* state)
328 state->level = 1;
329 state->score = 0;
330 state->blink = false;
331 state->status = CLIX_CONTINUE;
333 clix_init_new_level(state);
335 clix_update_selected(state);
338 /* Function for drawing a cell */
339 static void clix_draw_cell(struct clix_game_state_t* state, const int x, const int y)
341 int realx = XOFS;
342 int realy = YOFS;
344 realx += x * (CELL_SIZE + 1);
345 realy += y * (CELL_SIZE + 1);
347 if (state->blink && state->board_selected[ XYPOS( x, y)]) {
348 rb->lcd_set_foreground(LCD_WHITE);
349 } else {
350 switch (state->board[ XYPOS( x, y)])
352 case CC_BLUE:
353 rb->lcd_set_foreground( LCD_RGBPACK( 25, 25, 255));
354 break;
355 case CC_GREEN:
356 rb->lcd_set_foreground( LCD_RGBPACK( 25, 255, 25));
357 break;
358 case CC_RED:
359 rb->lcd_set_foreground( LCD_RGBPACK( 255, 25, 25));
360 break;
361 case CC_YELLOW:
362 rb->lcd_set_foreground( LCD_RGBPACK( 225, 225, 25));
363 break;
364 case CC_ORANGE:
365 rb->lcd_set_foreground( LCD_RGBPACK( 230, 140, 15));
366 break;
367 case CC_CYAN:
368 rb->lcd_set_foreground( LCD_RGBPACK( 25, 245, 230));
369 break;
370 case CC_BROWN:
371 rb->lcd_set_foreground( LCD_RGBPACK(139, 69, 19));
372 break;
373 case CC_PINK:
374 rb->lcd_set_foreground( LCD_RGBPACK(255, 105, 180));
375 break;
376 case CC_DARK_GREEN:
377 rb->lcd_set_foreground( LCD_RGBPACK( 0, 100, 0));
378 break;
379 case CC_DARK_BLUE:
380 rb->lcd_set_foreground( LCD_RGBPACK( 280, 32, 144));
381 break;
382 default:
383 rb->lcd_set_foreground( LCD_BLACK);
384 break;
388 rb->lcd_fillrect( realx, realy, CELL_SIZE, CELL_SIZE);
390 /* draw cursor */
391 if ( x == state->x && y == state->y) {
392 rb->lcd_set_foreground( LCD_WHITE);
393 rb->lcd_drawrect( realx - 1, realy - 1, CELL_SIZE + 2, CELL_SIZE + 2);
397 /* main function of drawing the whole board and score... */
398 static void clix_draw(struct clix_game_state_t* state)
400 int i,j;
401 char str[30];
403 /* Clear screen */
404 rb->lcd_clear_display();
405 rb->lcd_set_foreground( LCD_WHITE);
407 rb->lcd_putsxy( MARGIN, MARGIN, "Score:");
408 rb->snprintf( str, sizeof(str), "%d", state->score);
409 rb->lcd_putsxy( 43, MARGIN, str);
410 #if LCD_WIDTH <= 100
411 rb->lcd_putsxy( 75, MARGIN, "L:");
412 rb->snprintf( str, sizeof(str), "%d", state->level);
413 rb->lcd_putsxy( 90, MARGIN, str);
414 #else
415 rb->lcd_putsxy( 75, MARGIN, "Level:");
416 rb->snprintf( str, sizeof(str), "%d", state->level);
417 rb->lcd_putsxy( 113, MARGIN, str);
418 #endif
419 for( i = 0; i < BOARD_WIDTH; ++i)
421 for( j = 0; j < BOARD_HEIGHT; ++j)
423 clix_draw_cell( state, i, j);
427 rb->lcd_update();
430 static void clix_move_cursor(struct clix_game_state_t* state, const bool left)
432 int x, y;
434 x = state->x;
437 y = state->y;
438 while(state->board[ XYPOS( x, y)] == CC_BLACK && y < BOARD_HEIGHT) y++;
439 if (y < BOARD_HEIGHT) {
440 state->y = y;
441 state->x = x;
443 else
445 if (left) {
446 if( x >= 0)
447 x--;
448 else
449 y = state->y;
451 else
453 if( x < BOARD_WIDTH - 1)
454 x++;
455 else
456 x = 0;
459 } while ( y != state->y);
463 /* returns the color of the given position, if out of bounds return CC_BLACK */
464 static int clix_get_color(struct clix_game_state_t* state, const int x, const int y)
466 if( x >= 0 && x < BOARD_WIDTH && y >= 0 && y < BOARD_HEIGHT)
467 return state->board[XYPOS( x, y)];
468 else
469 return CC_BLACK;
472 static int clix_clear_selected(struct clix_game_state_t* state)
474 int i, j, x, y;
476 state->status = CLIX_CLEARED;
478 /* clear the selected blocks */
479 for( i = 0; i < BOARD_WIDTH; ++i)
481 for( j = 0; j < BOARD_HEIGHT; ++j)
483 if( state->board_selected[ XYPOS( i, j)] )
485 state->board_selected[ XYPOS( i, j)] = false;
486 state->board[ XYPOS( i, j)] = CC_BLACK;
491 /* count score */
492 state->score += state->selected_count * state->level;
493 state->selected_count = 0;
495 /* let blocks falling down */
496 for( i = BOARD_WIDTH - 1; i >= 0; --i)
498 for( j = BOARD_HEIGHT - 1; j >= 0; --j)
500 y = j;
501 while( (y + 1) < BOARD_HEIGHT &&
502 state->board[ XYPOS( i, y + 1)] == CC_BLACK
504 y++;
506 if (y != j) {
507 state->board[ XYPOS( i, y)] = state->board[ XYPOS( i, j)];
508 state->board[ XYPOS( i, j)] = CC_BLACK;
513 /* move columns to left side */
514 for( i = 0; i < BOARD_WIDTH; ++i)
516 x = i;
517 while( (x - 1) >= 0 &&
518 state->board[ XYPOS( x - 1, BOARD_HEIGHT - 1)] == CC_BLACK
520 x--;
521 if (x != i)
523 for( j = 0; j < BOARD_HEIGHT; ++j)
525 state->board[ XYPOS( x, j)] = state->board[ XYPOS( i, j)];
526 state->board[ XYPOS( i, j)] = CC_BLACK;
531 if(state->board[ XYPOS( 0, BOARD_HEIGHT - 1)] != CC_BLACK)
532 state->status = CLIX_CONTINUE;
534 if (state->status != CLIX_CLEARED) {
535 /* check if a move is still possible, otherwise the game is over.
536 tart from the left bottom, because there are the last fields
537 at the end of the game.
539 for( i = 0; i < BOARD_WIDTH; ++i)
541 for( j = BOARD_HEIGHT - 1; j >= 0; --j)
543 int color = state->board[ XYPOS( i, j)];
544 if (color != CC_BLACK) {
545 if (color == clix_get_color( state, i - 1, j) ||
546 color == clix_get_color( state, i + 1, j) ||
547 color == clix_get_color( state, i, j - 1) ||
548 color == clix_get_color( state, i, j + 1)
551 /* end the loop, but in a diffrent way than usually*/
552 i = BOARD_WIDTH + 1;
553 j = -2;
558 /* if the loops ended without a possible move, the game is over */
559 if( i == BOARD_WIDTH && j == -1)
560 state->status = CLIX_GAMEOVER;
562 /* set cursor to the right position */
563 if (state->status == CLIX_CONTINUE) {
564 clix_move_cursor( state, true);
565 clix_update_selected( state);
569 return state->status;
572 static bool clix_help(void)
574 #define WORDS (sizeof help_text / sizeof (char*))
575 static char *help_text[] = {
576 "Clix", "", "Aim", "",
577 "Remove", "all", "blocks", "from", "the", "board", "to", "achieve",
578 "the", "next", "level.", "You", "can", "only", "remove", "blocks,",
579 "if", "at", "least", "two", "blocks", "with", "the", "same", "color",
580 "have", "a", "direct", "connection.", "The", "more", "blocks", "you",
581 "remove", "per", "turn,", "the", "more", "points", "you", "get."
583 static struct style_text formation[]={
584 { 0, TEXT_CENTER|TEXT_UNDERLINE },
585 { 2, C_RED },
586 { -1, 0 }
588 int button;
590 rb->lcd_setfont(FONT_UI);
591 rb->lcd_set_foreground(LCD_WHITE);
592 if (display_text(WORDS, help_text, formation, NULL))
593 return true;
594 do {
595 button = rb->button_get(true);
596 if ( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
597 return true;
598 } while( ( button == BUTTON_NONE )
599 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
600 rb->lcd_setfont(FONT_SYSFIXED);
601 return 0;
604 static bool _ingame;
605 static int clix_menu_cb(int action, const struct menu_item_ex *this_item)
607 if(action == ACTION_REQUEST_MENUITEM
608 && !_ingame && ((intptr_t)this_item)==0)
609 return ACTION_EXIT_MENUITEM;
610 return action;
613 static int clix_menu(struct clix_game_state_t* state, bool ingame)
615 rb->button_clear_queue();
616 int choice = 0;
617 bool leave_menu=false;
618 int ret=0;
620 _ingame = ingame;
622 MENUITEM_STRINGLIST (main_menu, "Clix Menu", clix_menu_cb,
623 "Resume Game",
624 "Start New Game",
625 "Help",
626 "High Scores",
627 "Playback Control",
628 "Quit");
630 #ifdef HAVE_TOUCHSCREEN
631 /* Entering Menu, set the touchscreen to the global setting */
632 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
633 #endif
635 while (!leave_menu) {
637 switch (rb->do_menu(&main_menu, &choice, NULL, false)) {
638 case 0:
639 leave_menu=true;
640 ret = 0;
641 break;
642 case 1:
643 clix_init(state);
644 leave_menu=true;
645 ret = 0;
646 break;
647 case 2:
648 if (clix_help()) {
649 leave_menu=true;
650 ret = 1;
652 break;
653 case 3:
654 highscore_show(NUM_SCORES, highest, NUM_SCORES, true);
655 break;
656 case 4:
657 playback_control(NULL);
658 break;
659 case 5:
660 case MENU_ATTACHED_USB:
661 leave_menu=true;
662 ret = 1;
663 break;
664 default:
665 break;
669 #ifdef HAVE_TOUCHSCREEN
670 /* Leaving the menu, set back to pointer mode */
671 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
672 #endif
674 return ret;
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 int lastbutton = BUTTON_NONE;
693 while(true)
695 if (TIME_AFTER(*rb->current_tick, blink_tick)) {
696 state->blink = !state->blink;
697 blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
700 time = 6; /* number of ticks this function will loop reading keys */
701 start = *rb->current_tick;
702 end = start + time;
703 while(TIME_BEFORE(*rb->current_tick, end))
705 oldx = state->x;
706 oldy = state->y;
708 button = rb->button_get_w_tmo(end - *rb->current_tick);
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 case CLIX_BUTTON_SCROLL_BACK|BUTTON_REPEAT:
742 #endif
743 case CLIX_BUTTON_UP:
744 if( state->y == 0 ||
745 state->board[ XYPOS( state->x, state->y - 1)] ==
746 CC_BLACK
748 state->y = BOARD_HEIGHT - 1;
749 else
750 state->y--;
752 clix_move_cursor(state, true);
753 break;
754 case CLIX_BUTTON_RIGHT:
755 if( state->x == (BOARD_WIDTH - 1))
756 state->x = 0;
757 else
758 state->x++;
760 clix_move_cursor(state, false);
761 break;
762 #ifdef CLIX_BUTTON_SCROLL_FWD
763 case CLIX_BUTTON_SCROLL_FWD:
764 case CLIX_BUTTON_SCROLL_FWD|BUTTON_REPEAT:
765 #endif
766 case CLIX_BUTTON_DOWN:
767 if( state->y == (BOARD_HEIGHT - 1))
768 state->y = 0;
769 else
770 state->y++;
772 clix_move_cursor( state, true);
773 break;
774 case CLIX_BUTTON_LEFT:
775 if( state->x == 0)
776 state->x = BOARD_WIDTH - 1;
777 else
778 state->x--;
780 clix_move_cursor(state, true);
782 break;
783 #endif
784 case CLIX_BUTTON_CLICK:
786 if (state->selected_count > 1) {
787 switch( clix_clear_selected( state))
789 case CLIX_CLEARED:
790 state->score += state->level * 100;
791 clix_draw( state);
792 if (state->level < NUM_LEVELS) {
793 rb->splash(HZ*2, "Great! Next Level!");
794 state->level++;
795 clix_init_new_level( state);
796 clix_update_selected( state);
798 else {
799 rb->splash(HZ*2, "Congratulation!!!");
800 rb->lcd_clear_display();
801 rb->splash(HZ*2, "You have finished the game.");
802 if (clix_menu(state, 0))
803 return 1;
805 break;
806 case CLIX_GAMEOVER:
807 clix_draw( state);
808 rb->splash(HZ*2, "Game Over!");
809 rb->lcd_clear_display();
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");
815 if (position != -1)
816 highscore_show(position, highest,
817 NUM_SCORES, true);
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(button != BUTTON_NONE)
840 lastbutton = button;
842 if( (oldx != state->x || oldy != state->y) &&
843 state->board_selected[ XYPOS( oldx, oldy)] !=
844 state->board_selected[ XYPOS( state->x, state->y)]
847 clix_update_selected(state);
849 clix_draw(state);
850 rb->sleep(time);
855 /* this is the plugin entry point */
856 enum plugin_status plugin_start(const void* parameter)
858 (void)parameter;
860 rb->lcd_set_backdrop(NULL);
861 rb->lcd_set_foreground(LCD_WHITE);
862 rb->lcd_set_background(LCD_BLACK);
863 rb->lcd_setfont(FONT_SYSFIXED);
864 #ifdef HAVE_TOUCHSCREEN
865 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
866 #endif
868 highscore_load(HIGHSCORE_FILE, highest, NUM_SCORES);
870 struct clix_game_state_t state;
871 clix_handle_game( &state);
873 highscore_save(HIGHSCORE_FILE, highest, NUM_SCORES);
875 return PLUGIN_OK;