Update the discussion of themeing in the manual, and put a note in the wps tags appen...
[kugel-rb.git] / apps / plugins / clix.c
blob07356568395ddbe3091a342b9fb39197ec30afd0
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 SCORE_FILE PLUGIN_GAMES_DIR "/clix.score"
188 #define NUM_SCORES 5
189 struct highscore highscores[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();
438 rb->lcd_set_foreground(LCD_WHITE);
441 static void clix_move_cursor(struct clix_game_state_t* state, const bool left)
443 int x, y;
445 x = state->x;
448 y = state->y;
449 while(state->board[ XYPOS( x, y)] == CC_BLACK && y < BOARD_HEIGHT) y++;
450 if (y < BOARD_HEIGHT) {
451 state->y = y;
452 state->x = x;
454 else
456 if (left) {
457 if( x >= 0)
458 x--;
459 else
460 y = state->y;
462 else
464 if( x < BOARD_WIDTH - 1)
465 x++;
466 else
467 x = 0;
470 } 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;
485 bool found_move;
487 state->status = CLIX_CLEARED;
489 /* clear the selected blocks */
490 for( i = 0; i < BOARD_WIDTH; ++i)
492 for( j = 0; j < BOARD_HEIGHT; ++j)
494 if( state->board_selected[ XYPOS( i, j)] )
496 state->board_selected[ XYPOS( i, j)] = false;
497 state->board[ XYPOS( i, j)] = CC_BLACK;
502 /* count score */
503 state->score += state->selected_count * state->level;
504 state->selected_count = 0;
506 /* let blocks falling down */
507 for( i = BOARD_WIDTH - 1; i >= 0; --i)
509 for( j = BOARD_HEIGHT - 1; j >= 0; --j)
511 y = j;
512 while( (y + 1) < BOARD_HEIGHT &&
513 state->board[ XYPOS( i, y + 1)] == CC_BLACK
515 y++;
517 if (y != j) {
518 state->board[ XYPOS( i, y)] = state->board[ XYPOS( i, j)];
519 state->board[ XYPOS( i, j)] = CC_BLACK;
524 /* move columns to left side */
525 for( i = 0; i < BOARD_WIDTH; ++i)
527 x = i;
528 while( (x - 1) >= 0 &&
529 state->board[ XYPOS( x - 1, BOARD_HEIGHT - 1)] == CC_BLACK
531 x--;
532 if (x != i)
534 for( j = 0; j < BOARD_HEIGHT; ++j)
536 state->board[ XYPOS( x, j)] = state->board[ XYPOS( i, j)];
537 state->board[ XYPOS( i, j)] = CC_BLACK;
542 if(state->board[ XYPOS( 0, BOARD_HEIGHT - 1)] != CC_BLACK)
543 state->status = CLIX_CONTINUE;
545 if (state->status != CLIX_CLEARED) {
546 /* check if a move is still possible, otherwise the game is over.
547 tart from the left bottom, because there are the last fields
548 at the end of the game.
550 found_move = false;
551 for( i = 0; !found_move && i < BOARD_WIDTH; ++i)
553 for( j = BOARD_HEIGHT - 1; !found_move && j >= 0; --j)
555 int color = state->board[ XYPOS( i, j)];
556 if (color != CC_BLACK) {
557 if (color == clix_get_color( state, i - 1, j) ||
558 color == clix_get_color( state, i + 1, j) ||
559 color == clix_get_color( state, i, j - 1) ||
560 color == clix_get_color( state, i, j + 1)
563 found_move = true;
568 /* if the loops ended without a possible move, the game is over */
569 if( !found_move)
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 static char *help_text[] = {
585 "Clix", "", "Aim", "",
586 "Remove", "all", "blocks", "from", "the", "board", "to", "achieve",
587 "the", "next", "level.", "You", "can", "only", "remove", "blocks,",
588 "if", "at", "least", "two", "blocks", "with", "the", "same", "color",
589 "have", "a", "direct", "connection.", "The", "more", "blocks", "you",
590 "remove", "per", "turn,", "the", "more", "points", "you", "get."
592 static struct style_text formation[]={
593 { 0, TEXT_CENTER|TEXT_UNDERLINE },
594 { 2, C_RED },
595 LAST_STYLE_ITEM
598 rb->lcd_setfont(FONT_UI);
599 rb->lcd_set_foreground(LCD_WHITE);
600 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
601 return true;
602 rb->lcd_setfont(FONT_SYSFIXED);
604 return false;
607 static bool _ingame;
608 static int clix_menu_cb(int action, const struct menu_item_ex *this_item)
610 if(action == ACTION_REQUEST_MENUITEM
611 && !_ingame && ((intptr_t)this_item)==0)
612 return ACTION_EXIT_MENUITEM;
613 return action;
616 static int clix_menu(struct clix_game_state_t* state, bool ingame)
618 rb->button_clear_queue();
619 int choice = 0;
620 bool leave_menu=false;
621 int ret=0;
623 _ingame = ingame;
625 MENUITEM_STRINGLIST (main_menu, "Clix Menu", clix_menu_cb,
626 "Resume Game",
627 "Start New Game",
628 "Help",
629 "High Scores",
630 "Playback Control",
631 "Quit");
633 #ifdef HAVE_TOUCHSCREEN
634 /* Entering Menu, set the touchscreen to the global setting */
635 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
636 #endif
638 while (!leave_menu) {
640 switch (rb->do_menu(&main_menu, &choice, NULL, false)) {
641 case 0:
642 leave_menu=true;
643 ret = 0;
644 break;
645 case 1:
646 clix_init(state);
647 leave_menu=true;
648 ret = 0;
649 break;
650 case 2:
651 if (clix_help()) {
652 leave_menu=true;
653 ret = 1;
655 break;
656 case 3:
657 highscore_show(-1, highscores, NUM_SCORES, true);
658 break;
659 case 4:
660 playback_control(NULL);
661 break;
662 case 5:
663 case MENU_ATTACHED_USB:
664 leave_menu=true;
665 ret = 1;
666 break;
667 default:
668 break;
672 #ifdef HAVE_TOUCHSCREEN
673 /* Leaving the menu, set back to pointer mode */
674 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
675 #endif
677 return ret;
680 static int clix_click(struct clix_game_state_t* state)
682 int position;
683 if (state->selected_count <= 1) {
684 return 0;
686 switch( clix_clear_selected( state))
688 case CLIX_CLEARED:
689 state->score += state->level * 100;
690 clix_draw( state);
691 if (state->level < NUM_LEVELS) {
692 rb->splash(HZ*2, "Great! Next Level!");
693 state->level++;
694 clix_init_new_level( state);
695 clix_update_selected( state);
697 else {
698 rb->splash(HZ*2, "Congratulation!!!");
699 rb->splash(HZ*2, "You have finished the game.");
700 if(clix_menu(state, 0))
701 return 1;
703 break;
704 case CLIX_GAMEOVER:
705 clix_draw( state);
706 rb->splash(HZ*2, "Game Over!");
707 rb->lcd_clear_display();
708 position = highscore_update(state->score, state->level, "",
709 highscores, NUM_SCORES);
710 if (position != -1)
712 if (position == 0)
713 rb->splash(HZ*2, "New High Score");
714 highscore_show(position, highscores, NUM_SCORES, true);
716 if(clix_menu(state, 0))
717 return 1;
718 break;
719 default:
720 rb->sleep(10); /* prevent repeating clicks */
721 break;
723 return 0;
726 static int clix_handle_game(struct clix_game_state_t* state)
728 int button;
729 int blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
731 int time;
732 int start;
733 int end;
734 int oldx, oldy;
736 if (clix_menu(state, 0))
737 return 1;
739 while(true)
741 if (TIME_AFTER(*rb->current_tick, blink_tick)) {
742 state->blink = !state->blink;
743 blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
746 time = 6; /* number of ticks this function will loop reading keys */
747 start = *rb->current_tick;
748 end = start + time;
749 while(TIME_BEFORE(*rb->current_tick, end))
751 oldx = state->x;
752 oldy = state->y;
754 button = rb->button_get_w_tmo(end - *rb->current_tick);
755 #ifdef HAVE_TOUCHSCREEN
756 if(button & BUTTON_TOUCHSCREEN)
758 int x = rb->button_get_data() >> 16;
759 int y = rb->button_get_data() & 0xffff;
761 x -= XOFS;
762 y -= YOFS;
763 if(x >= 0 && y >= 0)
765 x /= CELL_SIZE + 1;
766 y /= CELL_SIZE + 1;
768 if(x < BOARD_WIDTH && y < BOARD_HEIGHT
769 && state->board[XYPOS(x, y)] != CC_BLACK)
771 if(state->x == x && state->y == y)
772 button = CLIX_BUTTON_CLICK;
773 else
775 state->x = x;
776 state->y = y;
781 #endif
782 switch( button)
784 #ifndef HAVE_TOUCHSCREEN
785 #ifdef CLIX_BUTTON_SCROLL_BACK
786 case CLIX_BUTTON_SCROLL_BACK:
787 case CLIX_BUTTON_SCROLL_BACK|BUTTON_REPEAT:
788 #endif
789 case CLIX_BUTTON_UP:
790 case CLIX_BUTTON_UP|BUTTON_REPEAT:
791 if( state->y == 0 ||
792 state->board[ XYPOS( state->x, state->y - 1)] ==
793 CC_BLACK
795 state->y = BOARD_HEIGHT - 1;
796 else
797 state->y--;
799 clix_move_cursor(state, true);
800 break;
802 #ifdef CLIX_BUTTON_SCROLL_FWD
803 case CLIX_BUTTON_SCROLL_FWD:
804 case CLIX_BUTTON_SCROLL_FWD|BUTTON_REPEAT:
805 #endif
806 case CLIX_BUTTON_DOWN:
807 case CLIX_BUTTON_DOWN|BUTTON_REPEAT:
808 if( state->y == (BOARD_HEIGHT - 1))
809 state->y = 0;
810 else
811 state->y++;
813 clix_move_cursor( state, true);
814 break;
816 case CLIX_BUTTON_RIGHT:
817 case CLIX_BUTTON_RIGHT|BUTTON_REPEAT:
818 if( state->x == (BOARD_WIDTH - 1))
819 state->x = 0;
820 else
821 state->x++;
823 clix_move_cursor(state, false);
824 break;
826 case CLIX_BUTTON_LEFT:
827 case CLIX_BUTTON_LEFT|BUTTON_REPEAT:
828 if( state->x == 0)
829 state->x = BOARD_WIDTH - 1;
830 else
831 state->x--;
833 clix_move_cursor(state, true);
834 break;
835 #endif
836 case CLIX_BUTTON_CLICK:
837 if (clix_click(state) == 1)
838 return 1;
839 break;
841 case CLIX_BUTTON_QUIT:
842 if (clix_menu(state, 1) != 0) {
843 rb->button_clear_queue();
844 return 1;
846 break;
847 default:
849 break;
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(SCORE_FILE, highscores, NUM_SCORES);
880 struct clix_game_state_t state;
881 clix_handle_game( &state);
883 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
885 return PLUGIN_OK;