Add platform file for Ipod 1G / 2G. Now only the front image is missing for building...
[Rockbox.git] / apps / plugins / rockblox.c
blobe66d24256b290e113e2533c105c1156b123e87c9
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"
25 PLUGIN_HEADER
27 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
28 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
29 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
31 #define ROCKBLOX_OFF (BUTTON_MENU | BUTTON_SELECT)
32 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
33 #define ROCKBLOX_ROTATE_RIGHT2 (BUTTON_MENU | BUTTON_REL)
34 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
35 #define ROCKBLOX_LEFT BUTTON_LEFT
36 #define ROCKBLOX_RIGHT BUTTON_RIGHT
37 #define ROCKBLOX_DOWN BUTTON_PLAY
38 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_PLAY)
39 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
41 #define SCROLL_WHEEL
43 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
44 (CONFIG_KEYPAD == IRIVER_H300_PAD)
46 #define ROCKBLOX_OFF BUTTON_OFF
47 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
48 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
49 #define ROCKBLOX_DOWN BUTTON_DOWN
50 #define ROCKBLOX_LEFT BUTTON_LEFT
51 #define ROCKBLOX_RIGHT BUTTON_RIGHT
52 #define ROCKBLOX_DROP BUTTON_MODE
53 #define ROCKBLOX_RESTART BUTTON_ON
55 #define ROCKBLOX_RC_OFF BUTTON_RC_STOP
57 #elif CONFIG_KEYPAD == RECORDER_PAD
59 #define ROCKBLOX_OFF BUTTON_OFF
60 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
61 #define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
62 #define ROCKBLOX_DOWN BUTTON_DOWN
63 #define ROCKBLOX_LEFT BUTTON_LEFT
64 #define ROCKBLOX_RIGHT BUTTON_RIGHT
65 #define ROCKBLOX_DROP BUTTON_ON
66 #define ROCKBLOX_RESTART BUTTON_F1
68 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
70 #define ROCKBLOX_OFF BUTTON_OFF
71 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
72 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
73 #define ROCKBLOX_DOWN BUTTON_DOWN
74 #define ROCKBLOX_LEFT BUTTON_LEFT
75 #define ROCKBLOX_RIGHT BUTTON_RIGHT
76 #define ROCKBLOX_DROP BUTTON_ON
77 #define ROCKBLOX_RESTART BUTTON_F1
79 #elif CONFIG_KEYPAD == PLAYER_PAD
81 #define ROCKBLOX_OFF BUTTON_STOP
82 #define ROCKBLOX_ROTATE_RIGHT BUTTON_PLAY
83 #define ROCKBLOX_ROTATE_LEFT (BUTTON_ON|BUTTON_PLAY)
84 #define ROCKBLOX_DOWN BUTTON_MENU
85 #define ROCKBLOX_LEFT BUTTON_LEFT
86 #define ROCKBLOX_RIGHT BUTTON_RIGHT
87 #define ROCKBLOX_DROP_PRE BUTTON_ON
88 #define ROCKBLOX_DROP (BUTTON_ON|BUTTON_REL)
90 #elif CONFIG_KEYPAD == ONDIO_PAD
92 #define ROCKBLOX_OFF BUTTON_OFF
93 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
94 #define ROCKBLOX_ROTATE_LEFT (BUTTON_MENU|BUTTON_UP)
95 #define ROCKBLOX_DOWN BUTTON_DOWN
96 #define ROCKBLOX_LEFT BUTTON_LEFT
97 #define ROCKBLOX_RIGHT BUTTON_RIGHT
98 #define ROCKBLOX_DROP_PRE BUTTON_MENU
99 #define ROCKBLOX_DROP (BUTTON_MENU|BUTTON_REL)
101 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
103 #define ROCKBLOX_OFF BUTTON_POWER
104 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
105 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
106 #define ROCKBLOX_DOWN BUTTON_DOWN
107 #define ROCKBLOX_LEFT BUTTON_LEFT
108 #define ROCKBLOX_RIGHT BUTTON_RIGHT
109 #define ROCKBLOX_DROP BUTTON_REC
110 #define ROCKBLOX_RESTART BUTTON_PLAY
112 #elif CONFIG_KEYPAD == SANSA_E200_PAD
114 #define ROCKBLOX_OFF BUTTON_POWER
115 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_UP
116 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_DOWN
117 #define ROCKBLOX_DOWN BUTTON_DOWN
118 #define ROCKBLOX_LEFT BUTTON_LEFT
119 #define ROCKBLOX_RIGHT BUTTON_RIGHT
120 #define ROCKBLOX_DROP BUTTON_SELECT
121 #define ROCKBLOX_RESTART BUTTON_REC
123 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
125 #define ROCKBLOX_OFF BUTTON_POWER
126 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_UP
127 #define ROCKBLOX_ROTATE_LEFT BUTTON_REW
128 #define ROCKBLOX_DOWN BUTTON_SCROLL_DOWN
129 #define ROCKBLOX_LEFT BUTTON_LEFT
130 #define ROCKBLOX_RIGHT BUTTON_RIGHT
131 #define ROCKBLOX_DROP BUTTON_FF
132 #define ROCKBLOX_RESTART BUTTON_PLAY
134 #elif CONFIG_KEYPAD == GIGABEAT_PAD
136 #define ROCKBLOX_OFF BUTTON_POWER
137 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
138 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
139 #define ROCKBLOX_ROTATE BUTTON_UP
140 #define ROCKBLOX_DOWN BUTTON_DOWN
141 #define ROCKBLOX_LEFT BUTTON_LEFT
142 #define ROCKBLOX_RIGHT BUTTON_RIGHT
143 #define ROCKBLOX_DROP BUTTON_SELECT
144 #define ROCKBLOX_RESTART BUTTON_A
146 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
148 #define ROCKBLOX_OFF BUTTON_PLAY
149 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
150 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
151 #define ROCKBLOX_DOWN BUTTON_DOWN
152 #define ROCKBLOX_LEFT BUTTON_LEFT
153 #define ROCKBLOX_RIGHT BUTTON_RIGHT
154 #define ROCKBLOX_DROP BUTTON_MODE
155 #define ROCKBLOX_RESTART BUTTON_EQ
157 #endif
159 #define BLOCKS_NUM 7
160 #define EMPTY_BLOCK 7
162 #define BOARD_WIDTH 10
164 #ifdef HAVE_LCD_BITMAP
166 #define BOARD_HEIGHT 20
168 #if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
170 #define BLOCK_WIDTH 12
171 #define BLOCK_HEIGHT 12
172 #define BOARD_X 86
173 #define BOARD_Y 0
174 #define PREVIEW_X 12
175 #define PREVIEW_Y 11
176 #define LABEL_X 242
177 #define SCORE_Y 25
178 #define LEVEL_Y 70
179 #define LINES_Y 105
181 #elif (LCD_WIDTH == 240) && (LCD_HEIGHT == 320)
183 #define BLOCK_WIDTH 15
184 #define BLOCK_HEIGHT 15
185 #define BOARD_X 7
186 #define BOARD_Y 1
187 #define PREVIEW_X 171
188 #define PREVIEW_Y 241
189 #define LABEL_X 172
190 #define SCORE_Y 29
191 #define LEVEL_Y 71
192 #define LINES_Y 109
193 #define HIGH_LABEL_X 172
194 #define HIGH_SCORE_Y 163
195 #define HIGH_LEVEL_Y 172
197 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
199 #define BLOCK_WIDTH 8
200 #define BLOCK_HEIGHT 8
201 #define BOARD_X 27
202 #define BOARD_Y 5
203 #define PREVIEW_X 158
204 #define PREVIEW_Y 130
205 #define LABEL_X 147
206 #define SCORE_Y 20
207 #define LEVEL_Y 65
208 #define LINES_Y 100
210 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
212 #define BLOCK_WIDTH 6
213 #define BLOCK_HEIGHT 6
214 #define BOARD_X 25
215 #define BOARD_Y 1
216 #define PREVIEW_X 126
217 #define PREVIEW_Y 102
218 #define LABEL_X 112
219 #define SCORE_Y 17
220 #define LEVEL_Y 49
221 #define LINES_Y 81
223 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
225 #define BLOCK_WIDTH 10
226 #define BLOCK_HEIGHT 10
227 #define BOARD_X 6
228 #define BOARD_Y 10
229 #define PREVIEW_X 124
230 #define PREVIEW_Y 167
231 #define LABEL_X 117
232 #define SCORE_Y 24
233 #define LEVEL_Y 65
234 #define LINES_Y 103
235 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
237 #define BLOCK_WIDTH 6
238 #define BLOCK_HEIGHT 6
239 #define BOARD_X 22
240 #define BOARD_Y 3
241 #define PREVIEW_X 114
242 #define PREVIEW_Y 100
243 #define LABEL_X 101
244 #define SCORE_Y 17
245 #define LEVEL_Y 49
246 #define LINES_Y 82
248 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
250 #define BLOCK_WIDTH 6
251 #define BLOCK_HEIGHT 6
252 #define BOARD_X 4
253 #define BOARD_Y 3
254 #define PREVIEW_X 84
255 #define PREVIEW_Y 100
256 #define LABEL_X 71
257 #define SCORE_Y 17
258 #define LEVEL_Y 49
259 #define LINES_Y 82
261 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 64)
263 #define BLOCK_WIDTH 3
264 #define BLOCK_HEIGHT 3
265 #define BOARD_X 9
266 #define BOARD_Y 3
267 #define PREVIEW_X 53
268 #define PREVIEW_Y 5
269 #define LABEL_X 70
270 #define SCORE_Y 32
271 #define LEVEL_Y 13
272 #define LINES_Y 51
274 #elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
276 #define BLOCK_WIDTH 4
277 #define BLOCK_HEIGHT 3
278 #define BOARD_X 9
279 #define BOARD_Y 3
280 #define PREVIEW_X 59
281 #define PREVIEW_Y 5
282 #define LABEL_X 59
283 #define SCORE_Y 32
284 #define LEVEL_Y 13
285 #define LEVEL_X 78
286 #define LINES_Y 51
288 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
290 #define BLOCK_WIDTH 5
291 #define BLOCK_HEIGHT 5
292 #define BOARD_X 14
293 #define BOARD_Y 0
294 #define PREVIEW_X 98
295 #define PREVIEW_Y 88
296 #define LABEL_X 80
297 #define SCORE_Y 15
298 #define LEVEL_Y 45
299 #define LINES_Y 74
301 #endif
303 #ifndef LEVEL_X
304 #define LEVEL_X LABEL_X
305 #endif
307 #ifndef LINES_X
308 #define LINES_X LABEL_X
309 #endif
311 #define MYLCD(fn) rb->lcd_ ## fn
313 extern const fb_data rockblox_background[];
315 #else /* HAVE_LCD_CHARCELLS */
317 #define BOARD_HEIGHT 14
319 #define BLOCK_WIDTH 1
320 #define BLOCK_HEIGHT 1
321 #define BOARD_X 5
322 #define BOARD_Y 0
323 #define PREVIEW_X 15
324 #define PREVIEW_Y 1
326 #define MYLCD(fn) pgfx_ ## fn
328 #endif
330 /* <<Explanation on Rockblox shapes>>
333 %% - O has 1 orientation
335 %% %
336 %% %% - Z has 2 orientations
339 %% %
340 %% %% - S has 2 orientations
344 % %%%% - I has 2 orientations
347 % %%
348 % % % %%% - L has 4 orientations
349 %% %%% % %
351 % %%s
352 % % % %%% - J has 4 orientations
353 %% %%% % %
355 % % %%%
356 %% % %% % - T has 4 orientations
357 % %%% %
361 /* must have variable */
362 static struct plugin_api *rb;
364 static bool gameover = false;
365 /* c=current f=figure o=orientation n=next */
366 static int lines = 0, level = 0, score = 0, cx, cy, cf, co, nf;
367 static short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */
369 #ifdef SCROLL_WHEEL
370 int wheel_events = 0, last_wheel_event = 0;
371 bool wheel_enabled = false;
372 #endif
374 static const short scoring[4] = { /* scoring for each number of lines */
375 #if BOARD_HEIGHT == 20
376 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
377 #elif BOARD_HEIGHT == 14 /* Player special values */
378 60 /* single */ , 150 /* double */ , 500 /* triple */ , 2000 /* rockblox */
379 #endif
382 struct figure
384 #if LCD_DEPTH >= 2
385 unsigned short color[3]; /* color of figure (light,middle,shadow) */
386 #endif
387 unsigned short max_or; /* max orientations */
388 signed short shapeX[4], shapeY[4]; /* implementation of figures */
391 /* array of figures */
392 figures[BLOCKS_NUM] = {
393 /* O */
395 #if LCD_DEPTH >= 16
396 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
397 LCD_RGBPACK(0,153,153)},
398 #elif LCD_DEPTH == 2
399 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
400 #endif
402 {-1, 0, -1, 0},
403 {0, 0, 1, 1}
405 /* I */
407 #if LCD_DEPTH >= 16
408 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
409 LCD_RGBPACK (153, 0, 0)},
410 #elif LCD_DEPTH == 2
411 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
412 #endif
414 {-2, -1, 0, 1},
415 {0, 0, 0, 0}
417 /* 'Z' */
419 #if LCD_DEPTH >= 16
420 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
421 LCD_RGBPACK (0, 153, 0)},
422 #elif LCD_DEPTH == 2
423 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
424 #endif
426 {0, 1, -1, 0},
427 {0, 0, 1, 1}
429 /* 'S' */
431 #if LCD_DEPTH >= 16
432 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
433 LCD_RGBPACK (0, 0, 153)},
434 #elif LCD_DEPTH == 2
435 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
436 #endif
438 {-1, 0, 0, 1},
439 {0, 0, 1, 1}
441 /* 'L' */
443 #if LCD_DEPTH >= 16
444 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
445 LCD_RGBPACK (153, 153, 0)},
446 #elif LCD_DEPTH == 2
447 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
448 #endif
450 {-1, 0, 1, 1},
451 {0, 0, 0, 1}
453 /* 'J' */
455 #if LCD_DEPTH >= 16
456 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
457 LCD_RGBPACK (153, 0, 153)},
458 #elif LCD_DEPTH == 2
459 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
460 #endif
462 {-1, 0, 1, -1},
463 {0, 0, 0, 1}
465 /* 'T' */
467 #if LCD_DEPTH >= 16
468 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
469 LCD_RGBPACK (85, 85, 85)},
470 #elif LCD_DEPTH == 2
471 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
472 #endif
474 {-1, 0, 1, 0},
475 {0, 0, 0, 1}
479 /* Rockbox File System only supports full filenames inc dir */
480 #define HIGH_SCORE "/.rockbox/rocks/rockblox.score"
481 #define MAX_HIGH_SCORES 5
482 /* Default High Scores... */
483 struct highscore Highest[MAX_HIGH_SCORES];
485 /* get random number from (0) to (range-1) */
486 static int t_rand (int range)
488 return rb->rand () % range;
491 /* init the board array to have no blocks */
492 static void init_board (void)
494 int i, j;
495 for (i = 0; i < BOARD_WIDTH; i++)
496 for (j = 0; j < BOARD_HEIGHT; j++)
497 board[j][i] = EMPTY_BLOCK;
500 /* show the score, level and lines */
501 static void show_details (void)
503 char str[25]; /* for strings */
505 #ifdef HAVE_LCD_BITMAP
506 #if LCD_DEPTH >= 2
507 rb->lcd_set_foreground (LCD_BLACK);
508 rb->lcd_set_background (LCD_WHITE);
509 #endif
510 rb->snprintf (str, sizeof (str), "%d", score);
511 rb->lcd_putsxy (LABEL_X, SCORE_Y, str);
512 rb->snprintf (str, sizeof (str), "%d", level);
513 rb->lcd_putsxy (LEVEL_X, LEVEL_Y, str);
514 rb->snprintf (str, sizeof (str), "%d", lines);
515 rb->lcd_putsxy (LINES_X, LINES_Y, str);
516 #else /* HAVE_LCD_CHARCELLS */
517 rb->snprintf (str, sizeof (str), "L%d/%d", level, lines);
518 rb->lcd_puts (5, 0, str);
519 rb->snprintf (str, sizeof (str), "S%d", score);
520 rb->lcd_puts (5, 1, str);
521 #endif
524 static void init_rockblox (void)
526 #ifdef HIGH_SCORE_Y
527 int i;
528 char str[25]; /* for strings */
529 #endif
530 highscore_update(score, level, Highest, MAX_HIGH_SCORES);
532 level = 1;
533 lines = 0;
534 score = 0;
535 gameover = false;
536 nf = t_rand (BLOCKS_NUM);
537 init_board ();
538 #ifdef HAVE_LCD_BITMAP
539 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
540 #else /* HAVE_LCD_CHARCELLS */
541 pgfx_display (0, 0);
542 pgfx_display_block (3, 0, 3, 1);
543 pgfx_display_block (4, 0, 3, 0);
544 pgfx_clear_display();
545 pgfx_fillrect (3, 0, 2, 14);
546 pgfx_fillrect (15, 7, 2, 7);
547 pgfx_update();
548 #endif
549 show_details ();
550 #ifdef HIGH_SCORE_Y
551 for (i = MAX_HIGH_SCORES-1; i>=0; i--)
553 rb->snprintf (str, sizeof (str), "%06d L%1d", Highest[i].score, Highest[i].level);
554 rb->lcd_putsxy (HIGH_LABEL_X, HIGH_SCORE_Y + (10 * ((MAX_HIGH_SCORES-1) - i)), str);
556 #endif
559 static inline int level_speed(int level)
561 #if BOARD_HEIGHT == 20
562 return (5*HZ) / (level + 9);
563 #elif BOARD_HEIGHT == 14
564 return (7*HZ) / (level + 9);
565 #endif
568 static int getRelativeX (int figure, int square, int orientation)
570 switch (orientation) {
571 case 0:
572 return figures[figure].shapeX[square];
573 case 1:
574 return figures[figure].shapeY[square];
575 case 2:
576 return -figures[figure].shapeX[square];
577 case 3:
578 return -figures[figure].shapeY[square];
579 default:
580 return 0;
584 static int getRelativeY (int figure, int square, int orientation)
586 switch (orientation) {
587 case 0:
588 return figures[figure].shapeY[square];
589 case 1:
590 return -figures[figure].shapeX[square];
591 case 2:
592 return -figures[figure].shapeY[square];
593 case 3:
594 return figures[figure].shapeX[square];
595 default:
596 return 0;
600 /* redraw the while board on the screen */
601 static void refresh_board (void)
603 int i, j, x, y, block;
605 #if LCD_DEPTH >= 2
606 rb->lcd_set_foreground (LCD_BLACK);
607 #elif LCD_DEPTH == 1
608 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
609 #endif
611 MYLCD(fillrect) (BOARD_X, BOARD_Y, BOARD_WIDTH * BLOCK_WIDTH,
612 BOARD_HEIGHT * BLOCK_HEIGHT);
614 #if LCD_DEPTH == 1
615 MYLCD(set_drawmode) (DRMODE_SOLID);
616 #endif
618 for (i = 0; i < BOARD_WIDTH; i++)
619 for (j = 0; j < BOARD_HEIGHT; j++) {
620 block = board[j][i];
621 if (block != EMPTY_BLOCK) {
622 #ifdef HAVE_LCD_BITMAP
623 #if LCD_DEPTH >= 2
624 /* middle drawing */
625 rb->lcd_set_foreground (figures[block].color[1]);
626 #endif
627 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
628 BOARD_Y + j * BLOCK_HEIGHT,
629 BLOCK_WIDTH, BLOCK_HEIGHT);
630 #if LCD_DEPTH >= 2
631 /* light drawing */
632 rb->lcd_set_foreground (figures[block].color[0]);
633 #endif
634 rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH,
635 BOARD_Y + j * BLOCK_HEIGHT,
636 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2);
637 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH,
638 BOARD_X + (i + 1) * BLOCK_WIDTH - 2,
639 BOARD_Y + j * BLOCK_HEIGHT);
640 #if LCD_DEPTH >= 2
641 /* shadow drawing */
642 rb->lcd_set_foreground (figures[block].color[2]);
643 #endif
644 rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
645 BOARD_Y + j * BLOCK_HEIGHT + 1,
646 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
647 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1,
648 BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
649 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
650 #else /* HAVE_LCD_CHARCELLS */
651 pgfx_drawpixel (BOARD_X + i, BOARD_Y + j);
652 #endif
656 for (i = 0; i < 4; i++) {
657 x = getRelativeX (cf, i, co) + cx;
658 y = getRelativeY (cf, i, co) + cy;
659 #ifdef HAVE_LCD_BITMAP
660 #if LCD_DEPTH >= 2
661 rb->lcd_set_foreground (figures[cf].color[1]); /* middle drawing */
662 #endif
663 rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH,
664 BOARD_Y + y * BLOCK_HEIGHT,
665 BLOCK_WIDTH, BLOCK_HEIGHT);
666 #if LCD_DEPTH >= 2
667 rb->lcd_set_foreground (figures[cf].color[0]); /* light drawing */
668 #endif
669 rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT,
670 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2);
671 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH,
672 BOARD_X + (x + 1) * BLOCK_WIDTH - 2,
673 BOARD_Y + y * BLOCK_HEIGHT);
674 #if LCD_DEPTH >= 2
675 rb->lcd_set_foreground (figures[cf].color[2]); /* shadow drawing */
676 #endif
677 rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
678 BOARD_Y + y * BLOCK_HEIGHT + 1,
679 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
680 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1,
681 BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
682 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
683 #else /* HAVE_LCD_CHARCELLS */
684 pgfx_drawpixel (BOARD_X + x, BOARD_Y + y);
685 #endif
687 MYLCD(update) ();
690 static bool canMoveTo (int x, int y, int newOrientation)
692 int i, rx, ry;
693 for (i = 0; i < 4; i++) {
694 ry = getRelativeY (cf, i, newOrientation) + y;
695 rx = getRelativeX (cf, i, newOrientation) + x;
696 if ((rx < 0 || rx >= BOARD_WIDTH) ||
697 (ry < 0 || ry >= BOARD_HEIGHT) || (board[ry][rx] != EMPTY_BLOCK))
698 return false;
700 return true;
703 /* draws the preview of next block in the preview window */
704 static void draw_next_block (void)
706 int i, rx, ry;
707 /* clear preview window first */
708 #if LCD_DEPTH >= 2
709 rb->lcd_set_foreground (LCD_BLACK);
710 #elif LCD_DEPTH == 1
711 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
712 #endif
714 /* 4x4 */
715 MYLCD(fillrect) (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4);
717 #if LCD_DEPTH == 1
718 MYLCD(set_drawmode) (DRMODE_SOLID);
719 #endif
721 /* draw the lightgray rectangles */
722 #if LCD_DEPTH >= 16
723 rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
724 #elif LCD_DEPTH == 2
725 rb->lcd_set_foreground (LCD_DARKGRAY);
726 #endif
728 #if LCD_DEPTH >= 2
729 for (rx = 0; rx < 4; rx++)
730 for (ry = 0; ry < 4; ry++)
731 rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH,
732 PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH,
733 BLOCK_HEIGHT);
734 #endif
736 /* draw the figure */
737 for (i = 0; i < 4; i++) {
738 rx = getRelativeX (nf, i, 0) + 2;
739 ry = getRelativeY (nf, i, 0) + 2;
740 #ifdef HAVE_LCD_BITMAP
741 #if LCD_DEPTH >= 2
742 rb->lcd_set_foreground (figures[nf].color[1]); /* middle drawing */
743 #endif
744 rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH,
745 PREVIEW_Y + ry * BLOCK_HEIGHT,
746 BLOCK_WIDTH, BLOCK_HEIGHT);
747 #if LCD_DEPTH >= 2
748 rb->lcd_set_foreground (figures[nf].color[0]); /* light drawing */
749 #endif
750 rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH,
751 PREVIEW_Y + ry * BLOCK_HEIGHT,
752 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2);
753 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH,
754 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2,
755 PREVIEW_Y + ry * BLOCK_HEIGHT);
756 #if LCD_DEPTH >= 2
757 rb->lcd_set_foreground (figures[nf].color[2]); /* shadow drawing */
758 #endif
759 rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
760 PREVIEW_Y + ry * BLOCK_HEIGHT + 1,
761 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
762 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1,
763 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
764 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
765 #else /* HAVE_LCD_CHARCELLS */
766 pgfx_drawpixel (PREVIEW_X + rx, PREVIEW_Y + ry);
767 #endif
772 /* move the block to a relative location */
773 static void move_block (int x, int y, int o)
775 if (canMoveTo (cx + x, cy + y, o)) {
776 cy += y;
777 cx += x;
778 co = o;
782 /* try to add a new block to play with (return true if gameover) */
783 static void new_block (void)
785 cy = 1;
786 cx = 5;
787 cf = nf;
788 co = 0; /* start at the same orientation all time */
789 nf = t_rand (BLOCKS_NUM);
790 gameover = !canMoveTo (cx, cy, co);
792 draw_next_block ();
796 /* check for filled lines and do what necessary */
797 static int check_lines (void)
799 int i, j, y;
800 int rockblox = 0;
802 for (j = 0; j < BOARD_HEIGHT; j++) {
803 for (i = 0; ((i < BOARD_WIDTH) && (board[j][i] != EMPTY_BLOCK)); i++);
804 if (i == BOARD_WIDTH) { /* woo hoo, we have a line */
805 rockblox++;
806 for (y = j; y > 0; y--)
807 for (i = 0; i < BOARD_WIDTH; i++)
808 board[y][i] = board[y - 1][i]; /* fall line */
812 return rockblox;
815 /* moves down the figure and returns true if gameover */
816 static void move_down (void)
818 int l, i, rx, ry;
820 if (!canMoveTo (cx, cy + 1, co)) {
821 /* save figure to board */
822 for (i = 0; i < 4; i++) {
823 rx = getRelativeX (cf, i, co) + cx;
824 ry = getRelativeY (cf, i, co) + cy;
825 board[ry][rx] = cf;
827 /* check if formed some lines */
828 l = check_lines ();
829 if (l) {
830 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
831 score += scoring[l - 1] * level;
832 lines += l;
833 level = (int) lines / 10 + 1;
836 /* show details */
837 show_details ();
839 /* generate a new figure */
840 new_block ();
841 } else
842 move_block (0, 1, co);
845 static int rockblox_loop (void)
847 int button;
848 int lastbutton = BUTTON_NONE;
849 long next_down_tick = *rb->current_tick + level_speed(level);
851 new_block ();
853 while (1) {
854 #ifdef HAS_BUTTON_HOLD
855 if (rb->button_hold ()) {
856 /* Restore user's original backlight setting */
857 rb->backlight_set_timeout (rb->global_settings->backlight_timeout);
859 rb->splash(0, "Paused");
860 while (rb->button_hold ())
861 rb->sleep(HZ/10);
863 /* Permanently enable the backlight (unless the user has
864 turned it off) */
865 if (rb->global_settings->backlight_timeout > 0)
866 rb->backlight_set_timeout (1);
868 /* get rid of the splash text */
869 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
870 show_details ();
871 draw_next_block ();
872 refresh_board ();
874 #endif
876 button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1));
877 switch (button) {
878 #ifdef ROCKBLOX_RC_OFF
879 case ROCKBLOX_RC_OFF:
880 #endif
881 case ROCKBLOX_OFF:
882 return PLUGIN_OK;
884 #if defined(ROCKBLOX_ROTATE)
885 case ROCKBLOX_ROTATE:
886 #endif
887 case ROCKBLOX_ROTATE_RIGHT:
888 case ROCKBLOX_ROTATE_RIGHT | BUTTON_REPEAT:
889 #ifdef SCROLL_WHEEL
890 /* if the wheel is disabled, add an event to the stack. */
891 if(wheel_enabled == false)
892 wheel_events++;
894 /* if it's enabled, go ahead and rotate.. */
895 if(wheel_enabled)
896 #endif
897 move_block (0, 0, (co + 1) % figures[cf].max_or);
898 break;
900 case ROCKBLOX_ROTATE_LEFT:
901 case ROCKBLOX_ROTATE_LEFT | BUTTON_REPEAT:
902 #ifdef SCROLL_WHEEL
903 if(wheel_enabled == false)
904 wheel_events++;
906 if(wheel_enabled)
907 #endif
908 move_block (0, 0,
909 (co + figures[cf].max_or -
910 1) % figures[cf].max_or);
911 break;
913 #ifdef ROCKBLOX_ROTATE_RIGHT2
914 case ROCKBLOX_ROTATE_RIGHT2:
915 move_block (0, 0, (co + 1) % figures[cf].max_or);
916 break;
917 #endif
919 case ROCKBLOX_DOWN:
920 case ROCKBLOX_DOWN | BUTTON_REPEAT:
921 move_block (0, 1, co);
922 break;
924 case ROCKBLOX_RIGHT:
925 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
926 move_block (1, 0, co);
927 break;
929 case ROCKBLOX_LEFT:
930 case ROCKBLOX_LEFT | BUTTON_REPEAT:
931 move_block (-1, 0, co);
932 break;
934 case ROCKBLOX_DROP:
935 #ifdef ROCKBLOX_DROP_PRE
936 if (lastbutton != ROCKBLOX_DROP_PRE)
937 break;
938 #endif
939 while (canMoveTo (cx, cy + 1, co))
940 move_block (0, 1, co);
941 break;
942 #ifdef ROCKBLOX_RESTART
943 case ROCKBLOX_RESTART:
944 rb->splash (HZ * 1, "Restarting...");
945 init_rockblox ();
946 new_block ();
947 break;
948 #endif
950 default:
951 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
952 return PLUGIN_USB_CONNECTED;
953 break;
955 if (button != BUTTON_NONE)
956 lastbutton = button;
958 #ifdef SCROLL_WHEEL
959 /* check if we should enable the scroll wheel, if events
960 * begin to stack up... */
961 if(wheel_enabled == false)
963 /* stopped rotating the wheel, reset the count */
964 if(wheel_events == last_wheel_event)
966 last_wheel_event = 0;
967 wheel_events = 0;
969 /* rotated the wheel a while constantly, enable it. */
970 else if(wheel_events > 3)
972 wheel_enabled = true;
975 /* this evens out the last event and the "current" event.
976 * if we get an event next time through button reading, it will
977 * remain ahead of last_event. if we don't, they'll end up equaling
978 * each other.. thus, the scroll count will be reset. */
979 if(wheel_enabled == false && wheel_events > last_wheel_event)
980 last_wheel_event++;
982 #endif
984 if (TIME_AFTER(*rb->current_tick, next_down_tick)) {
985 move_down ();
986 next_down_tick += level_speed(level);
987 if (TIME_AFTER(*rb->current_tick, next_down_tick))
988 /* restart time "raster" when we had to wait longer than usual
989 * (pause, game restart etc) */
990 next_down_tick = *rb->current_tick + level_speed(level);
993 if (gameover) {
994 #if LCD_DEPTH >= 2
995 rb->lcd_set_foreground (LCD_BLACK);
996 #endif
997 rb->splash (HZ * 2, "Game Over");
998 init_rockblox ();
999 new_block ();
1002 refresh_board ();
1005 return PLUGIN_OK;
1008 enum plugin_status plugin_start (struct plugin_api *api, void *parameter)
1010 int ret;
1012 (void) parameter;
1013 rb = api;
1015 rb->srand (*rb->current_tick);
1017 /* Load HighScore if any */
1018 highscore_init(rb);
1019 highscore_load(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1021 #if LCD_DEPTH > 1
1022 rb->lcd_set_backdrop(NULL);
1023 #endif
1025 #ifdef HAVE_LCD_BITMAP
1026 rb->lcd_setfont (FONT_SYSFIXED);
1027 #else
1028 if (!pgfx_init(rb, 4, 2))
1030 rb->splash(HZ*2, "Old LCD :(");
1031 return PLUGIN_OK;
1033 #endif
1034 /* Permanently enable the backlight (unless the user has turned it off) */
1035 if (rb->global_settings->backlight_timeout > 0)
1036 rb->backlight_set_timeout (1);
1038 init_rockblox ();
1039 ret = rockblox_loop ();
1041 #ifdef HAVE_LCD_BITMAP
1042 rb->lcd_setfont (FONT_UI);
1043 #else
1044 pgfx_release();
1045 #endif
1046 /* Save user's HighScore */
1047 highscore_save(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1048 /* Restore user's original backlight setting */
1049 rb->backlight_set_timeout (rb->global_settings->backlight_timeout);
1051 return ret;