very minor code police. also fix a possible but unlikely missed cpu_boost(false)
[Rockbox.git] / apps / plugins / rockblox.c
blob27ae8e2f990b66557696c1de3aa4cf78a7dd7ef2
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2005 Eli Sherer
12 * Heavily modified for embedded use by Björn Stenberg (bjorn@haxx.se)
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
23 #include "plugin.h"
24 #include "highscore.h"
25 #include "playergfx.h"
26 #include "helper.h"
28 PLUGIN_HEADER
30 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
31 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
32 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
34 #define ROCKBLOX_OFF (BUTTON_MENU | BUTTON_SELECT)
35 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
36 #define ROCKBLOX_ROTATE_RIGHT2 (BUTTON_MENU | BUTTON_REL)
37 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
38 #define ROCKBLOX_LEFT BUTTON_LEFT
39 #define ROCKBLOX_RIGHT BUTTON_RIGHT
40 #define ROCKBLOX_DOWN BUTTON_PLAY
41 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_PLAY)
42 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
44 #define SCROLL_WHEEL
46 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
47 (CONFIG_KEYPAD == IRIVER_H300_PAD)
49 #define ROCKBLOX_OFF BUTTON_OFF
50 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
51 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
52 #define ROCKBLOX_DOWN BUTTON_DOWN
53 #define ROCKBLOX_LEFT BUTTON_LEFT
54 #define ROCKBLOX_RIGHT BUTTON_RIGHT
55 #define ROCKBLOX_DROP BUTTON_MODE
56 #define ROCKBLOX_RESTART BUTTON_ON
58 #define ROCKBLOX_RC_OFF BUTTON_RC_STOP
60 #elif CONFIG_KEYPAD == RECORDER_PAD
62 #define ROCKBLOX_OFF BUTTON_OFF
63 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
64 #define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
65 #define ROCKBLOX_DOWN BUTTON_DOWN
66 #define ROCKBLOX_LEFT BUTTON_LEFT
67 #define ROCKBLOX_RIGHT BUTTON_RIGHT
68 #define ROCKBLOX_DROP BUTTON_ON
69 #define ROCKBLOX_RESTART BUTTON_F1
71 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
73 #define ROCKBLOX_OFF BUTTON_OFF
74 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
75 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
76 #define ROCKBLOX_DOWN BUTTON_DOWN
77 #define ROCKBLOX_LEFT BUTTON_LEFT
78 #define ROCKBLOX_RIGHT BUTTON_RIGHT
79 #define ROCKBLOX_DROP BUTTON_ON
80 #define ROCKBLOX_RESTART BUTTON_F1
82 #elif CONFIG_KEYPAD == PLAYER_PAD
84 #define ROCKBLOX_OFF BUTTON_STOP
85 #define ROCKBLOX_ROTATE_RIGHT BUTTON_PLAY
86 #define ROCKBLOX_ROTATE_LEFT (BUTTON_ON|BUTTON_PLAY)
87 #define ROCKBLOX_DOWN BUTTON_MENU
88 #define ROCKBLOX_LEFT BUTTON_LEFT
89 #define ROCKBLOX_RIGHT BUTTON_RIGHT
90 #define ROCKBLOX_DROP_PRE BUTTON_ON
91 #define ROCKBLOX_DROP (BUTTON_ON|BUTTON_REL)
93 #elif CONFIG_KEYPAD == ONDIO_PAD
95 #define ROCKBLOX_OFF BUTTON_OFF
96 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
97 #define ROCKBLOX_ROTATE_LEFT (BUTTON_MENU|BUTTON_UP)
98 #define ROCKBLOX_DOWN BUTTON_DOWN
99 #define ROCKBLOX_LEFT BUTTON_LEFT
100 #define ROCKBLOX_RIGHT BUTTON_RIGHT
101 #define ROCKBLOX_DROP_PRE BUTTON_MENU
102 #define ROCKBLOX_DROP (BUTTON_MENU|BUTTON_REL)
104 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
106 #define ROCKBLOX_OFF BUTTON_POWER
107 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
108 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
109 #define ROCKBLOX_DOWN BUTTON_DOWN
110 #define ROCKBLOX_LEFT BUTTON_LEFT
111 #define ROCKBLOX_RIGHT BUTTON_RIGHT
112 #define ROCKBLOX_DROP BUTTON_REC
113 #define ROCKBLOX_RESTART BUTTON_PLAY
115 #elif CONFIG_KEYPAD == SANSA_E200_PAD
117 #define ROCKBLOX_OFF BUTTON_POWER
118 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
119 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
120 #define ROCKBLOX_DOWN BUTTON_DOWN
121 #define ROCKBLOX_LEFT BUTTON_LEFT
122 #define ROCKBLOX_RIGHT BUTTON_RIGHT
123 #define ROCKBLOX_DROP BUTTON_SELECT
124 #define ROCKBLOX_RESTART BUTTON_REC
126 #elif CONFIG_KEYPAD == SANSA_C200_PAD
128 #define ROCKBLOX_OFF BUTTON_POWER
129 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
130 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_VOL_DOWN
131 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
132 #define ROCKBLOX_DOWN BUTTON_DOWN
133 #define ROCKBLOX_LEFT BUTTON_LEFT
134 #define ROCKBLOX_RIGHT BUTTON_RIGHT
135 #define ROCKBLOX_DROP BUTTON_SELECT
136 #define ROCKBLOX_RESTART BUTTON_REC
138 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
140 #define ROCKBLOX_OFF BUTTON_POWER
141 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_UP
142 #define ROCKBLOX_ROTATE_LEFT BUTTON_REW
143 #define ROCKBLOX_DOWN BUTTON_SCROLL_DOWN
144 #define ROCKBLOX_LEFT BUTTON_LEFT
145 #define ROCKBLOX_RIGHT BUTTON_RIGHT
146 #define ROCKBLOX_DROP BUTTON_FF
147 #define ROCKBLOX_RESTART BUTTON_PLAY
149 #elif CONFIG_KEYPAD == GIGABEAT_PAD
151 #define ROCKBLOX_OFF BUTTON_POWER
152 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
153 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
154 #define ROCKBLOX_ROTATE BUTTON_UP
155 #define ROCKBLOX_DOWN BUTTON_DOWN
156 #define ROCKBLOX_LEFT BUTTON_LEFT
157 #define ROCKBLOX_RIGHT BUTTON_RIGHT
158 #define ROCKBLOX_DROP BUTTON_SELECT
159 #define ROCKBLOX_RESTART BUTTON_A
161 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
163 #define ROCKBLOX_OFF BUTTON_PLAY
164 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
165 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
166 #define ROCKBLOX_DOWN BUTTON_DOWN
167 #define ROCKBLOX_LEFT BUTTON_LEFT
168 #define ROCKBLOX_RIGHT BUTTON_RIGHT
169 #define ROCKBLOX_DROP BUTTON_MODE
170 #define ROCKBLOX_RESTART BUTTON_EQ
172 #elif CONFIG_KEYPAD == MROBE500_PAD
173 #define ROCKBLOX_OFF BUTTON_POWER
174 #define ROCKBLOX_ROTATE_RIGHT BUTTON_RC_VOL_UP
175 #define ROCKBLOX_ROTATE_LEFT BUTTON_RC_VOL_DOWN
176 #define ROCKBLOX_DOWN BUTTON_RC_DOWN
177 #define ROCKBLOX_LEFT BUTTON_LEFT
178 #define ROCKBLOX_RIGHT BUTTON_RIGHT
179 #define ROCKBLOX_DROP BUTTON_RC_HEART
180 #define ROCKBLOX_RESTART BUTTON_RC_MODE
182 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
183 #define ROCKBLOX_OFF BUTTON_BACK
184 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
185 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
186 #define ROCKBLOX_ROTATE BUTTON_UP
187 #define ROCKBLOX_DOWN BUTTON_DOWN
188 #define ROCKBLOX_LEFT BUTTON_LEFT
189 #define ROCKBLOX_RIGHT BUTTON_RIGHT
190 #define ROCKBLOX_DROP BUTTON_SELECT
191 #define ROCKBLOX_RESTART BUTTON_PLAY
193 #elif CONFIG_KEYPAD == MROBE100_PAD
195 #define ROCKBLOX_OFF BUTTON_POWER
196 #define ROCKBLOX_ROTATE_RIGHT BUTTON_MENU
197 #define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
198 #define ROCKBLOX_ROTATE BUTTON_UP
199 #define ROCKBLOX_DOWN BUTTON_DOWN
200 #define ROCKBLOX_LEFT BUTTON_LEFT
201 #define ROCKBLOX_RIGHT BUTTON_RIGHT
202 #define ROCKBLOX_DROP BUTTON_SELECT
203 #define ROCKBLOX_RESTART BUTTON_DISPLAY
205 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
207 #define ROCKBLOX_OFF BUTTON_RC_REC
208 #define ROCKBLOX_ROTATE_RIGHT BUTTON_RC_VOL_DOWN
209 #define ROCKBLOX_ROTATE_LEFT BUTTON_RC_VOL_UP
210 #define ROCKBLOX_DOWN BUTTON_RC_MENU
211 #define ROCKBLOX_LEFT BUTTON_RC_REW
212 #define ROCKBLOX_RIGHT BUTTON_RC_FF
213 #define ROCKBLOX_DROP BUTTON_RC_PLAY
214 #define ROCKBLOX_RESTART BUTTON_RC_MODE
216 #elif CONFIG_KEYPAD == COWOND2_PAD
217 #define ROCKBLOX_OFF BUTTON_POWER
218 #define ROCKBLOX_RESTART BUTTON_MENU
220 #else
221 #error No keymap defined!
222 #endif
224 #ifdef HAVE_TOUCHPAD
225 #ifndef ROCKBLOX_OFF
226 #define ROCKBLOX_OFF BUTTON_TOPLEFT
227 #endif
228 #ifndef ROCKBLOX_ROTATE_RIGHT
229 #define ROCKBLOX_ROTATE_RIGHT BUTTON_BOTTOMRIGHT
230 #endif
231 #ifndef ROCKBLOX_ROTATE_LEFT
232 #define ROCKBLOX_ROTATE_LEFT BUTTON_BOTTOMLEFT
233 #endif
234 #ifndef ROCKBLOX_DOWN
235 #define ROCKBLOX_DOWN BUTTON_BOTTOMMIDDLE
236 #endif
237 #ifndef ROCKBLOX_LEFT
238 #define ROCKBLOX_LEFT BUTTON_MIDLEFT
239 #endif
240 #ifndef ROCKBLOX_RIGHT
241 #define ROCKBLOX_RIGHT BUTTON_MIDRIGHT
242 #endif
243 #ifndef ROCKBLOX_DROP
244 #define ROCKBLOX_DROP BUTTON_CENTER
245 #endif
246 #ifndef ROCKBLOX_RESTART
247 #define ROCKBLOX_RESTART BUTTON_TOPRIGHT
248 #endif
249 #endif
251 #define BLOCKS_NUM 7
252 #define EMPTY_BLOCK 7
254 #define BOARD_WIDTH 10
256 #ifdef HAVE_LCD_BITMAP
258 #define BOARD_HEIGHT 20
260 #if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
262 #define BLOCK_WIDTH 30
263 #define BLOCK_HEIGHT 30
264 #define BOARD_X 14
265 #define BOARD_Y 2
266 #define PREVIEW_X 342
267 #define PREVIEW_Y 482
268 #define LABEL_X 344
269 #define SCORE_Y 58
270 #define LEVEL_Y 142
271 #define LINES_Y 218
272 #define HIGH_LABEL_X 344
273 #define HIGH_SCORE_Y 326
274 #define HIGH_LEVEL_Y 344
276 #elif (LCD_WIDTH == 480) && (LCD_HEIGHT == 640)
278 #define BLOCK_WIDTH 30
279 #define BLOCK_HEIGHT 30
280 #define BOARD_X 14
281 #define BOARD_Y 2
282 #define PREVIEW_X 342
283 #define PREVIEW_Y 482
284 #define LABEL_X 344
285 #define SCORE_Y 58
286 #define LEVEL_Y 142
287 #define LINES_Y 218
288 #define HIGH_LABEL_X 344
289 #define HIGH_SCORE_Y 326
290 #define HIGH_LEVEL_Y 344
292 #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
294 #define BLOCK_WIDTH 12
295 #define BLOCK_HEIGHT 12
296 #define BOARD_X 86
297 #define BOARD_Y 0
298 #define PREVIEW_X 12
299 #define PREVIEW_Y 11
300 #define LABEL_X 242
301 #define SCORE_Y 25
302 #define LEVEL_Y 70
303 #define LINES_Y 105
305 #elif (LCD_WIDTH == 240) && (LCD_HEIGHT == 320)
307 #define BLOCK_WIDTH 15
308 #define BLOCK_HEIGHT 15
309 #define BOARD_X 7
310 #define BOARD_Y 1
311 #define PREVIEW_X 171
312 #define PREVIEW_Y 241
313 #define LABEL_X 172
314 #define SCORE_Y 29
315 #define LEVEL_Y 71
316 #define LINES_Y 109
317 #define HIGH_LABEL_X 172
318 #define HIGH_SCORE_Y 163
319 #define HIGH_LEVEL_Y 172
321 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
323 #define BLOCK_WIDTH 8
324 #define BLOCK_HEIGHT 8
325 #define BOARD_X 27
326 #define BOARD_Y 5
327 #define PREVIEW_X 158
328 #define PREVIEW_Y 130
329 #define LABEL_X 147
330 #define SCORE_Y 20
331 #define LEVEL_Y 65
332 #define LINES_Y 100
334 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
336 #define BLOCK_WIDTH 6
337 #define BLOCK_HEIGHT 6
338 #define BOARD_X 25
339 #define BOARD_Y 1
340 #define PREVIEW_X 126
341 #define PREVIEW_Y 102
342 #define LABEL_X 112
343 #define SCORE_Y 17
344 #define LEVEL_Y 49
345 #define LINES_Y 81
347 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
349 #define BLOCK_WIDTH 10
350 #define BLOCK_HEIGHT 10
351 #define BOARD_X 6
352 #define BOARD_Y 10
353 #define PREVIEW_X 124
354 #define PREVIEW_Y 167
355 #define LABEL_X 117
356 #define SCORE_Y 24
357 #define LEVEL_Y 65
358 #define LINES_Y 103
359 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
361 #define BLOCK_WIDTH 6
362 #define BLOCK_HEIGHT 6
363 #define BOARD_X 22
364 #define BOARD_Y 3
365 #define PREVIEW_X 114
366 #define PREVIEW_Y 100
367 #define LABEL_X 101
368 #define SCORE_Y 17
369 #define LEVEL_Y 49
370 #define LINES_Y 82
372 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
374 #define BLOCK_WIDTH 5
375 #define BLOCK_HEIGHT 5
376 #define BOARD_X 14
377 #define BOARD_Y 0
378 #define PREVIEW_X 98
379 #define PREVIEW_Y 88
380 #define LABEL_X 80
381 #define SCORE_Y 15
382 #define LEVEL_Y 45
383 #define LINES_Y 74
385 #elif (LCD_WIDTH == 132) && (LCD_HEIGHT == 80)
387 #define BLOCK_WIDTH 4
388 #define BLOCK_HEIGHT 4
389 #define BOARD_X 10
390 #define BOARD_Y 0
391 #define PREVIEW_X 89
392 #define PREVIEW_Y 61
393 #define LABEL_X 78
394 #define SCORE_Y 10
395 #define LEVEL_Y 30
396 #define LINES_Y 50
398 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
400 #define BLOCK_WIDTH 6
401 #define BLOCK_HEIGHT 6
402 #define BOARD_X 4
403 #define BOARD_Y 3
404 #define PREVIEW_X 84
405 #define PREVIEW_Y 100
406 #define LABEL_X 71
407 #define SCORE_Y 17
408 #define LEVEL_Y 49
409 #define LINES_Y 82
411 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 96)
413 #define BLOCK_WIDTH 4
414 #define BLOCK_HEIGHT 4
415 #define BOARD_X 14
416 #define BOARD_Y 2
417 #define PREVIEW_X 89
418 #define PREVIEW_Y 76
419 #define LABEL_X 70
420 #define SCORE_Y 14
421 #define LEVEL_Y 39
422 #define LINES_Y 64
424 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 64)
426 #define BLOCK_WIDTH 3
427 #define BLOCK_HEIGHT 3
428 #define BOARD_X 9
429 #define BOARD_Y 3
430 #define PREVIEW_X 53
431 #define PREVIEW_Y 5
432 #define LABEL_X 70
433 #define SCORE_Y 32
434 #define LEVEL_Y 13
435 #define LINES_Y 51
437 #elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
439 #define BLOCK_WIDTH 4
440 #define BLOCK_HEIGHT 3
441 #define BOARD_X 9
442 #define BOARD_Y 3
443 #define PREVIEW_X 59
444 #define PREVIEW_Y 5
445 #define LABEL_X 59
446 #define SCORE_Y 32
447 #define LEVEL_Y 13
448 #define LEVEL_X 78
449 #define LINES_Y 51
451 #endif
453 #ifndef LEVEL_X
454 #define LEVEL_X LABEL_X
455 #endif
457 #ifndef LINES_X
458 #define LINES_X LABEL_X
459 #endif
461 #define MYLCD(fn) rb->lcd_ ## fn
463 extern const fb_data rockblox_background[];
465 #else /* HAVE_LCD_CHARCELLS */
467 #define BOARD_HEIGHT 14
469 #define BLOCK_WIDTH 1
470 #define BLOCK_HEIGHT 1
471 #define BOARD_X 5
472 #define BOARD_Y 0
473 #define PREVIEW_X 15
474 #define PREVIEW_Y 1
476 #define MYLCD(fn) pgfx_ ## fn
478 #endif
480 /* <<Explanation on Rockblox shapes>>
483 %% - O has 1 orientation
485 %% %
486 %% %% - Z has 2 orientations
489 %% %
490 %% %% - S has 2 orientations
494 % %%%% - I has 2 orientations
497 % %%
498 % % % %%% - L has 4 orientations
499 %% %%% % %
501 % %%s
502 % % % %%% - J has 4 orientations
503 %% %%% % %
505 % % %%%
506 %% % %% % - T has 4 orientations
507 % %%% %
511 /* must have variable */
512 static const struct plugin_api *rb;
514 static bool gameover = false;
515 /* c=current f=figure o=orientation n=next */
516 static int lines = 0, level = 0, score = 0, cx, cy, cf, co, nf;
517 static short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */
519 #ifdef SCROLL_WHEEL
520 int wheel_events = 0, last_wheel_event = 0;
521 bool wheel_enabled = false;
522 #endif
524 static const short scoring[4] = { /* scoring for each number of lines */
525 #if BOARD_HEIGHT == 20
526 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
527 #elif BOARD_HEIGHT == 14 /* Player special values */
528 60 /* single */ , 150 /* double */ , 500 /* triple */ , 2000 /* rockblox */
529 #endif
532 struct figure
534 #if LCD_DEPTH >= 2
535 unsigned short color[3]; /* color of figure (light,middle,shadow) */
536 #endif
537 unsigned short max_or; /* max orientations */
538 signed short shapeX[4], shapeY[4]; /* implementation of figures */
541 /* array of figures */
542 figures[BLOCKS_NUM] = {
543 /* O */
545 #if LCD_DEPTH >= 16
546 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
547 LCD_RGBPACK(0,153,153)},
548 #elif LCD_DEPTH == 2
549 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
550 #endif
552 {-1, 0, -1, 0},
553 {0, 0, 1, 1}
555 /* I */
557 #if LCD_DEPTH >= 16
558 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
559 LCD_RGBPACK (153, 0, 0)},
560 #elif LCD_DEPTH == 2
561 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
562 #endif
564 {-2, -1, 0, 1},
565 {0, 0, 0, 0}
567 /* 'Z' */
569 #if LCD_DEPTH >= 16
570 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
571 LCD_RGBPACK (0, 153, 0)},
572 #elif LCD_DEPTH == 2
573 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
574 #endif
576 {0, 1, -1, 0},
577 {0, 0, 1, 1}
579 /* 'S' */
581 #if LCD_DEPTH >= 16
582 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
583 LCD_RGBPACK (0, 0, 153)},
584 #elif LCD_DEPTH == 2
585 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
586 #endif
588 {-1, 0, 0, 1},
589 {0, 0, 1, 1}
591 /* 'L' */
593 #if LCD_DEPTH >= 16
594 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
595 LCD_RGBPACK (153, 153, 0)},
596 #elif LCD_DEPTH == 2
597 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
598 #endif
600 {-1, 0, 1, 1},
601 {0, 0, 0, 1}
603 /* 'J' */
605 #if LCD_DEPTH >= 16
606 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
607 LCD_RGBPACK (153, 0, 153)},
608 #elif LCD_DEPTH == 2
609 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
610 #endif
612 {-1, 0, 1, -1},
613 {0, 0, 0, 1}
615 /* 'T' */
617 #if LCD_DEPTH >= 16
618 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
619 LCD_RGBPACK (85, 85, 85)},
620 #elif LCD_DEPTH == 2
621 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
622 #endif
624 {-1, 0, 1, 0},
625 {0, 0, 0, 1}
629 /* Rockbox File System only supports full filenames inc dir */
630 #define HIGH_SCORE PLUGIN_GAMES_DIR "/rockblox.score"
631 #define MAX_HIGH_SCORES 5
632 /* Default High Scores... */
633 struct highscore Highest[MAX_HIGH_SCORES];
635 /* get random number from (0) to (range-1) */
636 static int t_rand (int range)
638 return rb->rand () % range;
641 /* init the board array to have no blocks */
642 static void init_board (void)
644 int i, j;
645 for (i = 0; i < BOARD_WIDTH; i++)
646 for (j = 0; j < BOARD_HEIGHT; j++)
647 board[j][i] = EMPTY_BLOCK;
650 /* show the score, level and lines */
651 static void show_details (void)
653 char str[25]; /* for strings */
655 #ifdef HAVE_LCD_BITMAP
656 #if LCD_DEPTH >= 2
657 rb->lcd_set_foreground (LCD_BLACK);
658 rb->lcd_set_background (LCD_WHITE);
659 #endif
660 rb->snprintf (str, sizeof (str), "%d", score);
661 rb->lcd_putsxy (LABEL_X, SCORE_Y, str);
662 rb->snprintf (str, sizeof (str), "%d", level);
663 rb->lcd_putsxy (LEVEL_X, LEVEL_Y, str);
664 rb->snprintf (str, sizeof (str), "%d", lines);
665 rb->lcd_putsxy (LINES_X, LINES_Y, str);
666 #else /* HAVE_LCD_CHARCELLS */
667 rb->snprintf (str, sizeof (str), "L%d/%d", level, lines);
668 rb->lcd_puts (5, 0, str);
669 rb->snprintf (str, sizeof (str), "S%d", score);
670 rb->lcd_puts (5, 1, str);
671 #endif
674 #ifdef HIGH_SCORE_Y
675 static void show_highscores (void)
677 int i;
678 char str[25]; /* for strings */
680 for (i = MAX_HIGH_SCORES-1; i>=0; i--)
682 rb->snprintf (str, sizeof (str), "%06d L%1d", Highest[i].score, Highest[i].level);
683 rb->lcd_putsxy (HIGH_LABEL_X, HIGH_SCORE_Y + (10 * ((MAX_HIGH_SCORES-1) - i)), str);
686 #endif
688 static void init_rockblox (void)
690 highscore_update(score, level, Highest, MAX_HIGH_SCORES);
692 level = 1;
693 lines = 0;
694 score = 0;
695 gameover = false;
696 nf = t_rand (BLOCKS_NUM);
697 init_board ();
698 #ifdef HAVE_LCD_BITMAP
699 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
700 #else /* HAVE_LCD_CHARCELLS */
701 pgfx_display (0, 0);
702 pgfx_display_block (3, 0, 3, 1);
703 pgfx_display_block (4, 0, 3, 0);
704 pgfx_clear_display();
705 pgfx_fillrect (3, 0, 2, 14);
706 pgfx_fillrect (15, 7, 2, 7);
707 pgfx_update();
708 #endif
709 show_details ();
710 #ifdef HIGH_SCORE_Y
711 show_highscores ();
712 #endif
715 static inline int level_speed(int level)
717 #if BOARD_HEIGHT == 20
718 return (5*HZ) / (level + 9);
719 #elif BOARD_HEIGHT == 14
720 return (7*HZ) / (level + 9);
721 #endif
724 static int getRelativeX (int figure, int square, int orientation)
726 switch (orientation) {
727 case 0:
728 return figures[figure].shapeX[square];
729 case 1:
730 return figures[figure].shapeY[square];
731 case 2:
732 return -figures[figure].shapeX[square];
733 case 3:
734 return -figures[figure].shapeY[square];
735 default:
736 return 0;
740 static int getRelativeY (int figure, int square, int orientation)
742 switch (orientation) {
743 case 0:
744 return figures[figure].shapeY[square];
745 case 1:
746 return -figures[figure].shapeX[square];
747 case 2:
748 return -figures[figure].shapeY[square];
749 case 3:
750 return figures[figure].shapeX[square];
751 default:
752 return 0;
756 /* redraw the while board on the screen */
757 static void refresh_board (void)
759 int i, j, x, y, block;
761 #if LCD_DEPTH >= 2
762 rb->lcd_set_foreground (LCD_BLACK);
763 #elif LCD_DEPTH == 1
764 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
765 #endif
767 MYLCD(fillrect) (BOARD_X, BOARD_Y, BOARD_WIDTH * BLOCK_WIDTH,
768 BOARD_HEIGHT * BLOCK_HEIGHT);
770 #if LCD_DEPTH == 1
771 MYLCD(set_drawmode) (DRMODE_SOLID);
772 #endif
774 for (i = 0; i < BOARD_WIDTH; i++)
775 for (j = 0; j < BOARD_HEIGHT; j++) {
776 block = board[j][i];
777 if (block != EMPTY_BLOCK) {
778 #ifdef HAVE_LCD_BITMAP
779 #if LCD_DEPTH >= 2
780 /* middle drawing */
781 rb->lcd_set_foreground (figures[block].color[1]);
782 #endif
783 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
784 BOARD_Y + j * BLOCK_HEIGHT,
785 BLOCK_WIDTH, BLOCK_HEIGHT);
786 #if LCD_DEPTH >= 2
787 /* light drawing */
788 rb->lcd_set_foreground (figures[block].color[0]);
789 #endif
790 rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH,
791 BOARD_Y + j * BLOCK_HEIGHT,
792 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2);
793 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH,
794 BOARD_X + (i + 1) * BLOCK_WIDTH - 2,
795 BOARD_Y + j * BLOCK_HEIGHT);
796 #if LCD_DEPTH >= 2
797 /* shadow drawing */
798 rb->lcd_set_foreground (figures[block].color[2]);
799 #endif
800 rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
801 BOARD_Y + j * BLOCK_HEIGHT + 1,
802 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
803 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1,
804 BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
805 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
806 #else /* HAVE_LCD_CHARCELLS */
807 pgfx_drawpixel (BOARD_X + i, BOARD_Y + j);
808 #endif
812 for (i = 0; i < 4; i++) {
813 x = getRelativeX (cf, i, co) + cx;
814 y = getRelativeY (cf, i, co) + cy;
815 #ifdef HAVE_LCD_BITMAP
816 #if LCD_DEPTH >= 2
817 rb->lcd_set_foreground (figures[cf].color[1]); /* middle drawing */
818 #endif
819 rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH,
820 BOARD_Y + y * BLOCK_HEIGHT,
821 BLOCK_WIDTH, BLOCK_HEIGHT);
822 #if LCD_DEPTH >= 2
823 rb->lcd_set_foreground (figures[cf].color[0]); /* light drawing */
824 #endif
825 rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT,
826 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2);
827 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH,
828 BOARD_X + (x + 1) * BLOCK_WIDTH - 2,
829 BOARD_Y + y * BLOCK_HEIGHT);
830 #if LCD_DEPTH >= 2
831 rb->lcd_set_foreground (figures[cf].color[2]); /* shadow drawing */
832 #endif
833 rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
834 BOARD_Y + y * BLOCK_HEIGHT + 1,
835 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
836 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1,
837 BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
838 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
839 #else /* HAVE_LCD_CHARCELLS */
840 pgfx_drawpixel (BOARD_X + x, BOARD_Y + y);
841 #endif
843 MYLCD(update) ();
846 static bool canMoveTo (int x, int y, int newOrientation)
848 int i, rx, ry;
849 for (i = 0; i < 4; i++) {
850 ry = getRelativeY (cf, i, newOrientation) + y;
851 rx = getRelativeX (cf, i, newOrientation) + x;
852 if ((rx < 0 || rx >= BOARD_WIDTH) ||
853 (ry < 0 || ry >= BOARD_HEIGHT) || (board[ry][rx] != EMPTY_BLOCK))
854 return false;
856 return true;
859 /* draws the preview of next block in the preview window */
860 static void draw_next_block (void)
862 int i, rx, ry;
863 /* clear preview window first */
864 #if LCD_DEPTH >= 2
865 rb->lcd_set_foreground (LCD_BLACK);
866 #elif LCD_DEPTH == 1
867 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
868 #endif
870 /* 4x4 */
871 MYLCD(fillrect) (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4);
873 #if LCD_DEPTH == 1
874 MYLCD(set_drawmode) (DRMODE_SOLID);
875 #endif
877 /* draw the lightgray rectangles */
878 #if LCD_DEPTH >= 16
879 rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
880 #elif LCD_DEPTH == 2
881 rb->lcd_set_foreground (LCD_DARKGRAY);
882 #endif
884 #if LCD_DEPTH >= 2
885 for (rx = 0; rx < 4; rx++)
886 for (ry = 0; ry < 4; ry++)
887 rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH,
888 PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH,
889 BLOCK_HEIGHT);
890 #endif
892 /* draw the figure */
893 for (i = 0; i < 4; i++) {
894 rx = getRelativeX (nf, i, 0) + 2;
895 ry = getRelativeY (nf, i, 0) + 2;
896 #ifdef HAVE_LCD_BITMAP
897 #if LCD_DEPTH >= 2
898 rb->lcd_set_foreground (figures[nf].color[1]); /* middle drawing */
899 #endif
900 rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH,
901 PREVIEW_Y + ry * BLOCK_HEIGHT,
902 BLOCK_WIDTH, BLOCK_HEIGHT);
903 #if LCD_DEPTH >= 2
904 rb->lcd_set_foreground (figures[nf].color[0]); /* light drawing */
905 #endif
906 rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH,
907 PREVIEW_Y + ry * BLOCK_HEIGHT,
908 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2);
909 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH,
910 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2,
911 PREVIEW_Y + ry * BLOCK_HEIGHT);
912 #if LCD_DEPTH >= 2
913 rb->lcd_set_foreground (figures[nf].color[2]); /* shadow drawing */
914 #endif
915 rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
916 PREVIEW_Y + ry * BLOCK_HEIGHT + 1,
917 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
918 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1,
919 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
920 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
921 #else /* HAVE_LCD_CHARCELLS */
922 pgfx_drawpixel (PREVIEW_X + rx, PREVIEW_Y + ry);
923 #endif
928 /* move the block to a relative location */
929 static void move_block (int x, int y, int o)
931 if (canMoveTo (cx + x, cy + y, o)) {
932 cy += y;
933 cx += x;
934 co = o;
938 /* try to add a new block to play with (return true if gameover) */
939 static void new_block (void)
941 cy = 1;
942 cx = 5;
943 cf = nf;
944 co = 0; /* start at the same orientation all time */
945 nf = t_rand (BLOCKS_NUM);
946 gameover = !canMoveTo (cx, cy, co);
948 draw_next_block ();
952 /* check for filled lines and do what necessary */
953 static int check_lines (void)
955 int i, j, y;
956 int rockblox = 0;
958 for (j = 0; j < BOARD_HEIGHT; j++) {
959 for (i = 0; ((i < BOARD_WIDTH) && (board[j][i] != EMPTY_BLOCK)); i++);
960 if (i == BOARD_WIDTH) { /* woo hoo, we have a line */
961 rockblox++;
962 for (y = j; y > 0; y--)
963 for (i = 0; i < BOARD_WIDTH; i++)
964 board[y][i] = board[y - 1][i]; /* fall line */
968 return rockblox;
971 /* moves down the figure and returns true if gameover */
972 static void move_down (void)
974 int l, i, rx, ry;
976 if (!canMoveTo (cx, cy + 1, co)) {
977 /* save figure to board */
978 for (i = 0; i < 4; i++) {
979 rx = getRelativeX (cf, i, co) + cx;
980 ry = getRelativeY (cf, i, co) + cy;
981 board[ry][rx] = cf;
983 /* check if formed some lines */
984 l = check_lines ();
985 if (l) {
986 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
987 score += scoring[l - 1] * level;
988 lines += l;
989 level = (int) lines / 10 + 1;
992 /* show details */
993 show_details ();
995 /* generate a new figure */
996 new_block ();
997 } else
998 move_block (0, 1, co);
1001 static int rockblox_loop (void)
1003 int button;
1004 int lastbutton = BUTTON_NONE;
1005 long next_down_tick = *rb->current_tick + level_speed(level);
1007 new_block ();
1009 while (1) {
1010 #ifdef HAS_BUTTON_HOLD
1011 if (rb->button_hold ()) {
1012 /* Turn on backlight timeout (revert to settings) */
1013 backlight_use_settings(rb); /* backlight control in lib/helper.c */
1014 rb->splash(0, "Paused");
1015 while (rb->button_hold ())
1016 rb->sleep(HZ/10);
1018 /* Turn off backlight timeout */
1019 backlight_force_on(rb); /* backlight control in lib/helper.c */
1021 /* get rid of the splash text */
1022 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
1023 show_details ();
1024 #ifdef HIGH_SCORE_Y
1025 show_highscores ();
1026 #endif
1027 draw_next_block ();
1028 refresh_board ();
1030 #endif
1032 button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1));
1033 switch (button) {
1034 #ifdef ROCKBLOX_RC_OFF
1035 case ROCKBLOX_RC_OFF:
1036 #endif
1037 case ROCKBLOX_OFF:
1038 return PLUGIN_OK;
1040 #if defined(ROCKBLOX_ROTATE)
1041 case ROCKBLOX_ROTATE:
1042 #endif
1043 case ROCKBLOX_ROTATE_RIGHT:
1044 case ROCKBLOX_ROTATE_RIGHT | BUTTON_REPEAT:
1045 #ifdef SCROLL_WHEEL
1046 /* if the wheel is disabled, add an event to the stack. */
1047 if(wheel_enabled == false)
1048 wheel_events++;
1050 /* if it's enabled, go ahead and rotate.. */
1051 if(wheel_enabled)
1052 #endif
1053 move_block (0, 0, (co + 1) % figures[cf].max_or);
1054 break;
1056 case ROCKBLOX_ROTATE_LEFT:
1057 case ROCKBLOX_ROTATE_LEFT | BUTTON_REPEAT:
1058 #ifdef SCROLL_WHEEL
1059 if(wheel_enabled == false)
1060 wheel_events++;
1062 if(wheel_enabled)
1063 #endif
1064 move_block (0, 0,
1065 (co + figures[cf].max_or -
1066 1) % figures[cf].max_or);
1067 break;
1069 #ifdef ROCKBLOX_ROTATE_RIGHT2
1070 case ROCKBLOX_ROTATE_RIGHT2:
1071 move_block (0, 0, (co + 1) % figures[cf].max_or);
1072 break;
1073 #endif
1075 case ROCKBLOX_DOWN:
1076 case ROCKBLOX_DOWN | BUTTON_REPEAT:
1077 move_block (0, 1, co);
1078 break;
1080 case ROCKBLOX_RIGHT:
1081 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
1082 move_block (1, 0, co);
1083 break;
1085 case ROCKBLOX_LEFT:
1086 case ROCKBLOX_LEFT | BUTTON_REPEAT:
1087 move_block (-1, 0, co);
1088 break;
1090 case ROCKBLOX_DROP:
1091 #ifdef ROCKBLOX_DROP_PRE
1092 if (lastbutton != ROCKBLOX_DROP_PRE)
1093 break;
1094 #endif
1095 while (canMoveTo (cx, cy + 1, co))
1096 move_block (0, 1, co);
1097 break;
1098 #ifdef ROCKBLOX_RESTART
1099 case ROCKBLOX_RESTART:
1100 rb->splash (HZ * 1, "Restarting...");
1101 init_rockblox ();
1102 new_block ();
1103 break;
1104 #endif
1106 default:
1107 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
1108 return PLUGIN_USB_CONNECTED;
1109 break;
1111 if (button != BUTTON_NONE)
1112 lastbutton = button;
1114 #ifdef SCROLL_WHEEL
1115 /* check if we should enable the scroll wheel, if events
1116 * begin to stack up... */
1117 if(wheel_enabled == false)
1119 /* stopped rotating the wheel, reset the count */
1120 if(wheel_events == last_wheel_event)
1122 last_wheel_event = 0;
1123 wheel_events = 0;
1125 /* rotated the wheel a while constantly, enable it. */
1126 else if(wheel_events > 3)
1128 wheel_enabled = true;
1131 /* this evens out the last event and the "current" event.
1132 * if we get an event next time through button reading, it will
1133 * remain ahead of last_event. if we don't, they'll end up equaling
1134 * each other.. thus, the scroll count will be reset. */
1135 if(wheel_enabled == false && wheel_events > last_wheel_event)
1136 last_wheel_event++;
1138 #endif
1140 if (TIME_AFTER(*rb->current_tick, next_down_tick)) {
1141 move_down ();
1142 next_down_tick += level_speed(level);
1143 if (TIME_AFTER(*rb->current_tick, next_down_tick))
1144 /* restart time "raster" when we had to wait longer than usual
1145 * (pause, game restart etc) */
1146 next_down_tick = *rb->current_tick + level_speed(level);
1149 if (gameover) {
1150 #if LCD_DEPTH >= 2
1151 rb->lcd_set_foreground (LCD_BLACK);
1152 #endif
1153 rb->splash (HZ * 2, "Game Over");
1154 init_rockblox ();
1155 new_block ();
1158 refresh_board ();
1161 return PLUGIN_OK;
1164 enum plugin_status plugin_start (const struct plugin_api *api, const void *parameter)
1166 int ret;
1168 (void) parameter;
1169 rb = api;
1171 rb->srand (*rb->current_tick);
1173 /* Load HighScore if any */
1174 highscore_init(rb);
1175 highscore_load(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1177 #if LCD_DEPTH > 1
1178 rb->lcd_set_backdrop(NULL);
1179 #endif
1181 #ifdef HAVE_LCD_BITMAP
1182 rb->lcd_setfont (FONT_SYSFIXED);
1183 #else
1184 if (!pgfx_init(rb, 4, 2))
1186 rb->splash(HZ*2, "Old LCD :(");
1187 return PLUGIN_OK;
1189 #endif
1190 /* Turn off backlight timeout */
1191 backlight_force_on(rb); /* backlight control in lib/helper.c */
1193 init_rockblox ();
1194 ret = rockblox_loop ();
1196 #ifdef HAVE_LCD_BITMAP
1197 rb->lcd_setfont (FONT_UI);
1198 #else
1199 pgfx_release();
1200 #endif
1201 /* Save user's HighScore */
1202 highscore_save(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1203 backlight_use_settings(rb); /* backlight control in lib/helper.c */
1205 return ret;