Fix some quotation marks. Thanks to Alexander Levin for pointing it out.
[Rockbox.git] / apps / plugins / rockblox.c
blob82fb758deeca6cb7db2d88e818d8918d60209a63
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 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "plugin.h"
22 #include "highscore.h"
23 #include "playergfx.h"
24 #include "helper.h"
26 PLUGIN_HEADER
28 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
29 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
30 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
32 #define ROCKBLOX_OFF (BUTTON_MENU | BUTTON_SELECT)
33 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
34 #define ROCKBLOX_ROTATE_RIGHT2 (BUTTON_MENU | BUTTON_REL)
35 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
36 #define ROCKBLOX_LEFT BUTTON_LEFT
37 #define ROCKBLOX_RIGHT BUTTON_RIGHT
38 #define ROCKBLOX_DOWN BUTTON_PLAY
39 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_PLAY)
40 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
42 #define SCROLL_WHEEL
44 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
45 (CONFIG_KEYPAD == IRIVER_H300_PAD)
47 #define ROCKBLOX_OFF BUTTON_OFF
48 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
49 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
50 #define ROCKBLOX_DOWN BUTTON_DOWN
51 #define ROCKBLOX_LEFT BUTTON_LEFT
52 #define ROCKBLOX_RIGHT BUTTON_RIGHT
53 #define ROCKBLOX_DROP BUTTON_MODE
54 #define ROCKBLOX_RESTART BUTTON_ON
56 #define ROCKBLOX_RC_OFF BUTTON_RC_STOP
58 #elif CONFIG_KEYPAD == RECORDER_PAD
60 #define ROCKBLOX_OFF BUTTON_OFF
61 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
62 #define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
63 #define ROCKBLOX_DOWN BUTTON_DOWN
64 #define ROCKBLOX_LEFT BUTTON_LEFT
65 #define ROCKBLOX_RIGHT BUTTON_RIGHT
66 #define ROCKBLOX_DROP BUTTON_ON
67 #define ROCKBLOX_RESTART BUTTON_F1
69 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
71 #define ROCKBLOX_OFF BUTTON_OFF
72 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
73 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
74 #define ROCKBLOX_DOWN BUTTON_DOWN
75 #define ROCKBLOX_LEFT BUTTON_LEFT
76 #define ROCKBLOX_RIGHT BUTTON_RIGHT
77 #define ROCKBLOX_DROP BUTTON_ON
78 #define ROCKBLOX_RESTART BUTTON_F1
80 #elif CONFIG_KEYPAD == PLAYER_PAD
82 #define ROCKBLOX_OFF BUTTON_STOP
83 #define ROCKBLOX_ROTATE_RIGHT BUTTON_PLAY
84 #define ROCKBLOX_ROTATE_LEFT (BUTTON_ON|BUTTON_PLAY)
85 #define ROCKBLOX_DOWN BUTTON_MENU
86 #define ROCKBLOX_LEFT BUTTON_LEFT
87 #define ROCKBLOX_RIGHT BUTTON_RIGHT
88 #define ROCKBLOX_DROP_PRE BUTTON_ON
89 #define ROCKBLOX_DROP (BUTTON_ON|BUTTON_REL)
91 #elif CONFIG_KEYPAD == ONDIO_PAD
93 #define ROCKBLOX_OFF BUTTON_OFF
94 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
95 #define ROCKBLOX_ROTATE_LEFT (BUTTON_MENU|BUTTON_UP)
96 #define ROCKBLOX_DOWN BUTTON_DOWN
97 #define ROCKBLOX_LEFT BUTTON_LEFT
98 #define ROCKBLOX_RIGHT BUTTON_RIGHT
99 #define ROCKBLOX_DROP_PRE BUTTON_MENU
100 #define ROCKBLOX_DROP (BUTTON_MENU|BUTTON_REL)
102 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
104 #define ROCKBLOX_OFF BUTTON_POWER
105 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
106 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
107 #define ROCKBLOX_DOWN BUTTON_DOWN
108 #define ROCKBLOX_LEFT BUTTON_LEFT
109 #define ROCKBLOX_RIGHT BUTTON_RIGHT
110 #define ROCKBLOX_DROP BUTTON_REC
111 #define ROCKBLOX_RESTART BUTTON_PLAY
113 #elif CONFIG_KEYPAD == SANSA_E200_PAD
115 #define ROCKBLOX_OFF BUTTON_POWER
116 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
117 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
118 #define ROCKBLOX_DOWN BUTTON_DOWN
119 #define ROCKBLOX_LEFT BUTTON_LEFT
120 #define ROCKBLOX_RIGHT BUTTON_RIGHT
121 #define ROCKBLOX_DROP BUTTON_SELECT
122 #define ROCKBLOX_RESTART BUTTON_REC
124 #elif CONFIG_KEYPAD == SANSA_C200_PAD
126 #define ROCKBLOX_OFF BUTTON_POWER
127 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
128 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_VOL_DOWN
129 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
130 #define ROCKBLOX_DOWN BUTTON_DOWN
131 #define ROCKBLOX_LEFT BUTTON_LEFT
132 #define ROCKBLOX_RIGHT BUTTON_RIGHT
133 #define ROCKBLOX_DROP BUTTON_SELECT
134 #define ROCKBLOX_RESTART BUTTON_REC
136 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
138 #define ROCKBLOX_OFF BUTTON_POWER
139 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_UP
140 #define ROCKBLOX_ROTATE_LEFT BUTTON_REW
141 #define ROCKBLOX_DOWN BUTTON_SCROLL_DOWN
142 #define ROCKBLOX_LEFT BUTTON_LEFT
143 #define ROCKBLOX_RIGHT BUTTON_RIGHT
144 #define ROCKBLOX_DROP BUTTON_FF
145 #define ROCKBLOX_RESTART BUTTON_PLAY
147 #elif CONFIG_KEYPAD == GIGABEAT_PAD
149 #define ROCKBLOX_OFF BUTTON_POWER
150 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
151 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
152 #define ROCKBLOX_ROTATE BUTTON_UP
153 #define ROCKBLOX_DOWN BUTTON_DOWN
154 #define ROCKBLOX_LEFT BUTTON_LEFT
155 #define ROCKBLOX_RIGHT BUTTON_RIGHT
156 #define ROCKBLOX_DROP BUTTON_SELECT
157 #define ROCKBLOX_RESTART BUTTON_A
159 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
161 #define ROCKBLOX_OFF BUTTON_PLAY
162 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
163 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
164 #define ROCKBLOX_DOWN BUTTON_DOWN
165 #define ROCKBLOX_LEFT BUTTON_LEFT
166 #define ROCKBLOX_RIGHT BUTTON_RIGHT
167 #define ROCKBLOX_DROP BUTTON_MODE
168 #define ROCKBLOX_RESTART BUTTON_EQ
170 #elif CONFIG_KEYPAD == MROBE500_PAD
171 #define ROCKBLOX_OFF BUTTON_POWER
172 #define ROCKBLOX_ROTATE_RIGHT BUTTON_RC_VOL_UP
173 #define ROCKBLOX_ROTATE_LEFT BUTTON_RC_VOL_DOWN
174 #define ROCKBLOX_DOWN BUTTON_RC_DOWN
175 #define ROCKBLOX_LEFT BUTTON_LEFT
176 #define ROCKBLOX_RIGHT BUTTON_RIGHT
177 #define ROCKBLOX_DROP BUTTON_RC_HEART
178 #define ROCKBLOX_RESTART BUTTON_RC_MODE
180 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
181 #define ROCKBLOX_OFF BUTTON_BACK
182 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
183 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
184 #define ROCKBLOX_ROTATE BUTTON_UP
185 #define ROCKBLOX_DOWN BUTTON_DOWN
186 #define ROCKBLOX_LEFT BUTTON_LEFT
187 #define ROCKBLOX_RIGHT BUTTON_RIGHT
188 #define ROCKBLOX_DROP BUTTON_SELECT
189 #define ROCKBLOX_RESTART BUTTON_PLAY
191 #elif CONFIG_KEYPAD == MROBE100_PAD
193 #define ROCKBLOX_OFF BUTTON_POWER
194 #define ROCKBLOX_ROTATE_RIGHT BUTTON_MENU
195 #define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
196 #define ROCKBLOX_ROTATE BUTTON_UP
197 #define ROCKBLOX_DOWN BUTTON_DOWN
198 #define ROCKBLOX_LEFT BUTTON_LEFT
199 #define ROCKBLOX_RIGHT BUTTON_RIGHT
200 #define ROCKBLOX_DROP BUTTON_SELECT
201 #define ROCKBLOX_RESTART BUTTON_DISPLAY
203 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
205 #define ROCKBLOX_OFF BUTTON_RC_REC
206 #define ROCKBLOX_ROTATE_RIGHT BUTTON_RC_VOL_DOWN
207 #define ROCKBLOX_ROTATE_LEFT BUTTON_RC_VOL_UP
208 #define ROCKBLOX_DOWN BUTTON_RC_MENU
209 #define ROCKBLOX_LEFT BUTTON_RC_REW
210 #define ROCKBLOX_RIGHT BUTTON_RC_FF
211 #define ROCKBLOX_DROP BUTTON_RC_PLAY
212 #define ROCKBLOX_RESTART BUTTON_RC_MODE
214 #elif CONFIG_KEYPAD == COWOND2_PAD
215 #define ROCKBLOX_OFF BUTTON_POWER
216 #define ROCKBLOX_ROTATE_RIGHT BUTTON_PLUS
217 #define ROCKBLOX_ROTATE_LEFT BUTTON_MINUS
218 #define ROCKBLOX_DOWN BUTTON_DOWN
219 #define ROCKBLOX_LEFT BUTTON_LEFT
220 #define ROCKBLOX_RIGHT BUTTON_RIGHT
221 #define ROCKBLOX_DROP BUTTON_SELECT
222 #define ROCKBLOX_RESTART BUTTON_MENU
224 #else
225 #error No keymap defined!
226 #endif
228 #define BLOCKS_NUM 7
229 #define EMPTY_BLOCK 7
231 #define BOARD_WIDTH 10
233 #ifdef HAVE_LCD_BITMAP
235 #define BOARD_HEIGHT 20
237 #if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
239 #define BLOCK_WIDTH 30
240 #define BLOCK_HEIGHT 30
241 #define BOARD_X 14
242 #define BOARD_Y 2
243 #define PREVIEW_X 342
244 #define PREVIEW_Y 482
245 #define LABEL_X 344
246 #define SCORE_Y 58
247 #define LEVEL_Y 142
248 #define LINES_Y 218
249 #define HIGH_LABEL_X 344
250 #define HIGH_SCORE_Y 326
251 #define HIGH_LEVEL_Y 344
253 #elif (LCD_WIDTH == 480) && (LCD_HEIGHT == 640)
255 #define BLOCK_WIDTH 30
256 #define BLOCK_HEIGHT 30
257 #define BOARD_X 14
258 #define BOARD_Y 2
259 #define PREVIEW_X 342
260 #define PREVIEW_Y 482
261 #define LABEL_X 344
262 #define SCORE_Y 58
263 #define LEVEL_Y 142
264 #define LINES_Y 218
265 #define HIGH_LABEL_X 344
266 #define HIGH_SCORE_Y 326
267 #define HIGH_LEVEL_Y 344
269 #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
271 #define BLOCK_WIDTH 12
272 #define BLOCK_HEIGHT 12
273 #define BOARD_X 86
274 #define BOARD_Y 0
275 #define PREVIEW_X 12
276 #define PREVIEW_Y 11
277 #define LABEL_X 242
278 #define SCORE_Y 25
279 #define LEVEL_Y 70
280 #define LINES_Y 105
282 #elif (LCD_WIDTH == 240) && (LCD_HEIGHT == 320)
284 #define BLOCK_WIDTH 15
285 #define BLOCK_HEIGHT 15
286 #define BOARD_X 7
287 #define BOARD_Y 1
288 #define PREVIEW_X 171
289 #define PREVIEW_Y 241
290 #define LABEL_X 172
291 #define SCORE_Y 29
292 #define LEVEL_Y 71
293 #define LINES_Y 109
294 #define HIGH_LABEL_X 172
295 #define HIGH_SCORE_Y 163
296 #define HIGH_LEVEL_Y 172
298 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
300 #define BLOCK_WIDTH 8
301 #define BLOCK_HEIGHT 8
302 #define BOARD_X 27
303 #define BOARD_Y 5
304 #define PREVIEW_X 158
305 #define PREVIEW_Y 130
306 #define LABEL_X 147
307 #define SCORE_Y 20
308 #define LEVEL_Y 65
309 #define LINES_Y 100
311 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
313 #define BLOCK_WIDTH 6
314 #define BLOCK_HEIGHT 6
315 #define BOARD_X 25
316 #define BOARD_Y 1
317 #define PREVIEW_X 126
318 #define PREVIEW_Y 102
319 #define LABEL_X 112
320 #define SCORE_Y 17
321 #define LEVEL_Y 49
322 #define LINES_Y 81
324 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
326 #define BLOCK_WIDTH 10
327 #define BLOCK_HEIGHT 10
328 #define BOARD_X 6
329 #define BOARD_Y 10
330 #define PREVIEW_X 124
331 #define PREVIEW_Y 167
332 #define LABEL_X 117
333 #define SCORE_Y 24
334 #define LEVEL_Y 65
335 #define LINES_Y 103
336 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
338 #define BLOCK_WIDTH 6
339 #define BLOCK_HEIGHT 6
340 #define BOARD_X 22
341 #define BOARD_Y 3
342 #define PREVIEW_X 114
343 #define PREVIEW_Y 100
344 #define LABEL_X 101
345 #define SCORE_Y 17
346 #define LEVEL_Y 49
347 #define LINES_Y 82
349 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
351 #define BLOCK_WIDTH 5
352 #define BLOCK_HEIGHT 5
353 #define BOARD_X 14
354 #define BOARD_Y 0
355 #define PREVIEW_X 98
356 #define PREVIEW_Y 88
357 #define LABEL_X 80
358 #define SCORE_Y 15
359 #define LEVEL_Y 45
360 #define LINES_Y 74
362 #elif (LCD_WIDTH == 132) && (LCD_HEIGHT == 80)
364 #define BLOCK_WIDTH 4
365 #define BLOCK_HEIGHT 4
366 #define BOARD_X 10
367 #define BOARD_Y 0
368 #define PREVIEW_X 89
369 #define PREVIEW_Y 61
370 #define LABEL_X 78
371 #define SCORE_Y 10
372 #define LEVEL_Y 30
373 #define LINES_Y 50
375 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
377 #define BLOCK_WIDTH 6
378 #define BLOCK_HEIGHT 6
379 #define BOARD_X 4
380 #define BOARD_Y 3
381 #define PREVIEW_X 84
382 #define PREVIEW_Y 100
383 #define LABEL_X 71
384 #define SCORE_Y 17
385 #define LEVEL_Y 49
386 #define LINES_Y 82
388 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 96)
390 #define BLOCK_WIDTH 4
391 #define BLOCK_HEIGHT 4
392 #define BOARD_X 14
393 #define BOARD_Y 2
394 #define PREVIEW_X 89
395 #define PREVIEW_Y 76
396 #define LABEL_X 70
397 #define SCORE_Y 14
398 #define LEVEL_Y 39
399 #define LINES_Y 64
401 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 64)
403 #define BLOCK_WIDTH 3
404 #define BLOCK_HEIGHT 3
405 #define BOARD_X 9
406 #define BOARD_Y 3
407 #define PREVIEW_X 53
408 #define PREVIEW_Y 5
409 #define LABEL_X 70
410 #define SCORE_Y 32
411 #define LEVEL_Y 13
412 #define LINES_Y 51
414 #elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
416 #define BLOCK_WIDTH 4
417 #define BLOCK_HEIGHT 3
418 #define BOARD_X 9
419 #define BOARD_Y 3
420 #define PREVIEW_X 59
421 #define PREVIEW_Y 5
422 #define LABEL_X 59
423 #define SCORE_Y 32
424 #define LEVEL_Y 13
425 #define LEVEL_X 78
426 #define LINES_Y 51
428 #endif
430 #ifndef LEVEL_X
431 #define LEVEL_X LABEL_X
432 #endif
434 #ifndef LINES_X
435 #define LINES_X LABEL_X
436 #endif
438 #define MYLCD(fn) rb->lcd_ ## fn
440 extern const fb_data rockblox_background[];
442 #else /* HAVE_LCD_CHARCELLS */
444 #define BOARD_HEIGHT 14
446 #define BLOCK_WIDTH 1
447 #define BLOCK_HEIGHT 1
448 #define BOARD_X 5
449 #define BOARD_Y 0
450 #define PREVIEW_X 15
451 #define PREVIEW_Y 1
453 #define MYLCD(fn) pgfx_ ## fn
455 #endif
457 /* <<Explanation on Rockblox shapes>>
460 %% - O has 1 orientation
462 %% %
463 %% %% - Z has 2 orientations
466 %% %
467 %% %% - S has 2 orientations
471 % %%%% - I has 2 orientations
474 % %%
475 % % % %%% - L has 4 orientations
476 %% %%% % %
478 % %%s
479 % % % %%% - J has 4 orientations
480 %% %%% % %
482 % % %%%
483 %% % %% % - T has 4 orientations
484 % %%% %
488 /* must have variable */
489 static struct plugin_api *rb;
491 static bool gameover = false;
492 /* c=current f=figure o=orientation n=next */
493 static int lines = 0, level = 0, score = 0, cx, cy, cf, co, nf;
494 static short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */
496 #ifdef SCROLL_WHEEL
497 int wheel_events = 0, last_wheel_event = 0;
498 bool wheel_enabled = false;
499 #endif
501 static const short scoring[4] = { /* scoring for each number of lines */
502 #if BOARD_HEIGHT == 20
503 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
504 #elif BOARD_HEIGHT == 14 /* Player special values */
505 60 /* single */ , 150 /* double */ , 500 /* triple */ , 2000 /* rockblox */
506 #endif
509 struct figure
511 #if LCD_DEPTH >= 2
512 unsigned short color[3]; /* color of figure (light,middle,shadow) */
513 #endif
514 unsigned short max_or; /* max orientations */
515 signed short shapeX[4], shapeY[4]; /* implementation of figures */
518 /* array of figures */
519 figures[BLOCKS_NUM] = {
520 /* O */
522 #if LCD_DEPTH >= 16
523 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
524 LCD_RGBPACK(0,153,153)},
525 #elif LCD_DEPTH == 2
526 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
527 #endif
529 {-1, 0, -1, 0},
530 {0, 0, 1, 1}
532 /* I */
534 #if LCD_DEPTH >= 16
535 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
536 LCD_RGBPACK (153, 0, 0)},
537 #elif LCD_DEPTH == 2
538 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
539 #endif
541 {-2, -1, 0, 1},
542 {0, 0, 0, 0}
544 /* 'Z' */
546 #if LCD_DEPTH >= 16
547 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
548 LCD_RGBPACK (0, 153, 0)},
549 #elif LCD_DEPTH == 2
550 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
551 #endif
553 {0, 1, -1, 0},
554 {0, 0, 1, 1}
556 /* 'S' */
558 #if LCD_DEPTH >= 16
559 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
560 LCD_RGBPACK (0, 0, 153)},
561 #elif LCD_DEPTH == 2
562 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
563 #endif
565 {-1, 0, 0, 1},
566 {0, 0, 1, 1}
568 /* 'L' */
570 #if LCD_DEPTH >= 16
571 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
572 LCD_RGBPACK (153, 153, 0)},
573 #elif LCD_DEPTH == 2
574 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
575 #endif
577 {-1, 0, 1, 1},
578 {0, 0, 0, 1}
580 /* 'J' */
582 #if LCD_DEPTH >= 16
583 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
584 LCD_RGBPACK (153, 0, 153)},
585 #elif LCD_DEPTH == 2
586 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
587 #endif
589 {-1, 0, 1, -1},
590 {0, 0, 0, 1}
592 /* 'T' */
594 #if LCD_DEPTH >= 16
595 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
596 LCD_RGBPACK (85, 85, 85)},
597 #elif LCD_DEPTH == 2
598 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
599 #endif
601 {-1, 0, 1, 0},
602 {0, 0, 0, 1}
606 /* Rockbox File System only supports full filenames inc dir */
607 #define HIGH_SCORE PLUGIN_GAMES_DIR "/rockblox.score"
608 #define MAX_HIGH_SCORES 5
609 /* Default High Scores... */
610 struct highscore Highest[MAX_HIGH_SCORES];
612 /* get random number from (0) to (range-1) */
613 static int t_rand (int range)
615 return rb->rand () % range;
618 /* init the board array to have no blocks */
619 static void init_board (void)
621 int i, j;
622 for (i = 0; i < BOARD_WIDTH; i++)
623 for (j = 0; j < BOARD_HEIGHT; j++)
624 board[j][i] = EMPTY_BLOCK;
627 /* show the score, level and lines */
628 static void show_details (void)
630 char str[25]; /* for strings */
632 #ifdef HAVE_LCD_BITMAP
633 #if LCD_DEPTH >= 2
634 rb->lcd_set_foreground (LCD_BLACK);
635 rb->lcd_set_background (LCD_WHITE);
636 #endif
637 rb->snprintf (str, sizeof (str), "%d", score);
638 rb->lcd_putsxy (LABEL_X, SCORE_Y, str);
639 rb->snprintf (str, sizeof (str), "%d", level);
640 rb->lcd_putsxy (LEVEL_X, LEVEL_Y, str);
641 rb->snprintf (str, sizeof (str), "%d", lines);
642 rb->lcd_putsxy (LINES_X, LINES_Y, str);
643 #else /* HAVE_LCD_CHARCELLS */
644 rb->snprintf (str, sizeof (str), "L%d/%d", level, lines);
645 rb->lcd_puts (5, 0, str);
646 rb->snprintf (str, sizeof (str), "S%d", score);
647 rb->lcd_puts (5, 1, str);
648 #endif
651 #ifdef HIGH_SCORE_Y
652 static void show_highscores (void)
654 int i;
655 char str[25]; /* for strings */
657 for (i = MAX_HIGH_SCORES-1; i>=0; i--)
659 rb->snprintf (str, sizeof (str), "%06d L%1d", Highest[i].score, Highest[i].level);
660 rb->lcd_putsxy (HIGH_LABEL_X, HIGH_SCORE_Y + (10 * ((MAX_HIGH_SCORES-1) - i)), str);
663 #endif
665 static void init_rockblox (void)
667 highscore_update(score, level, Highest, MAX_HIGH_SCORES);
669 level = 1;
670 lines = 0;
671 score = 0;
672 gameover = false;
673 nf = t_rand (BLOCKS_NUM);
674 init_board ();
675 #ifdef HAVE_LCD_BITMAP
676 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
677 #else /* HAVE_LCD_CHARCELLS */
678 pgfx_display (0, 0);
679 pgfx_display_block (3, 0, 3, 1);
680 pgfx_display_block (4, 0, 3, 0);
681 pgfx_clear_display();
682 pgfx_fillrect (3, 0, 2, 14);
683 pgfx_fillrect (15, 7, 2, 7);
684 pgfx_update();
685 #endif
686 show_details ();
687 #ifdef HIGH_SCORE_Y
688 show_highscores ();
689 #endif
692 static inline int level_speed(int level)
694 #if BOARD_HEIGHT == 20
695 return (5*HZ) / (level + 9);
696 #elif BOARD_HEIGHT == 14
697 return (7*HZ) / (level + 9);
698 #endif
701 static int getRelativeX (int figure, int square, int orientation)
703 switch (orientation) {
704 case 0:
705 return figures[figure].shapeX[square];
706 case 1:
707 return figures[figure].shapeY[square];
708 case 2:
709 return -figures[figure].shapeX[square];
710 case 3:
711 return -figures[figure].shapeY[square];
712 default:
713 return 0;
717 static int getRelativeY (int figure, int square, int orientation)
719 switch (orientation) {
720 case 0:
721 return figures[figure].shapeY[square];
722 case 1:
723 return -figures[figure].shapeX[square];
724 case 2:
725 return -figures[figure].shapeY[square];
726 case 3:
727 return figures[figure].shapeX[square];
728 default:
729 return 0;
733 /* redraw the while board on the screen */
734 static void refresh_board (void)
736 int i, j, x, y, block;
738 #if LCD_DEPTH >= 2
739 rb->lcd_set_foreground (LCD_BLACK);
740 #elif LCD_DEPTH == 1
741 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
742 #endif
744 MYLCD(fillrect) (BOARD_X, BOARD_Y, BOARD_WIDTH * BLOCK_WIDTH,
745 BOARD_HEIGHT * BLOCK_HEIGHT);
747 #if LCD_DEPTH == 1
748 MYLCD(set_drawmode) (DRMODE_SOLID);
749 #endif
751 for (i = 0; i < BOARD_WIDTH; i++)
752 for (j = 0; j < BOARD_HEIGHT; j++) {
753 block = board[j][i];
754 if (block != EMPTY_BLOCK) {
755 #ifdef HAVE_LCD_BITMAP
756 #if LCD_DEPTH >= 2
757 /* middle drawing */
758 rb->lcd_set_foreground (figures[block].color[1]);
759 #endif
760 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
761 BOARD_Y + j * BLOCK_HEIGHT,
762 BLOCK_WIDTH, BLOCK_HEIGHT);
763 #if LCD_DEPTH >= 2
764 /* light drawing */
765 rb->lcd_set_foreground (figures[block].color[0]);
766 #endif
767 rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH,
768 BOARD_Y + j * BLOCK_HEIGHT,
769 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2);
770 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH,
771 BOARD_X + (i + 1) * BLOCK_WIDTH - 2,
772 BOARD_Y + j * BLOCK_HEIGHT);
773 #if LCD_DEPTH >= 2
774 /* shadow drawing */
775 rb->lcd_set_foreground (figures[block].color[2]);
776 #endif
777 rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
778 BOARD_Y + j * BLOCK_HEIGHT + 1,
779 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
780 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1,
781 BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
782 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
783 #else /* HAVE_LCD_CHARCELLS */
784 pgfx_drawpixel (BOARD_X + i, BOARD_Y + j);
785 #endif
789 for (i = 0; i < 4; i++) {
790 x = getRelativeX (cf, i, co) + cx;
791 y = getRelativeY (cf, i, co) + cy;
792 #ifdef HAVE_LCD_BITMAP
793 #if LCD_DEPTH >= 2
794 rb->lcd_set_foreground (figures[cf].color[1]); /* middle drawing */
795 #endif
796 rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH,
797 BOARD_Y + y * BLOCK_HEIGHT,
798 BLOCK_WIDTH, BLOCK_HEIGHT);
799 #if LCD_DEPTH >= 2
800 rb->lcd_set_foreground (figures[cf].color[0]); /* light drawing */
801 #endif
802 rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT,
803 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2);
804 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH,
805 BOARD_X + (x + 1) * BLOCK_WIDTH - 2,
806 BOARD_Y + y * BLOCK_HEIGHT);
807 #if LCD_DEPTH >= 2
808 rb->lcd_set_foreground (figures[cf].color[2]); /* shadow drawing */
809 #endif
810 rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
811 BOARD_Y + y * BLOCK_HEIGHT + 1,
812 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
813 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1,
814 BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
815 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
816 #else /* HAVE_LCD_CHARCELLS */
817 pgfx_drawpixel (BOARD_X + x, BOARD_Y + y);
818 #endif
820 MYLCD(update) ();
823 static bool canMoveTo (int x, int y, int newOrientation)
825 int i, rx, ry;
826 for (i = 0; i < 4; i++) {
827 ry = getRelativeY (cf, i, newOrientation) + y;
828 rx = getRelativeX (cf, i, newOrientation) + x;
829 if ((rx < 0 || rx >= BOARD_WIDTH) ||
830 (ry < 0 || ry >= BOARD_HEIGHT) || (board[ry][rx] != EMPTY_BLOCK))
831 return false;
833 return true;
836 /* draws the preview of next block in the preview window */
837 static void draw_next_block (void)
839 int i, rx, ry;
840 /* clear preview window first */
841 #if LCD_DEPTH >= 2
842 rb->lcd_set_foreground (LCD_BLACK);
843 #elif LCD_DEPTH == 1
844 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
845 #endif
847 /* 4x4 */
848 MYLCD(fillrect) (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4);
850 #if LCD_DEPTH == 1
851 MYLCD(set_drawmode) (DRMODE_SOLID);
852 #endif
854 /* draw the lightgray rectangles */
855 #if LCD_DEPTH >= 16
856 rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
857 #elif LCD_DEPTH == 2
858 rb->lcd_set_foreground (LCD_DARKGRAY);
859 #endif
861 #if LCD_DEPTH >= 2
862 for (rx = 0; rx < 4; rx++)
863 for (ry = 0; ry < 4; ry++)
864 rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH,
865 PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH,
866 BLOCK_HEIGHT);
867 #endif
869 /* draw the figure */
870 for (i = 0; i < 4; i++) {
871 rx = getRelativeX (nf, i, 0) + 2;
872 ry = getRelativeY (nf, i, 0) + 2;
873 #ifdef HAVE_LCD_BITMAP
874 #if LCD_DEPTH >= 2
875 rb->lcd_set_foreground (figures[nf].color[1]); /* middle drawing */
876 #endif
877 rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH,
878 PREVIEW_Y + ry * BLOCK_HEIGHT,
879 BLOCK_WIDTH, BLOCK_HEIGHT);
880 #if LCD_DEPTH >= 2
881 rb->lcd_set_foreground (figures[nf].color[0]); /* light drawing */
882 #endif
883 rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH,
884 PREVIEW_Y + ry * BLOCK_HEIGHT,
885 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2);
886 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH,
887 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2,
888 PREVIEW_Y + ry * BLOCK_HEIGHT);
889 #if LCD_DEPTH >= 2
890 rb->lcd_set_foreground (figures[nf].color[2]); /* shadow drawing */
891 #endif
892 rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
893 PREVIEW_Y + ry * BLOCK_HEIGHT + 1,
894 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
895 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1,
896 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
897 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
898 #else /* HAVE_LCD_CHARCELLS */
899 pgfx_drawpixel (PREVIEW_X + rx, PREVIEW_Y + ry);
900 #endif
905 /* move the block to a relative location */
906 static void move_block (int x, int y, int o)
908 if (canMoveTo (cx + x, cy + y, o)) {
909 cy += y;
910 cx += x;
911 co = o;
915 /* try to add a new block to play with (return true if gameover) */
916 static void new_block (void)
918 cy = 1;
919 cx = 5;
920 cf = nf;
921 co = 0; /* start at the same orientation all time */
922 nf = t_rand (BLOCKS_NUM);
923 gameover = !canMoveTo (cx, cy, co);
925 draw_next_block ();
929 /* check for filled lines and do what necessary */
930 static int check_lines (void)
932 int i, j, y;
933 int rockblox = 0;
935 for (j = 0; j < BOARD_HEIGHT; j++) {
936 for (i = 0; ((i < BOARD_WIDTH) && (board[j][i] != EMPTY_BLOCK)); i++);
937 if (i == BOARD_WIDTH) { /* woo hoo, we have a line */
938 rockblox++;
939 for (y = j; y > 0; y--)
940 for (i = 0; i < BOARD_WIDTH; i++)
941 board[y][i] = board[y - 1][i]; /* fall line */
945 return rockblox;
948 /* moves down the figure and returns true if gameover */
949 static void move_down (void)
951 int l, i, rx, ry;
953 if (!canMoveTo (cx, cy + 1, co)) {
954 /* save figure to board */
955 for (i = 0; i < 4; i++) {
956 rx = getRelativeX (cf, i, co) + cx;
957 ry = getRelativeY (cf, i, co) + cy;
958 board[ry][rx] = cf;
960 /* check if formed some lines */
961 l = check_lines ();
962 if (l) {
963 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
964 score += scoring[l - 1] * level;
965 lines += l;
966 level = (int) lines / 10 + 1;
969 /* show details */
970 show_details ();
972 /* generate a new figure */
973 new_block ();
974 } else
975 move_block (0, 1, co);
978 static int rockblox_loop (void)
980 int button;
981 int lastbutton = BUTTON_NONE;
982 long next_down_tick = *rb->current_tick + level_speed(level);
984 new_block ();
986 while (1) {
987 #ifdef HAS_BUTTON_HOLD
988 if (rb->button_hold ()) {
989 /* Turn on backlight timeout (revert to settings) */
990 backlight_use_settings(rb); /* backlight control in lib/helper.c */
991 rb->splash(0, "Paused");
992 while (rb->button_hold ())
993 rb->sleep(HZ/10);
995 /* Turn off backlight timeout */
996 backlight_force_on(rb); /* backlight control in lib/helper.c */
998 /* get rid of the splash text */
999 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
1000 show_details ();
1001 #ifdef HIGH_SCORE_Y
1002 show_highscores ();
1003 #endif
1004 draw_next_block ();
1005 refresh_board ();
1007 #endif
1009 button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1));
1010 switch (button) {
1011 #ifdef ROCKBLOX_RC_OFF
1012 case ROCKBLOX_RC_OFF:
1013 #endif
1014 case ROCKBLOX_OFF:
1015 return PLUGIN_OK;
1017 #if defined(ROCKBLOX_ROTATE)
1018 case ROCKBLOX_ROTATE:
1019 #endif
1020 case ROCKBLOX_ROTATE_RIGHT:
1021 case ROCKBLOX_ROTATE_RIGHT | BUTTON_REPEAT:
1022 #ifdef SCROLL_WHEEL
1023 /* if the wheel is disabled, add an event to the stack. */
1024 if(wheel_enabled == false)
1025 wheel_events++;
1027 /* if it's enabled, go ahead and rotate.. */
1028 if(wheel_enabled)
1029 #endif
1030 move_block (0, 0, (co + 1) % figures[cf].max_or);
1031 break;
1033 case ROCKBLOX_ROTATE_LEFT:
1034 case ROCKBLOX_ROTATE_LEFT | BUTTON_REPEAT:
1035 #ifdef SCROLL_WHEEL
1036 if(wheel_enabled == false)
1037 wheel_events++;
1039 if(wheel_enabled)
1040 #endif
1041 move_block (0, 0,
1042 (co + figures[cf].max_or -
1043 1) % figures[cf].max_or);
1044 break;
1046 #ifdef ROCKBLOX_ROTATE_RIGHT2
1047 case ROCKBLOX_ROTATE_RIGHT2:
1048 move_block (0, 0, (co + 1) % figures[cf].max_or);
1049 break;
1050 #endif
1052 case ROCKBLOX_DOWN:
1053 case ROCKBLOX_DOWN | BUTTON_REPEAT:
1054 move_block (0, 1, co);
1055 break;
1057 case ROCKBLOX_RIGHT:
1058 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
1059 move_block (1, 0, co);
1060 break;
1062 case ROCKBLOX_LEFT:
1063 case ROCKBLOX_LEFT | BUTTON_REPEAT:
1064 move_block (-1, 0, co);
1065 break;
1067 case ROCKBLOX_DROP:
1068 #ifdef ROCKBLOX_DROP_PRE
1069 if (lastbutton != ROCKBLOX_DROP_PRE)
1070 break;
1071 #endif
1072 while (canMoveTo (cx, cy + 1, co))
1073 move_block (0, 1, co);
1074 break;
1075 #ifdef ROCKBLOX_RESTART
1076 case ROCKBLOX_RESTART:
1077 rb->splash (HZ * 1, "Restarting...");
1078 init_rockblox ();
1079 new_block ();
1080 break;
1081 #endif
1083 default:
1084 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
1085 return PLUGIN_USB_CONNECTED;
1086 break;
1088 if (button != BUTTON_NONE)
1089 lastbutton = button;
1091 #ifdef SCROLL_WHEEL
1092 /* check if we should enable the scroll wheel, if events
1093 * begin to stack up... */
1094 if(wheel_enabled == false)
1096 /* stopped rotating the wheel, reset the count */
1097 if(wheel_events == last_wheel_event)
1099 last_wheel_event = 0;
1100 wheel_events = 0;
1102 /* rotated the wheel a while constantly, enable it. */
1103 else if(wheel_events > 3)
1105 wheel_enabled = true;
1108 /* this evens out the last event and the "current" event.
1109 * if we get an event next time through button reading, it will
1110 * remain ahead of last_event. if we don't, they'll end up equaling
1111 * each other.. thus, the scroll count will be reset. */
1112 if(wheel_enabled == false && wheel_events > last_wheel_event)
1113 last_wheel_event++;
1115 #endif
1117 if (TIME_AFTER(*rb->current_tick, next_down_tick)) {
1118 move_down ();
1119 next_down_tick += level_speed(level);
1120 if (TIME_AFTER(*rb->current_tick, next_down_tick))
1121 /* restart time "raster" when we had to wait longer than usual
1122 * (pause, game restart etc) */
1123 next_down_tick = *rb->current_tick + level_speed(level);
1126 if (gameover) {
1127 #if LCD_DEPTH >= 2
1128 rb->lcd_set_foreground (LCD_BLACK);
1129 #endif
1130 rb->splash (HZ * 2, "Game Over");
1131 init_rockblox ();
1132 new_block ();
1135 refresh_board ();
1138 return PLUGIN_OK;
1141 enum plugin_status plugin_start (struct plugin_api *api, void *parameter)
1143 int ret;
1145 (void) parameter;
1146 rb = api;
1148 rb->srand (*rb->current_tick);
1150 /* Load HighScore if any */
1151 highscore_init(rb);
1152 highscore_load(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1154 #if LCD_DEPTH > 1
1155 rb->lcd_set_backdrop(NULL);
1156 #endif
1158 #ifdef HAVE_LCD_BITMAP
1159 rb->lcd_setfont (FONT_SYSFIXED);
1160 #else
1161 if (!pgfx_init(rb, 4, 2))
1163 rb->splash(HZ*2, "Old LCD :(");
1164 return PLUGIN_OK;
1166 #endif
1167 /* Turn off backlight timeout */
1168 backlight_force_on(rb); /* backlight control in lib/helper.c */
1170 init_rockblox ();
1171 ret = rockblox_loop ();
1173 #ifdef HAVE_LCD_BITMAP
1174 rb->lcd_setfont (FONT_UI);
1175 #else
1176 pgfx_release();
1177 #endif
1178 /* Save user's HighScore */
1179 highscore_save(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1180 backlight_use_settings(rb); /* backlight control in lib/helper.c */
1182 return ret;