Accept FS#7228 by Dagni McPhee enable pitchscreen on sansa
[Rockbox.git] / apps / plugins / rockblox.c
blob2484d6eaaa1026f094e49af21e9b392188e7e1a2
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_3G_PAD) || \
28 (CONFIG_KEYPAD == IPOD_4G_PAD)
30 #define ROCKBLOX_OFF (BUTTON_MENU | BUTTON_SELECT)
31 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
32 #define ROCKBLOX_ROTATE_RIGHT2 (BUTTON_MENU | BUTTON_REL)
33 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
34 #define ROCKBLOX_LEFT BUTTON_LEFT
35 #define ROCKBLOX_RIGHT BUTTON_RIGHT
36 #define ROCKBLOX_DOWN BUTTON_PLAY
37 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_PLAY)
38 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
40 #define SCROLL_WHEEL
42 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
43 (CONFIG_KEYPAD == IRIVER_H300_PAD)
45 #define ROCKBLOX_OFF BUTTON_OFF
46 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
47 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
48 #define ROCKBLOX_DOWN BUTTON_DOWN
49 #define ROCKBLOX_LEFT BUTTON_LEFT
50 #define ROCKBLOX_RIGHT BUTTON_RIGHT
51 #define ROCKBLOX_DROP BUTTON_MODE
52 #define ROCKBLOX_RESTART BUTTON_ON
54 #define ROCKBLOX_RC_OFF BUTTON_RC_STOP
55 #elif CONFIG_KEYPAD == RECORDER_PAD
57 #define ROCKBLOX_OFF BUTTON_OFF
58 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
59 #define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
60 #define ROCKBLOX_DOWN BUTTON_DOWN
61 #define ROCKBLOX_LEFT BUTTON_LEFT
62 #define ROCKBLOX_RIGHT BUTTON_RIGHT
63 #define ROCKBLOX_DROP BUTTON_ON
64 #define ROCKBLOX_RESTART BUTTON_F1
66 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
68 #define ROCKBLOX_OFF BUTTON_OFF
69 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
70 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
71 #define ROCKBLOX_DOWN BUTTON_DOWN
72 #define ROCKBLOX_LEFT BUTTON_LEFT
73 #define ROCKBLOX_RIGHT BUTTON_RIGHT
74 #define ROCKBLOX_DROP BUTTON_ON
75 #define ROCKBLOX_RESTART BUTTON_F1
77 #elif CONFIG_KEYPAD == PLAYER_PAD
79 #define ROCKBLOX_OFF BUTTON_STOP
80 #define ROCKBLOX_ROTATE_RIGHT BUTTON_PLAY
81 #define ROCKBLOX_ROTATE_LEFT (BUTTON_ON|BUTTON_PLAY)
82 #define ROCKBLOX_DOWN BUTTON_MENU
83 #define ROCKBLOX_LEFT BUTTON_LEFT
84 #define ROCKBLOX_RIGHT BUTTON_RIGHT
85 #define ROCKBLOX_DROP_PRE BUTTON_ON
86 #define ROCKBLOX_DROP (BUTTON_ON|BUTTON_REL)
88 #elif CONFIG_KEYPAD == ONDIO_PAD
90 #define ROCKBLOX_OFF BUTTON_OFF
91 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
92 #define ROCKBLOX_ROTATE_LEFT (BUTTON_MENU|BUTTON_UP)
93 #define ROCKBLOX_DOWN BUTTON_DOWN
94 #define ROCKBLOX_LEFT BUTTON_LEFT
95 #define ROCKBLOX_RIGHT BUTTON_RIGHT
96 #define ROCKBLOX_DROP_PRE BUTTON_MENU
97 #define ROCKBLOX_DROP (BUTTON_MENU|BUTTON_REL)
99 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
101 #define ROCKBLOX_OFF BUTTON_POWER
102 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
103 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
104 #define ROCKBLOX_DOWN BUTTON_DOWN
105 #define ROCKBLOX_LEFT BUTTON_LEFT
106 #define ROCKBLOX_RIGHT BUTTON_RIGHT
107 #define ROCKBLOX_DROP BUTTON_REC
108 #define ROCKBLOX_RESTART BUTTON_PLAY
110 #elif CONFIG_KEYPAD == SANSA_E200_PAD
112 #define ROCKBLOX_OFF BUTTON_POWER
113 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_UP
114 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_DOWN
115 #define ROCKBLOX_DOWN BUTTON_DOWN
116 #define ROCKBLOX_LEFT BUTTON_LEFT
117 #define ROCKBLOX_RIGHT BUTTON_RIGHT
118 #define ROCKBLOX_DROP BUTTON_SELECT
119 #define ROCKBLOX_RESTART BUTTON_REC
121 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
123 #define ROCKBLOX_OFF BUTTON_POWER
124 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_UP
125 #define ROCKBLOX_ROTATE_LEFT BUTTON_REW
126 #define ROCKBLOX_DOWN BUTTON_SCROLL_DOWN
127 #define ROCKBLOX_LEFT BUTTON_LEFT
128 #define ROCKBLOX_RIGHT BUTTON_RIGHT
129 #define ROCKBLOX_DROP BUTTON_FF
130 #define ROCKBLOX_RESTART BUTTON_PLAY
132 #elif CONFIG_KEYPAD == GIGABEAT_PAD
134 #define ROCKBLOX_OFF BUTTON_POWER
135 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
136 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
137 #define ROCKBLOX_ROTATE BUTTON_UP
138 #define ROCKBLOX_DOWN BUTTON_DOWN
139 #define ROCKBLOX_LEFT BUTTON_LEFT
140 #define ROCKBLOX_RIGHT BUTTON_RIGHT
141 #define ROCKBLOX_DROP BUTTON_SELECT
142 #define ROCKBLOX_RESTART BUTTON_A
144 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
146 #define ROCKBLOX_OFF BUTTON_PLAY
147 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
148 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
149 #define ROCKBLOX_DOWN BUTTON_DOWN
150 #define ROCKBLOX_LEFT BUTTON_LEFT
151 #define ROCKBLOX_RIGHT BUTTON_RIGHT
152 #define ROCKBLOX_DROP BUTTON_MODE
153 #define ROCKBLOX_RESTART BUTTON_EQ
155 #endif
157 #define BLOCKS_NUM 7
158 #define EMPTY_BLOCK 7
160 #define BOARD_WIDTH 10
162 #ifdef HAVE_LCD_BITMAP
164 #define BOARD_HEIGHT 20
166 #if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
168 #define BLOCK_WIDTH 12
169 #define BLOCK_HEIGHT 12
170 #define BOARD_X 86
171 #define BOARD_Y 0
172 #define PREVIEW_X 12
173 #define PREVIEW_Y 11
174 #define LABEL_X 242
175 #define SCORE_Y 25
176 #define LEVEL_Y 70
177 #define LINES_Y 105
179 #elif (LCD_WIDTH == 240) && (LCD_HEIGHT == 320)
181 #define BLOCK_WIDTH 15
182 #define BLOCK_HEIGHT 15
183 #define BOARD_X 7
184 #define BOARD_Y 1
185 #define PREVIEW_X 171
186 #define PREVIEW_Y 241
187 #define LABEL_X 172
188 #define SCORE_Y 29
189 #define LEVEL_Y 71
190 #define LINES_Y 109
191 #define HIGH_LABEL_X 172
192 #define HIGH_SCORE_Y 163
193 #define HIGH_LEVEL_Y 172
195 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
197 #define BLOCK_WIDTH 8
198 #define BLOCK_HEIGHT 8
199 #define BOARD_X 27
200 #define BOARD_Y 5
201 #define PREVIEW_X 158
202 #define PREVIEW_Y 130
203 #define LABEL_X 147
204 #define SCORE_Y 20
205 #define LEVEL_Y 65
206 #define LINES_Y 100
208 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
210 #define BLOCK_WIDTH 6
211 #define BLOCK_HEIGHT 6
212 #define BOARD_X 25
213 #define BOARD_Y 1
214 #define PREVIEW_X 126
215 #define PREVIEW_Y 102
216 #define LABEL_X 112
217 #define SCORE_Y 17
218 #define LEVEL_Y 49
219 #define LINES_Y 81
221 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
223 #define BLOCK_WIDTH 10
224 #define BLOCK_HEIGHT 10
225 #define BOARD_X 6
226 #define BOARD_Y 10
227 #define PREVIEW_X 124
228 #define PREVIEW_Y 167
229 #define LABEL_X 117
230 #define SCORE_Y 24
231 #define LEVEL_Y 65
232 #define LINES_Y 103
233 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
235 #define BLOCK_WIDTH 6
236 #define BLOCK_HEIGHT 6
237 #define BOARD_X 22
238 #define BOARD_Y 3
239 #define PREVIEW_X 114
240 #define PREVIEW_Y 100
241 #define LABEL_X 101
242 #define SCORE_Y 17
243 #define LEVEL_Y 49
244 #define LINES_Y 82
246 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
248 #define BLOCK_WIDTH 6
249 #define BLOCK_HEIGHT 6
250 #define BOARD_X 4
251 #define BOARD_Y 3
252 #define PREVIEW_X 84
253 #define PREVIEW_Y 100
254 #define LABEL_X 71
255 #define SCORE_Y 17
256 #define LEVEL_Y 49
257 #define LINES_Y 82
259 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 64)
261 #define BLOCK_WIDTH 3
262 #define BLOCK_HEIGHT 3
263 #define BOARD_X 9
264 #define BOARD_Y 3
265 #define PREVIEW_X 53
266 #define PREVIEW_Y 5
267 #define LABEL_X 70
268 #define SCORE_Y 32
269 #define LEVEL_Y 13
270 #define LINES_Y 51
272 #elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
274 #define BLOCK_WIDTH 4
275 #define BLOCK_HEIGHT 3
276 #define BOARD_X 9
277 #define BOARD_Y 3
278 #define PREVIEW_X 59
279 #define PREVIEW_Y 5
280 #define LABEL_X 59
281 #define SCORE_Y 32
282 #define LEVEL_Y 13
283 #define LEVEL_X 78
284 #define LINES_Y 51
286 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
288 #define BLOCK_WIDTH 5
289 #define BLOCK_HEIGHT 5
290 #define BOARD_X 14
291 #define BOARD_Y 0
292 #define PREVIEW_X 98
293 #define PREVIEW_Y 88
294 #define LABEL_X 80
295 #define SCORE_Y 15
296 #define LEVEL_Y 45
297 #define LINES_Y 74
299 #endif
301 #ifndef LEVEL_X
302 #define LEVEL_X LABEL_X
303 #endif
305 #ifndef LINES_X
306 #define LINES_X LABEL_X
307 #endif
309 #define MYLCD(fn) rb->lcd_ ## fn
311 extern const fb_data rockblox_background[];
313 #else /* HAVE_LCD_CHARCELLS */
315 #define BOARD_HEIGHT 14
317 #define BLOCK_WIDTH 1
318 #define BLOCK_HEIGHT 1
319 #define BOARD_X 5
320 #define BOARD_Y 0
321 #define PREVIEW_X 15
322 #define PREVIEW_Y 1
324 #define MYLCD(fn) pgfx_ ## fn
326 #endif
328 /* <<Explanation on Rockblox shapes>>
331 %% - O has 1 orientation
333 %% %
334 %% %% - Z has 2 orientations
337 %% %
338 %% %% - S has 2 orientations
342 % %%%% - I has 2 orientations
345 % %%
346 % % % %%% - L has 4 orientations
347 %% %%% % %
349 % %%s
350 % % % %%% - J has 4 orientations
351 %% %%% % %
353 % % %%%
354 %% % %% % - T has 4 orientations
355 % %%% %
359 /* must have variable */
360 static struct plugin_api *rb;
362 static bool gameover = false;
363 /* c=current f=figure o=orientation n=next */
364 static int lines = 0, level = 0, score = 0, cx, cy, cf, co, nf;
365 static short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */
367 #ifdef SCROLL_WHEEL
368 int wheel_events = 0, last_wheel_event = 0;
369 bool wheel_enabled = false;
370 #endif
372 static const short scoring[4] = { /* scoring for each number of lines */
373 #if BOARD_HEIGHT == 20
374 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
375 #elif BOARD_HEIGHT == 14 /* Player special values */
376 60 /* single */ , 150 /* double */ , 500 /* triple */ , 2000 /* rockblox */
377 #endif
380 struct figure
382 #if LCD_DEPTH >= 2
383 unsigned short color[3]; /* color of figure (light,middle,shadow) */
384 #endif
385 unsigned short max_or; /* max orientations */
386 signed short shapeX[4], shapeY[4]; /* implementation of figures */
389 /* array of figures */
390 figures[BLOCKS_NUM] = {
391 /* O */
393 #if LCD_DEPTH >= 16
394 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
395 LCD_RGBPACK(0,153,153)},
396 #elif LCD_DEPTH == 2
397 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
398 #endif
400 {-1, 0, -1, 0},
401 {0, 0, 1, 1}
403 /* I */
405 #if LCD_DEPTH >= 16
406 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
407 LCD_RGBPACK (153, 0, 0)},
408 #elif LCD_DEPTH == 2
409 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
410 #endif
412 {-2, -1, 0, 1},
413 {0, 0, 0, 0}
415 /* 'Z' */
417 #if LCD_DEPTH >= 16
418 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
419 LCD_RGBPACK (0, 153, 0)},
420 #elif LCD_DEPTH == 2
421 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
422 #endif
424 {0, 1, -1, 0},
425 {0, 0, 1, 1}
427 /* 'S' */
429 #if LCD_DEPTH >= 16
430 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
431 LCD_RGBPACK (0, 0, 153)},
432 #elif LCD_DEPTH == 2
433 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
434 #endif
436 {-1, 0, 0, 1},
437 {0, 0, 1, 1}
439 /* 'L' */
441 #if LCD_DEPTH >= 16
442 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
443 LCD_RGBPACK (153, 153, 0)},
444 #elif LCD_DEPTH == 2
445 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
446 #endif
448 {-1, 0, 1, 1},
449 {0, 0, 0, 1}
451 /* 'J' */
453 #if LCD_DEPTH >= 16
454 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
455 LCD_RGBPACK (153, 0, 153)},
456 #elif LCD_DEPTH == 2
457 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
458 #endif
460 {-1, 0, 1, -1},
461 {0, 0, 0, 1}
463 /* 'T' */
465 #if LCD_DEPTH >= 16
466 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
467 LCD_RGBPACK (85, 85, 85)},
468 #elif LCD_DEPTH == 2
469 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
470 #endif
472 {-1, 0, 1, 0},
473 {0, 0, 0, 1}
477 /* Rockbox File System only supports full filenames inc dir */
478 #define HIGH_SCORE "/.rockbox/rocks/rockblox.score"
479 #define MAX_HIGH_SCORES 5
480 /* Default High Scores... */
481 struct highscore Highest[MAX_HIGH_SCORES];
483 /* get random number from (0) to (range-1) */
484 static int t_rand (int range)
486 return rb->rand () % range;
489 /* init the board array to have no blocks */
490 static void init_board (void)
492 int i, j;
493 for (i = 0; i < BOARD_WIDTH; i++)
494 for (j = 0; j < BOARD_HEIGHT; j++)
495 board[j][i] = EMPTY_BLOCK;
498 /* show the score, level and lines */
499 static void show_details (void)
501 char str[25]; /* for strings */
503 #ifdef HAVE_LCD_BITMAP
504 #if LCD_DEPTH >= 2
505 rb->lcd_set_foreground (LCD_BLACK);
506 rb->lcd_set_background (LCD_WHITE);
507 #endif
508 rb->snprintf (str, sizeof (str), "%d", score);
509 rb->lcd_putsxy (LABEL_X, SCORE_Y, str);
510 rb->snprintf (str, sizeof (str), "%d", level);
511 rb->lcd_putsxy (LEVEL_X, LEVEL_Y, str);
512 rb->snprintf (str, sizeof (str), "%d", lines);
513 rb->lcd_putsxy (LINES_X, LINES_Y, str);
514 #else /* HAVE_LCD_CHARCELLS */
515 rb->snprintf (str, sizeof (str), "L%d/%d", level, lines);
516 rb->lcd_puts (5, 0, str);
517 rb->snprintf (str, sizeof (str), "S%d", score);
518 rb->lcd_puts (5, 1, str);
519 #endif
522 static void init_rockblox (void)
524 #ifdef HIGH_SCORE_Y
525 int i;
526 char str[25]; /* for strings */
527 #endif
528 highscore_update(score, level, Highest, MAX_HIGH_SCORES);
530 level = 1;
531 lines = 0;
532 score = 0;
533 gameover = false;
534 nf = t_rand (BLOCKS_NUM);
535 init_board ();
536 #ifdef HAVE_LCD_BITMAP
537 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
538 #else /* HAVE_LCD_CHARCELLS */
539 pgfx_display (0, 0);
540 pgfx_display_block (3, 0, 3, 1);
541 pgfx_display_block (4, 0, 3, 0);
542 pgfx_clear_display();
543 pgfx_fillrect (3, 0, 2, 14);
544 pgfx_fillrect (15, 7, 2, 7);
545 pgfx_update();
546 #endif
547 show_details ();
548 #ifdef HIGH_SCORE_Y
549 for (i = MAX_HIGH_SCORES-1; i>=0; i--)
551 rb->snprintf (str, sizeof (str), "%06d L%1d", Highest[i].score, Highest[i].level);
552 rb->lcd_putsxy (HIGH_LABEL_X, HIGH_SCORE_Y + (10 * ((MAX_HIGH_SCORES-1) - i)), str);
554 #endif
557 static inline int level_speed(int level)
559 #if BOARD_HEIGHT == 20
560 return (5*HZ) / (level + 9);
561 #elif BOARD_HEIGHT == 14
562 return (7*HZ) / (level + 9);
563 #endif
566 static int getRelativeX (int figure, int square, int orientation)
568 switch (orientation) {
569 case 0:
570 return figures[figure].shapeX[square];
571 case 1:
572 return figures[figure].shapeY[square];
573 case 2:
574 return -figures[figure].shapeX[square];
575 case 3:
576 return -figures[figure].shapeY[square];
577 default:
578 return 0;
582 static int getRelativeY (int figure, int square, int orientation)
584 switch (orientation) {
585 case 0:
586 return figures[figure].shapeY[square];
587 case 1:
588 return -figures[figure].shapeX[square];
589 case 2:
590 return -figures[figure].shapeY[square];
591 case 3:
592 return figures[figure].shapeX[square];
593 default:
594 return 0;
598 /* redraw the while board on the screen */
599 static void refresh_board (void)
601 int i, j, x, y, block;
603 #if LCD_DEPTH >= 2
604 rb->lcd_set_foreground (LCD_BLACK);
605 #elif LCD_DEPTH == 1
606 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
607 #endif
609 MYLCD(fillrect) (BOARD_X, BOARD_Y, BOARD_WIDTH * BLOCK_WIDTH,
610 BOARD_HEIGHT * BLOCK_HEIGHT);
612 #if LCD_DEPTH == 1
613 MYLCD(set_drawmode) (DRMODE_SOLID);
614 #endif
616 for (i = 0; i < BOARD_WIDTH; i++)
617 for (j = 0; j < BOARD_HEIGHT; j++) {
618 block = board[j][i];
619 if (block != EMPTY_BLOCK) {
620 #ifdef HAVE_LCD_BITMAP
621 #if LCD_DEPTH >= 2
622 /* middle drawing */
623 rb->lcd_set_foreground (figures[block].color[1]);
624 #endif
625 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
626 BOARD_Y + j * BLOCK_HEIGHT,
627 BLOCK_WIDTH, BLOCK_HEIGHT);
628 #if LCD_DEPTH >= 2
629 /* light drawing */
630 rb->lcd_set_foreground (figures[block].color[0]);
631 #endif
632 rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH,
633 BOARD_Y + j * BLOCK_HEIGHT,
634 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2);
635 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH,
636 BOARD_X + (i + 1) * BLOCK_WIDTH - 2,
637 BOARD_Y + j * BLOCK_HEIGHT);
638 #if LCD_DEPTH >= 2
639 /* shadow drawing */
640 rb->lcd_set_foreground (figures[block].color[2]);
641 #endif
642 rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
643 BOARD_Y + j * BLOCK_HEIGHT + 1,
644 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
645 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1,
646 BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
647 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
648 #else /* HAVE_LCD_CHARCELLS */
649 pgfx_drawpixel (BOARD_X + i, BOARD_Y + j);
650 #endif
654 for (i = 0; i < 4; i++) {
655 x = getRelativeX (cf, i, co) + cx;
656 y = getRelativeY (cf, i, co) + cy;
657 #ifdef HAVE_LCD_BITMAP
658 #if LCD_DEPTH >= 2
659 rb->lcd_set_foreground (figures[cf].color[1]); /* middle drawing */
660 #endif
661 rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH,
662 BOARD_Y + y * BLOCK_HEIGHT,
663 BLOCK_WIDTH, BLOCK_HEIGHT);
664 #if LCD_DEPTH >= 2
665 rb->lcd_set_foreground (figures[cf].color[0]); /* light drawing */
666 #endif
667 rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT,
668 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2);
669 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH,
670 BOARD_X + (x + 1) * BLOCK_WIDTH - 2,
671 BOARD_Y + y * BLOCK_HEIGHT);
672 #if LCD_DEPTH >= 2
673 rb->lcd_set_foreground (figures[cf].color[2]); /* shadow drawing */
674 #endif
675 rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
676 BOARD_Y + y * BLOCK_HEIGHT + 1,
677 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
678 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1,
679 BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
680 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
681 #else /* HAVE_LCD_CHARCELLS */
682 pgfx_drawpixel (BOARD_X + x, BOARD_Y + y);
683 #endif
685 MYLCD(update) ();
688 static bool canMoveTo (int x, int y, int newOrientation)
690 int i, rx, ry;
691 for (i = 0; i < 4; i++) {
692 ry = getRelativeY (cf, i, newOrientation) + y;
693 rx = getRelativeX (cf, i, newOrientation) + x;
694 if ((rx < 0 || rx >= BOARD_WIDTH) ||
695 (ry < 0 || ry >= BOARD_HEIGHT) || (board[ry][rx] != EMPTY_BLOCK))
696 return false;
698 return true;
701 /* draws the preview of next block in the preview window */
702 static void draw_next_block (void)
704 int i, rx, ry;
705 /* clear preview window first */
706 #if LCD_DEPTH >= 2
707 rb->lcd_set_foreground (LCD_BLACK);
708 #elif LCD_DEPTH == 1
709 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
710 #endif
712 /* 4x4 */
713 MYLCD(fillrect) (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4);
715 #if LCD_DEPTH == 1
716 MYLCD(set_drawmode) (DRMODE_SOLID);
717 #endif
719 /* draw the lightgray rectangles */
720 #if LCD_DEPTH >= 16
721 rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
722 #elif LCD_DEPTH == 2
723 rb->lcd_set_foreground (LCD_DARKGRAY);
724 #endif
726 #if LCD_DEPTH >= 2
727 for (rx = 0; rx < 4; rx++)
728 for (ry = 0; ry < 4; ry++)
729 rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH,
730 PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH,
731 BLOCK_HEIGHT);
732 #endif
734 /* draw the figure */
735 for (i = 0; i < 4; i++) {
736 rx = getRelativeX (nf, i, 0) + 2;
737 ry = getRelativeY (nf, i, 0) + 2;
738 #ifdef HAVE_LCD_BITMAP
739 #if LCD_DEPTH >= 2
740 rb->lcd_set_foreground (figures[nf].color[1]); /* middle drawing */
741 #endif
742 rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH,
743 PREVIEW_Y + ry * BLOCK_HEIGHT,
744 BLOCK_WIDTH, BLOCK_HEIGHT);
745 #if LCD_DEPTH >= 2
746 rb->lcd_set_foreground (figures[nf].color[0]); /* light drawing */
747 #endif
748 rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH,
749 PREVIEW_Y + ry * BLOCK_HEIGHT,
750 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2);
751 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH,
752 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2,
753 PREVIEW_Y + ry * BLOCK_HEIGHT);
754 #if LCD_DEPTH >= 2
755 rb->lcd_set_foreground (figures[nf].color[2]); /* shadow drawing */
756 #endif
757 rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
758 PREVIEW_Y + ry * BLOCK_HEIGHT + 1,
759 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
760 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1,
761 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
762 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
763 #else /* HAVE_LCD_CHARCELLS */
764 pgfx_drawpixel (PREVIEW_X + rx, PREVIEW_Y + ry);
765 #endif
770 /* move the block to a relative location */
771 static void move_block (int x, int y, int o)
773 if (canMoveTo (cx + x, cy + y, o)) {
774 cy += y;
775 cx += x;
776 co = o;
780 /* try to add a new block to play with (return true if gameover) */
781 static void new_block (void)
783 cy = 1;
784 cx = 5;
785 cf = nf;
786 co = 0; /* start at the same orientation all time */
787 nf = t_rand (BLOCKS_NUM);
788 gameover = !canMoveTo (cx, cy, co);
790 draw_next_block ();
794 /* check for filled lines and do what necessary */
795 static int check_lines (void)
797 int i, j, y;
798 int rockblox = 0;
800 for (j = 0; j < BOARD_HEIGHT; j++) {
801 for (i = 0; ((i < BOARD_WIDTH) && (board[j][i] != EMPTY_BLOCK)); i++);
802 if (i == BOARD_WIDTH) { /* woo hoo, we have a line */
803 rockblox++;
804 for (y = j; y > 0; y--)
805 for (i = 0; i < BOARD_WIDTH; i++)
806 board[y][i] = board[y - 1][i]; /* fall line */
810 return rockblox;
813 /* moves down the figure and returns true if gameover */
814 static void move_down (void)
816 int l, i, rx, ry;
818 if (!canMoveTo (cx, cy + 1, co)) {
819 /* save figure to board */
820 for (i = 0; i < 4; i++) {
821 rx = getRelativeX (cf, i, co) + cx;
822 ry = getRelativeY (cf, i, co) + cy;
823 board[ry][rx] = cf;
825 /* check if formed some lines */
826 l = check_lines ();
827 if (l) {
828 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
829 score += scoring[l - 1] * level;
830 lines += l;
831 level = (int) lines / 10 + 1;
834 /* show details */
835 show_details ();
837 /* generate a new figure */
838 new_block ();
839 } else
840 move_block (0, 1, co);
843 static int rockblox_loop (void)
845 int button;
846 int lastbutton = BUTTON_NONE;
847 long next_down_tick = *rb->current_tick + level_speed(level);
849 new_block ();
851 while (1) {
852 #ifdef HAS_BUTTON_HOLD
853 if (rb->button_hold ()) {
854 /* Restore user's original backlight setting */
855 rb->backlight_set_timeout (rb->global_settings->backlight_timeout);
857 rb->splash(0, "Paused");
858 while (rb->button_hold ())
859 rb->sleep(HZ/10);
861 /* Permanently enable the backlight (unless the user has
862 turned it off) */
863 if (rb->global_settings->backlight_timeout > 0)
864 rb->backlight_set_timeout (1);
866 /* get rid of the splash text */
867 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
868 show_details ();
869 draw_next_block ();
870 refresh_board ();
872 #endif
874 button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1));
875 switch (button) {
876 #ifdef ROCKBLOX_RC_OFF
877 case ROCKBLOX_RC_OFF:
878 #endif
879 case ROCKBLOX_OFF:
880 return PLUGIN_OK;
882 #if defined(ROCKBLOX_ROTATE)
883 case ROCKBLOX_ROTATE:
884 #endif
885 case ROCKBLOX_ROTATE_RIGHT:
886 case ROCKBLOX_ROTATE_RIGHT | BUTTON_REPEAT:
887 #ifdef SCROLL_WHEEL
888 /* if the wheel is disabled, add an event to the stack. */
889 if(wheel_enabled == false)
890 wheel_events++;
892 /* if it's enabled, go ahead and rotate.. */
893 if(wheel_enabled)
894 #endif
895 move_block (0, 0, (co + 1) % figures[cf].max_or);
896 break;
898 case ROCKBLOX_ROTATE_LEFT:
899 case ROCKBLOX_ROTATE_LEFT | BUTTON_REPEAT:
900 #ifdef SCROLL_WHEEL
901 if(wheel_enabled == false)
902 wheel_events++;
904 if(wheel_enabled)
905 #endif
906 move_block (0, 0,
907 (co + figures[cf].max_or -
908 1) % figures[cf].max_or);
909 break;
911 #ifdef ROCKBLOX_ROTATE_RIGHT2
912 case ROCKBLOX_ROTATE_RIGHT2:
913 move_block (0, 0, (co + 1) % figures[cf].max_or);
914 break;
915 #endif
917 case ROCKBLOX_DOWN:
918 case ROCKBLOX_DOWN | BUTTON_REPEAT:
919 move_block (0, 1, co);
920 break;
922 case ROCKBLOX_RIGHT:
923 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
924 move_block (1, 0, co);
925 break;
927 case ROCKBLOX_LEFT:
928 case ROCKBLOX_LEFT | BUTTON_REPEAT:
929 move_block (-1, 0, co);
930 break;
932 case ROCKBLOX_DROP:
933 #ifdef ROCKBLOX_DROP_PRE
934 if (lastbutton != ROCKBLOX_DROP_PRE)
935 break;
936 #endif
937 while (canMoveTo (cx, cy + 1, co))
938 move_block (0, 1, co);
939 break;
940 #ifdef ROCKBLOX_RESTART
941 case ROCKBLOX_RESTART:
942 rb->splash (HZ * 1, "Restarting...");
943 init_rockblox ();
944 new_block ();
945 break;
946 #endif
948 default:
949 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
950 return PLUGIN_USB_CONNECTED;
951 break;
953 if (button != BUTTON_NONE)
954 lastbutton = button;
956 #ifdef SCROLL_WHEEL
957 /* check if we should enable the scroll wheel, if events
958 * begin to stack up... */
959 if(wheel_enabled == false)
961 /* stopped rotating the wheel, reset the count */
962 if(wheel_events == last_wheel_event)
964 last_wheel_event = 0;
965 wheel_events = 0;
967 /* rotated the wheel a while constantly, enable it. */
968 else if(wheel_events > 3)
970 wheel_enabled = true;
973 /* this evens out the last event and the "current" event.
974 * if we get an event next time through button reading, it will
975 * remain ahead of last_event. if we don't, they'll end up equaling
976 * each other.. thus, the scroll count will be reset. */
977 if(wheel_enabled == false && wheel_events > last_wheel_event)
978 last_wheel_event++;
980 #endif
982 if (TIME_AFTER(*rb->current_tick, next_down_tick)) {
983 move_down ();
984 next_down_tick += level_speed(level);
985 if (TIME_AFTER(*rb->current_tick, next_down_tick))
986 /* restart time "raster" when we had to wait longer than usual
987 * (pause, game restart etc) */
988 next_down_tick = *rb->current_tick + level_speed(level);
991 if (gameover) {
992 #if LCD_DEPTH >= 2
993 rb->lcd_set_foreground (LCD_BLACK);
994 #endif
995 rb->splash (HZ * 2, "Game Over");
996 init_rockblox ();
997 new_block ();
1000 refresh_board ();
1003 return PLUGIN_OK;
1006 enum plugin_status plugin_start (struct plugin_api *api, void *parameter)
1008 int ret;
1010 (void) parameter;
1011 rb = api;
1013 rb->srand (*rb->current_tick);
1015 /* Load HighScore if any */
1016 highscore_init(rb);
1017 highscore_load(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1019 #if LCD_DEPTH > 1
1020 rb->lcd_set_backdrop(NULL);
1021 #endif
1023 #ifdef HAVE_LCD_BITMAP
1024 rb->lcd_setfont (FONT_SYSFIXED);
1025 #else
1026 if (!pgfx_init(rb, 4, 2))
1028 rb->splash(HZ*2, "Old LCD :(");
1029 return PLUGIN_OK;
1031 #endif
1032 /* Permanently enable the backlight (unless the user has turned it off) */
1033 if (rb->global_settings->backlight_timeout > 0)
1034 rb->backlight_set_timeout (1);
1036 init_rockblox ();
1037 ret = rockblox_loop ();
1039 #ifdef HAVE_LCD_BITMAP
1040 rb->lcd_setfont (FONT_UI);
1041 #else
1042 pgfx_release();
1043 #endif
1044 /* Save user's HighScore */
1045 highscore_save(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1046 /* Restore user's original backlight setting */
1047 rb->backlight_set_timeout (rb->global_settings->backlight_timeout);
1049 return ret;