Extract config file saving code to a function; Do not write the NUL character to...
[kugel-rb.git] / apps / plugins / clix.c
blob0c928e008cc7aef9c5da6f32cbfeaf2bcd538461
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"
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_HDD6330_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 == PHILIPS_SA9200_PAD)
150 #define CLIX_BUTTON_QUIT BUTTON_POWER
151 #define CLIX_BUTTON_LEFT BUTTON_PREV
152 #define CLIX_BUTTON_RIGHT BUTTON_NEXT
153 #define CLIX_BUTTON_CLICK BUTTON_PLAY
154 #define CLIX_BUTTON_UP BUTTON_UP
155 #define CLIX_BUTTON_DOWN BUTTON_DOWN
157 #elif CONFIG_KEYPAD == COWON_D2_PAD
158 #define CLIX_BUTTON_QUIT BUTTON_POWER
160 #elif (CONFIG_KEYPAD == ONDAVX747_PAD)
161 #define CLIX_BUTTON_QUIT BUTTON_POWER
162 #define CLIX_BUTTON_CLICK BUTTON_MENU
163 #elif (CONFIG_KEYPAD == ONDAVX777_PAD)
164 #define CLIX_BUTTON_QUIT BUTTON_POWER
166 #elif (CONFIG_KEYPAD == MROBE500_PAD)
167 #define CLIX_BUTTON_QUIT BUTTON_POWER
169 #elif (CONFIG_KEYPAD == SAMSUNG_YH_PAD)
170 #define CLIX_BUTTON_QUIT BUTTON_REC
171 #define CLIX_BUTTON_LEFT BUTTON_LEFT
172 #define CLIX_BUTTON_RIGHT BUTTON_RIGHT
173 #define CLIX_BUTTON_CLICK BUTTON_PLAY
174 #define CLIX_BUTTON_UP BUTTON_UP
175 #define CLIX_BUTTON_DOWN BUTTON_DOWN
177 #elif (CONFIG_KEYPAD == PBELL_VIBE500_PAD)
178 #define CLIX_BUTTON_QUIT BUTTON_REC
179 #define CLIX_BUTTON_UP BUTTON_UP
180 #define CLIX_BUTTON_DOWN BUTTON_DOWN
181 #define CLIX_BUTTON_SCROLL_FWD BUTTON_PLAY
182 #define CLIX_BUTTON_SCROLL_BACK BUTTON_MENU
183 #define CLIX_BUTTON_LEFT BUTTON_PREV
184 #define CLIX_BUTTON_RIGHT BUTTON_NEXT
185 #define CLIX_BUTTON_CLICK BUTTON_OK
187 #else
188 #error "no keymap"
189 #endif
191 #ifndef CLIX_BUTTON_CLICK
192 #define CLIX_BUTTON_CLICK BUTTON_CENTER
193 #endif
195 #define SCORE_FILE PLUGIN_GAMES_DIR "/clix.score"
196 #define NUM_SCORES 5
197 struct highscore highscores[NUM_SCORES];
199 #define NUM_LEVELS 9
200 #define BLINK_TICKCOUNT 25
201 #define MARGIN 5
203 #if (LCD_WIDTH >= LCD_HEIGHT)
204 #define BOARD_WIDTH 18
205 #define BOARD_HEIGHT 12
206 #else
207 #define BOARD_WIDTH 12
208 #define BOARD_HEIGHT 18
209 #endif
211 #if (LCD_WIDTH>=480)
212 #if (LCD_WIDTH/BOARD_WIDTH) > (LCD_HEIGHT/BOARD_HEIGHT)
213 #define CELL_SIZE (LCD_HEIGHT/BOARD_HEIGHT)
214 #else
215 #define CELL_SIZE (LCD_WIDTH/BOARD_WIDTH)
216 #endif
218 #elif (LCD_WIDTH >= 306 && LCD_HEIGHT>= 204)
219 #define CELL_SIZE 16
221 #elif (LCD_WIDTH >= 270 && LCD_HEIGHT>= 180)
222 #define CELL_SIZE 14
224 #elif (LCD_WIDTH >= 234 && LCD_HEIGHT>= 156)
225 #define CELL_SIZE 12
227 #elif (LCD_WIDTH >= 198 && LCD_HEIGHT>= 132)
228 #define CELL_SIZE 10
230 #elif (LCD_WIDTH >= 162 && LCD_HEIGHT>= 108)
231 #define CELL_SIZE 8
233 #elif (LCD_WIDTH >= 126 && LCD_HEIGHT>= 84)
234 #define CELL_SIZE 6
236 #elif (LCD_WIDTH >= 60)
237 #define CELL_SIZE 4
238 #endif
240 #define XYPOS(x,y) ((y) * BOARD_WIDTH + x)
241 #define XOFS LCD_WIDTH/2-(BOARD_WIDTH * (CELL_SIZE + 1)/2)
242 #define YOFS (LCD_HEIGHT+10)/2-(BOARD_HEIGHT * (CELL_SIZE + 1)/2)
245 struct clix_game_state_t {
246 int level; /* current level */
247 int score; /* current game score */
248 int x,y; /* current positions of the cursor */
249 int board[BOARD_WIDTH * BOARD_HEIGHT]; /* play board*/
250 /* state of selected fields,maybe we can store this in the play board too */
251 bool board_selected[ BOARD_WIDTH * BOARD_HEIGHT];
252 int selected_count;
253 int status;
254 bool blink; /* true if selected CELLS are currently white */
257 /* game state enum */
258 enum {
259 CLIX_GAMEOVER = -1,
260 CLIX_CONTINUE,
261 CLIX_CLEARED
264 /* cell color enum */
265 enum {
266 CC_BLACK = -1,
267 CC_BLUE,
268 CC_GREEN,
269 CC_RED,
270 CC_YELLOW,
271 CC_ORANGE,
272 CC_CYAN,
273 CC_BROWN,
274 CC_PINK,
275 CC_DARK_BLUE,
276 CC_DARK_GREEN
279 /* recursive function to check if a neighbour cell is of the same color
280 if so call the function with the neighbours position
282 static void clix_set_selected(struct clix_game_state_t* state,
283 const int x, const int y)
285 state->selected_count++;
286 state->board_selected[ XYPOS( x, y)] = true;
287 int current_color = state->board[ XYPOS( x, y)];
289 if( (x - 1) >= 0 &&
290 state->board[ XYPOS( x - 1, y)] == current_color &&
291 state->board_selected[ XYPOS(x - 1, y)] == false)
292 clix_set_selected( state, x - 1, y);
294 if( (y + 1) < BOARD_HEIGHT &&
295 state->board[ XYPOS( x, y + 1)] == current_color &&
296 state->board_selected[ XYPOS(x, y + 1)] == false)
297 clix_set_selected( state, x, y + 1);
299 if( (x + 1) < BOARD_WIDTH &&
300 state->board[ XYPOS( x + 1, y)] == current_color &&
301 state->board_selected[ XYPOS(x + 1, y)] == false)
302 clix_set_selected( state, x + 1, y);
304 if( (y - 1) >= 0 &&
305 state->board[ XYPOS( x, y - 1)] == current_color &&
306 state->board_selected[ XYPOS(x, y - 1)] == false)
307 clix_set_selected( state, x, y - 1);
310 /* updates "blinking" cells by finding out which one is a valid neighbours */
311 static void clix_update_selected(struct clix_game_state_t* state)
313 int i;
315 for( i = 0; i < BOARD_WIDTH * BOARD_HEIGHT; ++i)
317 state->board_selected[i] = false;
319 state->selected_count = 0;
321 /* recursion starts here */
322 clix_set_selected( state, state->x, state->y);
325 /* inits the board with new random colors according to the level */
326 static void clix_init_new_level(struct clix_game_state_t* state)
328 int i;
329 int r;
331 state->y = BOARD_HEIGHT / 2;
332 state->x = BOARD_WIDTH / 2;
334 rb->srand( *rb->current_tick);
335 /* create a random colored board, according to the current level */
336 for(i = 0; i < BOARD_HEIGHT * BOARD_WIDTH; ++i)
338 r = rb->rand() % (state->level + 1);
339 state->board[i] = r;
343 /* this inits the game state structure */
344 static void clix_init(struct clix_game_state_t* state)
346 state->level = 1;
347 state->score = 0;
348 state->blink = false;
349 state->status = CLIX_CONTINUE;
351 clix_init_new_level(state);
353 clix_update_selected(state);
356 /* Function for drawing a cell */
357 static void clix_draw_cell(struct clix_game_state_t* state, const int x, const int y)
359 int realx = XOFS;
360 int realy = YOFS;
362 realx += x * (CELL_SIZE + 1);
363 realy += y * (CELL_SIZE + 1);
365 if (state->blink && state->board_selected[ XYPOS( x, y)]) {
366 rb->lcd_set_foreground(LCD_WHITE);
367 } else {
368 switch (state->board[ XYPOS( x, y)])
370 case CC_BLUE:
371 rb->lcd_set_foreground( LCD_RGBPACK( 25, 25, 255));
372 break;
373 case CC_GREEN:
374 rb->lcd_set_foreground( LCD_RGBPACK( 25, 255, 25));
375 break;
376 case CC_RED:
377 rb->lcd_set_foreground( LCD_RGBPACK( 255, 25, 25));
378 break;
379 case CC_YELLOW:
380 rb->lcd_set_foreground( LCD_RGBPACK( 225, 225, 25));
381 break;
382 case CC_ORANGE:
383 rb->lcd_set_foreground( LCD_RGBPACK( 230, 140, 15));
384 break;
385 case CC_CYAN:
386 rb->lcd_set_foreground( LCD_RGBPACK( 25, 245, 230));
387 break;
388 case CC_BROWN:
389 rb->lcd_set_foreground( LCD_RGBPACK(139, 69, 19));
390 break;
391 case CC_PINK:
392 rb->lcd_set_foreground( LCD_RGBPACK(255, 105, 180));
393 break;
394 case CC_DARK_GREEN:
395 rb->lcd_set_foreground( LCD_RGBPACK( 0, 100, 0));
396 break;
397 case CC_DARK_BLUE:
398 rb->lcd_set_foreground( LCD_RGBPACK( 280, 32, 144));
399 break;
400 default:
401 rb->lcd_set_foreground( LCD_BLACK);
402 break;
406 rb->lcd_fillrect( realx, realy, CELL_SIZE, CELL_SIZE);
408 /* draw cursor */
409 if ( x == state->x && y == state->y) {
410 rb->lcd_set_foreground( LCD_WHITE);
411 rb->lcd_drawrect( realx - 1, realy - 1, CELL_SIZE + 2, CELL_SIZE + 2);
415 /* main function of drawing the whole board and score... */
416 static void clix_draw(struct clix_game_state_t* state)
418 int i,j;
420 /* Clear screen */
421 rb->lcd_clear_display();
422 rb->lcd_set_foreground( LCD_WHITE);
424 rb->lcd_putsxy( MARGIN, MARGIN, "Score:");
425 rb->lcd_putsxyf( 43, MARGIN, "%d", state->score);
426 #if LCD_WIDTH <= 100
427 rb->lcd_putsxy( 75, MARGIN, "L:");
428 rb->lcd_putsxyf( 90, MARGIN, "%d", state->level);
429 #else
430 rb->lcd_putsxy( 75, MARGIN, "Level:");
431 rb->lcd_putsxyf( 113, MARGIN, "%d", state->level);
432 #endif
433 for( i = 0; i < BOARD_WIDTH; ++i)
435 for( j = 0; j < BOARD_HEIGHT; ++j)
437 clix_draw_cell( state, i, j);
441 rb->lcd_update();
442 rb->lcd_set_foreground(LCD_WHITE);
445 static void clix_move_cursor(struct clix_game_state_t* state, const bool left)
447 int x, y;
449 x = state->x;
452 y = state->y;
453 while(state->board[ XYPOS( x, y)] == CC_BLACK && y < BOARD_HEIGHT) y++;
454 if (y < BOARD_HEIGHT) {
455 state->y = y;
456 state->x = x;
458 else
460 if (left) {
461 if( x >= 0)
462 x--;
463 else
464 y = state->y;
466 else
468 if( x < BOARD_WIDTH - 1)
469 x++;
470 else
471 x = 0;
474 } while ( y != state->y);
477 /* returns the color of the given position, if out of bounds return CC_BLACK */
478 static int clix_get_color(struct clix_game_state_t* state, const int x, const int y)
480 if( x >= 0 && x < BOARD_WIDTH && y >= 0 && y < BOARD_HEIGHT)
481 return state->board[XYPOS( x, y)];
482 else
483 return CC_BLACK;
486 static int clix_clear_selected(struct clix_game_state_t* state)
488 int i, j, x, y;
489 bool found_move;
491 state->status = CLIX_CLEARED;
493 /* clear the selected blocks */
494 for( i = 0; i < BOARD_WIDTH; ++i)
496 for( j = 0; j < BOARD_HEIGHT; ++j)
498 if( state->board_selected[ XYPOS( i, j)] )
500 state->board_selected[ XYPOS( i, j)] = false;
501 state->board[ XYPOS( i, j)] = CC_BLACK;
506 /* count score */
507 state->score += state->selected_count * state->level;
508 state->selected_count = 0;
510 /* let blocks falling down */
511 for( i = BOARD_WIDTH - 1; i >= 0; --i)
513 for( j = BOARD_HEIGHT - 1; j >= 0; --j)
515 y = j;
516 while( (y + 1) < BOARD_HEIGHT &&
517 state->board[ XYPOS( i, y + 1)] == CC_BLACK
519 y++;
521 if (y != j) {
522 state->board[ XYPOS( i, y)] = state->board[ XYPOS( i, j)];
523 state->board[ XYPOS( i, j)] = CC_BLACK;
528 /* move columns to left side */
529 for( i = 0; i < BOARD_WIDTH; ++i)
531 x = i;
532 while( (x - 1) >= 0 &&
533 state->board[ XYPOS( x - 1, BOARD_HEIGHT - 1)] == CC_BLACK
535 x--;
536 if (x != i)
538 for( j = 0; j < BOARD_HEIGHT; ++j)
540 state->board[ XYPOS( x, j)] = state->board[ XYPOS( i, j)];
541 state->board[ XYPOS( i, j)] = CC_BLACK;
546 if(state->board[ XYPOS( 0, BOARD_HEIGHT - 1)] != CC_BLACK)
547 state->status = CLIX_CONTINUE;
549 if (state->status != CLIX_CLEARED) {
550 /* check if a move is still possible, otherwise the game is over.
551 tart from the left bottom, because there are the last fields
552 at the end of the game.
554 found_move = false;
555 for( i = 0; !found_move && i < BOARD_WIDTH; ++i)
557 for( j = BOARD_HEIGHT - 1; !found_move && j >= 0; --j)
559 int color = state->board[ XYPOS( i, j)];
560 if (color != CC_BLACK) {
561 if (color == clix_get_color( state, i - 1, j) ||
562 color == clix_get_color( state, i + 1, j) ||
563 color == clix_get_color( state, i, j - 1) ||
564 color == clix_get_color( state, i, j + 1)
567 found_move = true;
572 /* if the loops ended without a possible move, the game is over */
573 if( !found_move)
574 state->status = CLIX_GAMEOVER;
576 /* set cursor to the right position */
577 if (state->status == CLIX_CONTINUE) {
578 clix_move_cursor( state, true);
579 clix_update_selected( state);
583 return state->status;
586 static bool clix_help(void)
588 static char *help_text[] = {
589 "Clix", "", "Aim", "",
590 "Remove", "all", "blocks", "from", "the", "board", "to", "achieve",
591 "the", "next", "level.", "You", "can", "only", "remove", "blocks,",
592 "if", "at", "least", "two", "blocks", "with", "the", "same", "color",
593 "have", "a", "direct", "connection.", "The", "more", "blocks", "you",
594 "remove", "per", "turn,", "the", "more", "points", "you", "get."
596 static struct style_text formation[]={
597 { 0, TEXT_CENTER|TEXT_UNDERLINE },
598 { 2, C_RED },
599 LAST_STYLE_ITEM
602 rb->lcd_setfont(FONT_UI);
603 rb->lcd_set_foreground(LCD_WHITE);
604 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
605 return true;
606 rb->lcd_setfont(FONT_SYSFIXED);
608 return false;
611 static bool _ingame;
612 static int clix_menu_cb(int action, const struct menu_item_ex *this_item)
614 if(action == ACTION_REQUEST_MENUITEM
615 && !_ingame && ((intptr_t)this_item)==0)
616 return ACTION_EXIT_MENUITEM;
617 return action;
620 static int clix_menu(struct clix_game_state_t* state, bool ingame)
622 rb->button_clear_queue();
623 int choice = 0;
624 bool leave_menu=false;
625 int ret=0;
627 _ingame = ingame;
629 MENUITEM_STRINGLIST (main_menu, "Clix Menu", clix_menu_cb,
630 "Resume Game",
631 "Start New Game",
632 "Help",
633 "High Scores",
634 "Playback Control",
635 "Quit");
637 #ifdef HAVE_TOUCHSCREEN
638 /* Entering Menu, set the touchscreen to the global setting */
639 rb->touchscreen_set_mode(rb->global_settings->touch_mode);
640 #endif
642 while (!leave_menu) {
644 switch (rb->do_menu(&main_menu, &choice, NULL, false)) {
645 case 0:
646 leave_menu=true;
647 ret = 0;
648 break;
649 case 1:
650 clix_init(state);
651 leave_menu=true;
652 ret = 0;
653 break;
654 case 2:
655 if (clix_help()) {
656 leave_menu=true;
657 ret = 1;
659 break;
660 case 3:
661 highscore_show(-1, highscores, NUM_SCORES, true);
662 break;
663 case 4:
664 playback_control(NULL);
665 break;
666 case 5:
667 case MENU_ATTACHED_USB:
668 leave_menu=true;
669 ret = 1;
670 break;
671 default:
672 break;
676 #ifdef HAVE_TOUCHSCREEN
677 /* Leaving the menu, set back to pointer mode */
678 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
679 #endif
681 return ret;
684 static int clix_click(struct clix_game_state_t* state)
686 int position;
687 if (state->selected_count <= 1) {
688 return 0;
690 switch( clix_clear_selected( state))
692 case CLIX_CLEARED:
693 state->score += state->level * 100;
694 clix_draw( state);
695 if (state->level < NUM_LEVELS) {
696 rb->splash(HZ*2, "Great! Next Level!");
697 state->level++;
698 clix_init_new_level( state);
699 clix_update_selected( state);
701 else {
702 rb->splash(HZ*2, "Congratulation!!!");
703 rb->splash(HZ*2, "You have finished the game.");
704 if(clix_menu(state, 0))
705 return 1;
707 break;
708 case CLIX_GAMEOVER:
709 clix_draw( state);
710 rb->splash(HZ*2, "Game Over!");
711 rb->lcd_clear_display();
712 position = highscore_update(state->score, state->level, "",
713 highscores, NUM_SCORES);
714 if (position != -1)
716 if (position == 0)
717 rb->splash(HZ*2, "New High Score");
718 highscore_show(position, highscores, NUM_SCORES, true);
720 if(clix_menu(state, 0))
721 return 1;
722 break;
723 default:
724 rb->sleep(10); /* prevent repeating clicks */
725 break;
727 return 0;
730 static int clix_handle_game(struct clix_game_state_t* state)
732 int button;
733 int blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
735 int time;
736 int start;
737 int end;
738 int oldx, oldy;
740 if (clix_menu(state, 0))
741 return 1;
743 while(true)
745 if (TIME_AFTER(*rb->current_tick, blink_tick)) {
746 state->blink = !state->blink;
747 blink_tick = *rb->current_tick + BLINK_TICKCOUNT;
750 time = 6; /* number of ticks this function will loop reading keys */
751 start = *rb->current_tick;
752 end = start + time;
753 while(TIME_BEFORE(*rb->current_tick, end))
755 oldx = state->x;
756 oldy = state->y;
758 button = rb->button_get_w_tmo(end - *rb->current_tick);
759 #ifdef HAVE_TOUCHSCREEN
760 if(button & BUTTON_TOUCHSCREEN)
762 int x = rb->button_get_data() >> 16;
763 int y = rb->button_get_data() & 0xffff;
765 x -= XOFS;
766 y -= YOFS;
767 if(x >= 0 && y >= 0)
769 x /= CELL_SIZE + 1;
770 y /= CELL_SIZE + 1;
772 if(x < BOARD_WIDTH && y < BOARD_HEIGHT
773 && state->board[XYPOS(x, y)] != CC_BLACK)
775 if(state->x == x && state->y == y)
776 button = CLIX_BUTTON_CLICK;
777 else
779 state->x = x;
780 state->y = y;
785 #endif
786 switch( button)
788 #ifndef HAVE_TOUCHSCREEN
789 #ifdef CLIX_BUTTON_SCROLL_BACK
790 case CLIX_BUTTON_SCROLL_BACK:
791 case CLIX_BUTTON_SCROLL_BACK|BUTTON_REPEAT:
792 #endif
793 case CLIX_BUTTON_UP:
794 case CLIX_BUTTON_UP|BUTTON_REPEAT:
795 if( state->y == 0 ||
796 state->board[ XYPOS( state->x, state->y - 1)] ==
797 CC_BLACK
799 state->y = BOARD_HEIGHT - 1;
800 else
801 state->y--;
803 clix_move_cursor(state, true);
804 break;
806 #ifdef CLIX_BUTTON_SCROLL_FWD
807 case CLIX_BUTTON_SCROLL_FWD:
808 case CLIX_BUTTON_SCROLL_FWD|BUTTON_REPEAT:
809 #endif
810 case CLIX_BUTTON_DOWN:
811 case CLIX_BUTTON_DOWN|BUTTON_REPEAT:
812 if( state->y == (BOARD_HEIGHT - 1))
813 state->y = 0;
814 else
815 state->y++;
817 clix_move_cursor( state, true);
818 break;
820 case CLIX_BUTTON_RIGHT:
821 case CLIX_BUTTON_RIGHT|BUTTON_REPEAT:
822 if( state->x == (BOARD_WIDTH - 1))
823 state->x = 0;
824 else
825 state->x++;
827 clix_move_cursor(state, false);
828 break;
830 case CLIX_BUTTON_LEFT:
831 case CLIX_BUTTON_LEFT|BUTTON_REPEAT:
832 if( state->x == 0)
833 state->x = BOARD_WIDTH - 1;
834 else
835 state->x--;
837 clix_move_cursor(state, true);
838 break;
839 #endif
840 case CLIX_BUTTON_CLICK:
841 if (clix_click(state) == 1)
842 return 1;
843 break;
845 case CLIX_BUTTON_QUIT:
846 if (clix_menu(state, 1) != 0) {
847 rb->button_clear_queue();
848 return 1;
850 break;
851 default:
853 break;
856 if( (oldx != state->x || oldy != state->y) &&
857 state->board_selected[ XYPOS( oldx, oldy)] !=
858 state->board_selected[ XYPOS( state->x, state->y)]
861 clix_update_selected(state);
863 clix_draw(state);
864 rb->sleep(time);
869 /* this is the plugin entry point */
870 enum plugin_status plugin_start(const void* parameter)
872 (void)parameter;
874 rb->lcd_set_backdrop(NULL);
875 rb->lcd_set_foreground(LCD_WHITE);
876 rb->lcd_set_background(LCD_BLACK);
877 rb->lcd_setfont(FONT_SYSFIXED);
878 #ifdef HAVE_TOUCHSCREEN
879 rb->touchscreen_set_mode(TOUCHSCREEN_POINT);
880 #endif
882 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
884 struct clix_game_state_t state;
885 clix_handle_game( &state);
887 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
889 return PLUGIN_OK;