Add 2008 to the copyright notice.
[Rockbox.git] / apps / plugins / rockblox.c
blobb3444d39da283cba8a52cf94783ea0a23889a545
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 #endif
193 #define BLOCKS_NUM 7
194 #define EMPTY_BLOCK 7
196 #define BOARD_WIDTH 10
198 #ifdef HAVE_LCD_BITMAP
200 #define BOARD_HEIGHT 20
202 #if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
204 #define BLOCK_WIDTH 30
205 #define BLOCK_HEIGHT 30
206 #define BOARD_X 14
207 #define BOARD_Y 2
208 #define PREVIEW_X 342
209 #define PREVIEW_Y 482
210 #define LABEL_X 344
211 #define SCORE_Y 58
212 #define LEVEL_Y 142
213 #define LINES_Y 218
214 #define HIGH_LABEL_X 344
215 #define HIGH_SCORE_Y 326
216 #define HIGH_LEVEL_Y 344
218 #elif (LCD_WIDTH == 480) && (LCD_HEIGHT == 640)
220 #define BLOCK_WIDTH 30
221 #define BLOCK_HEIGHT 30
222 #define BOARD_X 14
223 #define BOARD_Y 2
224 #define PREVIEW_X 342
225 #define PREVIEW_Y 482
226 #define LABEL_X 344
227 #define SCORE_Y 58
228 #define LEVEL_Y 142
229 #define LINES_Y 218
230 #define HIGH_LABEL_X 344
231 #define HIGH_SCORE_Y 326
232 #define HIGH_LEVEL_Y 344
234 #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
236 #define BLOCK_WIDTH 12
237 #define BLOCK_HEIGHT 12
238 #define BOARD_X 86
239 #define BOARD_Y 0
240 #define PREVIEW_X 12
241 #define PREVIEW_Y 11
242 #define LABEL_X 242
243 #define SCORE_Y 25
244 #define LEVEL_Y 70
245 #define LINES_Y 105
247 #elif (LCD_WIDTH == 240) && (LCD_HEIGHT == 320)
249 #define BLOCK_WIDTH 15
250 #define BLOCK_HEIGHT 15
251 #define BOARD_X 7
252 #define BOARD_Y 1
253 #define PREVIEW_X 171
254 #define PREVIEW_Y 241
255 #define LABEL_X 172
256 #define SCORE_Y 29
257 #define LEVEL_Y 71
258 #define LINES_Y 109
259 #define HIGH_LABEL_X 172
260 #define HIGH_SCORE_Y 163
261 #define HIGH_LEVEL_Y 172
263 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
265 #define BLOCK_WIDTH 8
266 #define BLOCK_HEIGHT 8
267 #define BOARD_X 27
268 #define BOARD_Y 5
269 #define PREVIEW_X 158
270 #define PREVIEW_Y 130
271 #define LABEL_X 147
272 #define SCORE_Y 20
273 #define LEVEL_Y 65
274 #define LINES_Y 100
276 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
278 #define BLOCK_WIDTH 6
279 #define BLOCK_HEIGHT 6
280 #define BOARD_X 25
281 #define BOARD_Y 1
282 #define PREVIEW_X 126
283 #define PREVIEW_Y 102
284 #define LABEL_X 112
285 #define SCORE_Y 17
286 #define LEVEL_Y 49
287 #define LINES_Y 81
289 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
291 #define BLOCK_WIDTH 10
292 #define BLOCK_HEIGHT 10
293 #define BOARD_X 6
294 #define BOARD_Y 10
295 #define PREVIEW_X 124
296 #define PREVIEW_Y 167
297 #define LABEL_X 117
298 #define SCORE_Y 24
299 #define LEVEL_Y 65
300 #define LINES_Y 103
301 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
303 #define BLOCK_WIDTH 6
304 #define BLOCK_HEIGHT 6
305 #define BOARD_X 22
306 #define BOARD_Y 3
307 #define PREVIEW_X 114
308 #define PREVIEW_Y 100
309 #define LABEL_X 101
310 #define SCORE_Y 17
311 #define LEVEL_Y 49
312 #define LINES_Y 82
314 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
316 #define BLOCK_WIDTH 6
317 #define BLOCK_HEIGHT 6
318 #define BOARD_X 4
319 #define BOARD_Y 3
320 #define PREVIEW_X 84
321 #define PREVIEW_Y 100
322 #define LABEL_X 71
323 #define SCORE_Y 17
324 #define LEVEL_Y 49
325 #define LINES_Y 82
327 #elif (LCD_WIDTH == 132) && (LCD_HEIGHT == 80)
329 #define BLOCK_WIDTH 4
330 #define BLOCK_HEIGHT 4
331 #define BOARD_X 10
332 #define BOARD_Y 0
333 #define PREVIEW_X 89
334 #define PREVIEW_Y 61
335 #define LABEL_X 78
336 #define SCORE_Y 10
337 #define LEVEL_Y 30
338 #define LINES_Y 50
340 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 64)
342 #define BLOCK_WIDTH 3
343 #define BLOCK_HEIGHT 3
344 #define BOARD_X 9
345 #define BOARD_Y 3
346 #define PREVIEW_X 53
347 #define PREVIEW_Y 5
348 #define LABEL_X 70
349 #define SCORE_Y 32
350 #define LEVEL_Y 13
351 #define LINES_Y 51
353 #elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
355 #define BLOCK_WIDTH 4
356 #define BLOCK_HEIGHT 3
357 #define BOARD_X 9
358 #define BOARD_Y 3
359 #define PREVIEW_X 59
360 #define PREVIEW_Y 5
361 #define LABEL_X 59
362 #define SCORE_Y 32
363 #define LEVEL_Y 13
364 #define LEVEL_X 78
365 #define LINES_Y 51
367 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
369 #define BLOCK_WIDTH 5
370 #define BLOCK_HEIGHT 5
371 #define BOARD_X 14
372 #define BOARD_Y 0
373 #define PREVIEW_X 98
374 #define PREVIEW_Y 88
375 #define LABEL_X 80
376 #define SCORE_Y 15
377 #define LEVEL_Y 45
378 #define LINES_Y 74
380 #endif
382 #ifndef LEVEL_X
383 #define LEVEL_X LABEL_X
384 #endif
386 #ifndef LINES_X
387 #define LINES_X LABEL_X
388 #endif
390 #define MYLCD(fn) rb->lcd_ ## fn
392 extern const fb_data rockblox_background[];
394 #else /* HAVE_LCD_CHARCELLS */
396 #define BOARD_HEIGHT 14
398 #define BLOCK_WIDTH 1
399 #define BLOCK_HEIGHT 1
400 #define BOARD_X 5
401 #define BOARD_Y 0
402 #define PREVIEW_X 15
403 #define PREVIEW_Y 1
405 #define MYLCD(fn) pgfx_ ## fn
407 #endif
409 /* <<Explanation on Rockblox shapes>>
412 %% - O has 1 orientation
414 %% %
415 %% %% - Z has 2 orientations
418 %% %
419 %% %% - S has 2 orientations
423 % %%%% - I has 2 orientations
426 % %%
427 % % % %%% - L has 4 orientations
428 %% %%% % %
430 % %%s
431 % % % %%% - J has 4 orientations
432 %% %%% % %
434 % % %%%
435 %% % %% % - T has 4 orientations
436 % %%% %
440 /* must have variable */
441 static struct plugin_api *rb;
443 static bool gameover = false;
444 /* c=current f=figure o=orientation n=next */
445 static int lines = 0, level = 0, score = 0, cx, cy, cf, co, nf;
446 static short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */
448 #ifdef SCROLL_WHEEL
449 int wheel_events = 0, last_wheel_event = 0;
450 bool wheel_enabled = false;
451 #endif
453 static const short scoring[4] = { /* scoring for each number of lines */
454 #if BOARD_HEIGHT == 20
455 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
456 #elif BOARD_HEIGHT == 14 /* Player special values */
457 60 /* single */ , 150 /* double */ , 500 /* triple */ , 2000 /* rockblox */
458 #endif
461 struct figure
463 #if LCD_DEPTH >= 2
464 unsigned short color[3]; /* color of figure (light,middle,shadow) */
465 #endif
466 unsigned short max_or; /* max orientations */
467 signed short shapeX[4], shapeY[4]; /* implementation of figures */
470 /* array of figures */
471 figures[BLOCKS_NUM] = {
472 /* O */
474 #if LCD_DEPTH >= 16
475 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
476 LCD_RGBPACK(0,153,153)},
477 #elif LCD_DEPTH == 2
478 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
479 #endif
481 {-1, 0, -1, 0},
482 {0, 0, 1, 1}
484 /* I */
486 #if LCD_DEPTH >= 16
487 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
488 LCD_RGBPACK (153, 0, 0)},
489 #elif LCD_DEPTH == 2
490 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
491 #endif
493 {-2, -1, 0, 1},
494 {0, 0, 0, 0}
496 /* 'Z' */
498 #if LCD_DEPTH >= 16
499 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
500 LCD_RGBPACK (0, 153, 0)},
501 #elif LCD_DEPTH == 2
502 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
503 #endif
505 {0, 1, -1, 0},
506 {0, 0, 1, 1}
508 /* 'S' */
510 #if LCD_DEPTH >= 16
511 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
512 LCD_RGBPACK (0, 0, 153)},
513 #elif LCD_DEPTH == 2
514 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
515 #endif
517 {-1, 0, 0, 1},
518 {0, 0, 1, 1}
520 /* 'L' */
522 #if LCD_DEPTH >= 16
523 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
524 LCD_RGBPACK (153, 153, 0)},
525 #elif LCD_DEPTH == 2
526 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
527 #endif
529 {-1, 0, 1, 1},
530 {0, 0, 0, 1}
532 /* 'J' */
534 #if LCD_DEPTH >= 16
535 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
536 LCD_RGBPACK (153, 0, 153)},
537 #elif LCD_DEPTH == 2
538 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
539 #endif
541 {-1, 0, 1, -1},
542 {0, 0, 0, 1}
544 /* 'T' */
546 #if LCD_DEPTH >= 16
547 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
548 LCD_RGBPACK (85, 85, 85)},
549 #elif LCD_DEPTH == 2
550 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
551 #endif
553 {-1, 0, 1, 0},
554 {0, 0, 0, 1}
558 /* Rockbox File System only supports full filenames inc dir */
559 #define HIGH_SCORE PLUGIN_GAMES_DIR "/rockblox.score"
560 #define MAX_HIGH_SCORES 5
561 /* Default High Scores... */
562 struct highscore Highest[MAX_HIGH_SCORES];
564 /* get random number from (0) to (range-1) */
565 static int t_rand (int range)
567 return rb->rand () % range;
570 /* init the board array to have no blocks */
571 static void init_board (void)
573 int i, j;
574 for (i = 0; i < BOARD_WIDTH; i++)
575 for (j = 0; j < BOARD_HEIGHT; j++)
576 board[j][i] = EMPTY_BLOCK;
579 /* show the score, level and lines */
580 static void show_details (void)
582 char str[25]; /* for strings */
584 #ifdef HAVE_LCD_BITMAP
585 #if LCD_DEPTH >= 2
586 rb->lcd_set_foreground (LCD_BLACK);
587 rb->lcd_set_background (LCD_WHITE);
588 #endif
589 rb->snprintf (str, sizeof (str), "%d", score);
590 rb->lcd_putsxy (LABEL_X, SCORE_Y, str);
591 rb->snprintf (str, sizeof (str), "%d", level);
592 rb->lcd_putsxy (LEVEL_X, LEVEL_Y, str);
593 rb->snprintf (str, sizeof (str), "%d", lines);
594 rb->lcd_putsxy (LINES_X, LINES_Y, str);
595 #else /* HAVE_LCD_CHARCELLS */
596 rb->snprintf (str, sizeof (str), "L%d/%d", level, lines);
597 rb->lcd_puts (5, 0, str);
598 rb->snprintf (str, sizeof (str), "S%d", score);
599 rb->lcd_puts (5, 1, str);
600 #endif
603 #ifdef HIGH_SCORE_Y
604 static void show_highscores (void)
606 int i;
607 char str[25]; /* for strings */
609 for (i = MAX_HIGH_SCORES-1; i>=0; i--)
611 rb->snprintf (str, sizeof (str), "%06d L%1d", Highest[i].score, Highest[i].level);
612 rb->lcd_putsxy (HIGH_LABEL_X, HIGH_SCORE_Y + (10 * ((MAX_HIGH_SCORES-1) - i)), str);
615 #endif
617 static void init_rockblox (void)
619 highscore_update(score, level, Highest, MAX_HIGH_SCORES);
621 level = 1;
622 lines = 0;
623 score = 0;
624 gameover = false;
625 nf = t_rand (BLOCKS_NUM);
626 init_board ();
627 #ifdef HAVE_LCD_BITMAP
628 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
629 #else /* HAVE_LCD_CHARCELLS */
630 pgfx_display (0, 0);
631 pgfx_display_block (3, 0, 3, 1);
632 pgfx_display_block (4, 0, 3, 0);
633 pgfx_clear_display();
634 pgfx_fillrect (3, 0, 2, 14);
635 pgfx_fillrect (15, 7, 2, 7);
636 pgfx_update();
637 #endif
638 show_details ();
639 #ifdef HIGH_SCORE_Y
640 show_highscores ();
641 #endif
644 static inline int level_speed(int level)
646 #if BOARD_HEIGHT == 20
647 return (5*HZ) / (level + 9);
648 #elif BOARD_HEIGHT == 14
649 return (7*HZ) / (level + 9);
650 #endif
653 static int getRelativeX (int figure, int square, int orientation)
655 switch (orientation) {
656 case 0:
657 return figures[figure].shapeX[square];
658 case 1:
659 return figures[figure].shapeY[square];
660 case 2:
661 return -figures[figure].shapeX[square];
662 case 3:
663 return -figures[figure].shapeY[square];
664 default:
665 return 0;
669 static int getRelativeY (int figure, int square, int orientation)
671 switch (orientation) {
672 case 0:
673 return figures[figure].shapeY[square];
674 case 1:
675 return -figures[figure].shapeX[square];
676 case 2:
677 return -figures[figure].shapeY[square];
678 case 3:
679 return figures[figure].shapeX[square];
680 default:
681 return 0;
685 /* redraw the while board on the screen */
686 static void refresh_board (void)
688 int i, j, x, y, block;
690 #if LCD_DEPTH >= 2
691 rb->lcd_set_foreground (LCD_BLACK);
692 #elif LCD_DEPTH == 1
693 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
694 #endif
696 MYLCD(fillrect) (BOARD_X, BOARD_Y, BOARD_WIDTH * BLOCK_WIDTH,
697 BOARD_HEIGHT * BLOCK_HEIGHT);
699 #if LCD_DEPTH == 1
700 MYLCD(set_drawmode) (DRMODE_SOLID);
701 #endif
703 for (i = 0; i < BOARD_WIDTH; i++)
704 for (j = 0; j < BOARD_HEIGHT; j++) {
705 block = board[j][i];
706 if (block != EMPTY_BLOCK) {
707 #ifdef HAVE_LCD_BITMAP
708 #if LCD_DEPTH >= 2
709 /* middle drawing */
710 rb->lcd_set_foreground (figures[block].color[1]);
711 #endif
712 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
713 BOARD_Y + j * BLOCK_HEIGHT,
714 BLOCK_WIDTH, BLOCK_HEIGHT);
715 #if LCD_DEPTH >= 2
716 /* light drawing */
717 rb->lcd_set_foreground (figures[block].color[0]);
718 #endif
719 rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH,
720 BOARD_Y + j * BLOCK_HEIGHT,
721 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2);
722 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH,
723 BOARD_X + (i + 1) * BLOCK_WIDTH - 2,
724 BOARD_Y + j * BLOCK_HEIGHT);
725 #if LCD_DEPTH >= 2
726 /* shadow drawing */
727 rb->lcd_set_foreground (figures[block].color[2]);
728 #endif
729 rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
730 BOARD_Y + j * BLOCK_HEIGHT + 1,
731 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
732 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1,
733 BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
734 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
735 #else /* HAVE_LCD_CHARCELLS */
736 pgfx_drawpixel (BOARD_X + i, BOARD_Y + j);
737 #endif
741 for (i = 0; i < 4; i++) {
742 x = getRelativeX (cf, i, co) + cx;
743 y = getRelativeY (cf, i, co) + cy;
744 #ifdef HAVE_LCD_BITMAP
745 #if LCD_DEPTH >= 2
746 rb->lcd_set_foreground (figures[cf].color[1]); /* middle drawing */
747 #endif
748 rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH,
749 BOARD_Y + y * BLOCK_HEIGHT,
750 BLOCK_WIDTH, BLOCK_HEIGHT);
751 #if LCD_DEPTH >= 2
752 rb->lcd_set_foreground (figures[cf].color[0]); /* light drawing */
753 #endif
754 rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT,
755 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2);
756 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH,
757 BOARD_X + (x + 1) * BLOCK_WIDTH - 2,
758 BOARD_Y + y * BLOCK_HEIGHT);
759 #if LCD_DEPTH >= 2
760 rb->lcd_set_foreground (figures[cf].color[2]); /* shadow drawing */
761 #endif
762 rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
763 BOARD_Y + y * BLOCK_HEIGHT + 1,
764 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
765 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1,
766 BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
767 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
768 #else /* HAVE_LCD_CHARCELLS */
769 pgfx_drawpixel (BOARD_X + x, BOARD_Y + y);
770 #endif
772 MYLCD(update) ();
775 static bool canMoveTo (int x, int y, int newOrientation)
777 int i, rx, ry;
778 for (i = 0; i < 4; i++) {
779 ry = getRelativeY (cf, i, newOrientation) + y;
780 rx = getRelativeX (cf, i, newOrientation) + x;
781 if ((rx < 0 || rx >= BOARD_WIDTH) ||
782 (ry < 0 || ry >= BOARD_HEIGHT) || (board[ry][rx] != EMPTY_BLOCK))
783 return false;
785 return true;
788 /* draws the preview of next block in the preview window */
789 static void draw_next_block (void)
791 int i, rx, ry;
792 /* clear preview window first */
793 #if LCD_DEPTH >= 2
794 rb->lcd_set_foreground (LCD_BLACK);
795 #elif LCD_DEPTH == 1
796 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
797 #endif
799 /* 4x4 */
800 MYLCD(fillrect) (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4);
802 #if LCD_DEPTH == 1
803 MYLCD(set_drawmode) (DRMODE_SOLID);
804 #endif
806 /* draw the lightgray rectangles */
807 #if LCD_DEPTH >= 16
808 rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
809 #elif LCD_DEPTH == 2
810 rb->lcd_set_foreground (LCD_DARKGRAY);
811 #endif
813 #if LCD_DEPTH >= 2
814 for (rx = 0; rx < 4; rx++)
815 for (ry = 0; ry < 4; ry++)
816 rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH,
817 PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH,
818 BLOCK_HEIGHT);
819 #endif
821 /* draw the figure */
822 for (i = 0; i < 4; i++) {
823 rx = getRelativeX (nf, i, 0) + 2;
824 ry = getRelativeY (nf, i, 0) + 2;
825 #ifdef HAVE_LCD_BITMAP
826 #if LCD_DEPTH >= 2
827 rb->lcd_set_foreground (figures[nf].color[1]); /* middle drawing */
828 #endif
829 rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH,
830 PREVIEW_Y + ry * BLOCK_HEIGHT,
831 BLOCK_WIDTH, BLOCK_HEIGHT);
832 #if LCD_DEPTH >= 2
833 rb->lcd_set_foreground (figures[nf].color[0]); /* light drawing */
834 #endif
835 rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH,
836 PREVIEW_Y + ry * BLOCK_HEIGHT,
837 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2);
838 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH,
839 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2,
840 PREVIEW_Y + ry * BLOCK_HEIGHT);
841 #if LCD_DEPTH >= 2
842 rb->lcd_set_foreground (figures[nf].color[2]); /* shadow drawing */
843 #endif
844 rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
845 PREVIEW_Y + ry * BLOCK_HEIGHT + 1,
846 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
847 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1,
848 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
849 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
850 #else /* HAVE_LCD_CHARCELLS */
851 pgfx_drawpixel (PREVIEW_X + rx, PREVIEW_Y + ry);
852 #endif
857 /* move the block to a relative location */
858 static void move_block (int x, int y, int o)
860 if (canMoveTo (cx + x, cy + y, o)) {
861 cy += y;
862 cx += x;
863 co = o;
867 /* try to add a new block to play with (return true if gameover) */
868 static void new_block (void)
870 cy = 1;
871 cx = 5;
872 cf = nf;
873 co = 0; /* start at the same orientation all time */
874 nf = t_rand (BLOCKS_NUM);
875 gameover = !canMoveTo (cx, cy, co);
877 draw_next_block ();
881 /* check for filled lines and do what necessary */
882 static int check_lines (void)
884 int i, j, y;
885 int rockblox = 0;
887 for (j = 0; j < BOARD_HEIGHT; j++) {
888 for (i = 0; ((i < BOARD_WIDTH) && (board[j][i] != EMPTY_BLOCK)); i++);
889 if (i == BOARD_WIDTH) { /* woo hoo, we have a line */
890 rockblox++;
891 for (y = j; y > 0; y--)
892 for (i = 0; i < BOARD_WIDTH; i++)
893 board[y][i] = board[y - 1][i]; /* fall line */
897 return rockblox;
900 /* moves down the figure and returns true if gameover */
901 static void move_down (void)
903 int l, i, rx, ry;
905 if (!canMoveTo (cx, cy + 1, co)) {
906 /* save figure to board */
907 for (i = 0; i < 4; i++) {
908 rx = getRelativeX (cf, i, co) + cx;
909 ry = getRelativeY (cf, i, co) + cy;
910 board[ry][rx] = cf;
912 /* check if formed some lines */
913 l = check_lines ();
914 if (l) {
915 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
916 score += scoring[l - 1] * level;
917 lines += l;
918 level = (int) lines / 10 + 1;
921 /* show details */
922 show_details ();
924 /* generate a new figure */
925 new_block ();
926 } else
927 move_block (0, 1, co);
930 static int rockblox_loop (void)
932 int button;
933 int lastbutton = BUTTON_NONE;
934 long next_down_tick = *rb->current_tick + level_speed(level);
936 new_block ();
938 while (1) {
939 #ifdef HAS_BUTTON_HOLD
940 if (rb->button_hold ()) {
941 /* Turn on backlight timeout (revert to settings) */
942 backlight_use_settings(rb); /* backlight control in lib/helper.c */
943 rb->splash(0, "Paused");
944 while (rb->button_hold ())
945 rb->sleep(HZ/10);
947 /* Turn off backlight timeout */
948 backlight_force_on(rb); /* backlight control in lib/helper.c */
950 /* get rid of the splash text */
951 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
952 show_details ();
953 #ifdef HIGH_SCORE_Y
954 show_highscores ();
955 #endif
956 draw_next_block ();
957 refresh_board ();
959 #endif
961 button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1));
962 switch (button) {
963 #ifdef ROCKBLOX_RC_OFF
964 case ROCKBLOX_RC_OFF:
965 #endif
966 case ROCKBLOX_OFF:
967 return PLUGIN_OK;
969 #if defined(ROCKBLOX_ROTATE)
970 case ROCKBLOX_ROTATE:
971 #endif
972 case ROCKBLOX_ROTATE_RIGHT:
973 case ROCKBLOX_ROTATE_RIGHT | BUTTON_REPEAT:
974 #ifdef SCROLL_WHEEL
975 /* if the wheel is disabled, add an event to the stack. */
976 if(wheel_enabled == false)
977 wheel_events++;
979 /* if it's enabled, go ahead and rotate.. */
980 if(wheel_enabled)
981 #endif
982 move_block (0, 0, (co + 1) % figures[cf].max_or);
983 break;
985 case ROCKBLOX_ROTATE_LEFT:
986 case ROCKBLOX_ROTATE_LEFT | BUTTON_REPEAT:
987 #ifdef SCROLL_WHEEL
988 if(wheel_enabled == false)
989 wheel_events++;
991 if(wheel_enabled)
992 #endif
993 move_block (0, 0,
994 (co + figures[cf].max_or -
995 1) % figures[cf].max_or);
996 break;
998 #ifdef ROCKBLOX_ROTATE_RIGHT2
999 case ROCKBLOX_ROTATE_RIGHT2:
1000 move_block (0, 0, (co + 1) % figures[cf].max_or);
1001 break;
1002 #endif
1004 case ROCKBLOX_DOWN:
1005 case ROCKBLOX_DOWN | BUTTON_REPEAT:
1006 move_block (0, 1, co);
1007 break;
1009 case ROCKBLOX_RIGHT:
1010 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
1011 move_block (1, 0, co);
1012 break;
1014 case ROCKBLOX_LEFT:
1015 case ROCKBLOX_LEFT | BUTTON_REPEAT:
1016 move_block (-1, 0, co);
1017 break;
1019 case ROCKBLOX_DROP:
1020 #ifdef ROCKBLOX_DROP_PRE
1021 if (lastbutton != ROCKBLOX_DROP_PRE)
1022 break;
1023 #endif
1024 while (canMoveTo (cx, cy + 1, co))
1025 move_block (0, 1, co);
1026 break;
1027 #ifdef ROCKBLOX_RESTART
1028 case ROCKBLOX_RESTART:
1029 rb->splash (HZ * 1, "Restarting...");
1030 init_rockblox ();
1031 new_block ();
1032 break;
1033 #endif
1035 default:
1036 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
1037 return PLUGIN_USB_CONNECTED;
1038 break;
1040 if (button != BUTTON_NONE)
1041 lastbutton = button;
1043 #ifdef SCROLL_WHEEL
1044 /* check if we should enable the scroll wheel, if events
1045 * begin to stack up... */
1046 if(wheel_enabled == false)
1048 /* stopped rotating the wheel, reset the count */
1049 if(wheel_events == last_wheel_event)
1051 last_wheel_event = 0;
1052 wheel_events = 0;
1054 /* rotated the wheel a while constantly, enable it. */
1055 else if(wheel_events > 3)
1057 wheel_enabled = true;
1060 /* this evens out the last event and the "current" event.
1061 * if we get an event next time through button reading, it will
1062 * remain ahead of last_event. if we don't, they'll end up equaling
1063 * each other.. thus, the scroll count will be reset. */
1064 if(wheel_enabled == false && wheel_events > last_wheel_event)
1065 last_wheel_event++;
1067 #endif
1069 if (TIME_AFTER(*rb->current_tick, next_down_tick)) {
1070 move_down ();
1071 next_down_tick += level_speed(level);
1072 if (TIME_AFTER(*rb->current_tick, next_down_tick))
1073 /* restart time "raster" when we had to wait longer than usual
1074 * (pause, game restart etc) */
1075 next_down_tick = *rb->current_tick + level_speed(level);
1078 if (gameover) {
1079 #if LCD_DEPTH >= 2
1080 rb->lcd_set_foreground (LCD_BLACK);
1081 #endif
1082 rb->splash (HZ * 2, "Game Over");
1083 init_rockblox ();
1084 new_block ();
1087 refresh_board ();
1090 return PLUGIN_OK;
1093 enum plugin_status plugin_start (struct plugin_api *api, void *parameter)
1095 int ret;
1097 (void) parameter;
1098 rb = api;
1100 rb->srand (*rb->current_tick);
1102 /* Load HighScore if any */
1103 highscore_init(rb);
1104 highscore_load(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1106 #if LCD_DEPTH > 1
1107 rb->lcd_set_backdrop(NULL);
1108 #endif
1110 #ifdef HAVE_LCD_BITMAP
1111 rb->lcd_setfont (FONT_SYSFIXED);
1112 #else
1113 if (!pgfx_init(rb, 4, 2))
1115 rb->splash(HZ*2, "Old LCD :(");
1116 return PLUGIN_OK;
1118 #endif
1119 /* Turn off backlight timeout */
1120 backlight_force_on(rb); /* backlight control in lib/helper.c */
1122 init_rockblox ();
1123 ret = rockblox_loop ();
1125 #ifdef HAVE_LCD_BITMAP
1126 rb->lcd_setfont (FONT_UI);
1127 #else
1128 pgfx_release();
1129 #endif
1130 /* Save user's HighScore */
1131 highscore_save(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1132 backlight_use_settings(rb); /* backlight control in lib/helper.c */
1134 return ret;