use the list context in credits which has to be defined for every target
[Rockbox.git] / apps / plugins / rockblox.c
blob0b3382ff190f2ba834ad2e2c6c18e814878d939e
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_UP
117 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_DOWN
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 #endif
172 #define BLOCKS_NUM 7
173 #define EMPTY_BLOCK 7
175 #define BOARD_WIDTH 10
177 #ifdef HAVE_LCD_BITMAP
179 #define BOARD_HEIGHT 20
181 #if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
183 #define BLOCK_WIDTH 12
184 #define BLOCK_HEIGHT 12
185 #define BOARD_X 86
186 #define BOARD_Y 0
187 #define PREVIEW_X 12
188 #define PREVIEW_Y 11
189 #define LABEL_X 242
190 #define SCORE_Y 25
191 #define LEVEL_Y 70
192 #define LINES_Y 105
194 #elif (LCD_WIDTH == 240) && (LCD_HEIGHT == 320)
196 #define BLOCK_WIDTH 15
197 #define BLOCK_HEIGHT 15
198 #define BOARD_X 7
199 #define BOARD_Y 1
200 #define PREVIEW_X 171
201 #define PREVIEW_Y 241
202 #define LABEL_X 172
203 #define SCORE_Y 29
204 #define LEVEL_Y 71
205 #define LINES_Y 109
206 #define HIGH_LABEL_X 172
207 #define HIGH_SCORE_Y 163
208 #define HIGH_LEVEL_Y 172
210 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
212 #define BLOCK_WIDTH 8
213 #define BLOCK_HEIGHT 8
214 #define BOARD_X 27
215 #define BOARD_Y 5
216 #define PREVIEW_X 158
217 #define PREVIEW_Y 130
218 #define LABEL_X 147
219 #define SCORE_Y 20
220 #define LEVEL_Y 65
221 #define LINES_Y 100
223 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
225 #define BLOCK_WIDTH 6
226 #define BLOCK_HEIGHT 6
227 #define BOARD_X 25
228 #define BOARD_Y 1
229 #define PREVIEW_X 126
230 #define PREVIEW_Y 102
231 #define LABEL_X 112
232 #define SCORE_Y 17
233 #define LEVEL_Y 49
234 #define LINES_Y 81
236 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
238 #define BLOCK_WIDTH 10
239 #define BLOCK_HEIGHT 10
240 #define BOARD_X 6
241 #define BOARD_Y 10
242 #define PREVIEW_X 124
243 #define PREVIEW_Y 167
244 #define LABEL_X 117
245 #define SCORE_Y 24
246 #define LEVEL_Y 65
247 #define LINES_Y 103
248 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
250 #define BLOCK_WIDTH 6
251 #define BLOCK_HEIGHT 6
252 #define BOARD_X 22
253 #define BOARD_Y 3
254 #define PREVIEW_X 114
255 #define PREVIEW_Y 100
256 #define LABEL_X 101
257 #define SCORE_Y 17
258 #define LEVEL_Y 49
259 #define LINES_Y 82
261 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
263 #define BLOCK_WIDTH 6
264 #define BLOCK_HEIGHT 6
265 #define BOARD_X 4
266 #define BOARD_Y 3
267 #define PREVIEW_X 84
268 #define PREVIEW_Y 100
269 #define LABEL_X 71
270 #define SCORE_Y 17
271 #define LEVEL_Y 49
272 #define LINES_Y 82
274 #elif (LCD_WIDTH == 132) && (LCD_HEIGHT == 80)
276 #define BLOCK_WIDTH 4
277 #define BLOCK_HEIGHT 4
278 #define BOARD_X 10
279 #define BOARD_Y 0
280 #define PREVIEW_X 89
281 #define PREVIEW_Y 61
282 #define LABEL_X 78
283 #define SCORE_Y 10
284 #define LEVEL_Y 30
285 #define LINES_Y 50
287 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 64)
289 #define BLOCK_WIDTH 3
290 #define BLOCK_HEIGHT 3
291 #define BOARD_X 9
292 #define BOARD_Y 3
293 #define PREVIEW_X 53
294 #define PREVIEW_Y 5
295 #define LABEL_X 70
296 #define SCORE_Y 32
297 #define LEVEL_Y 13
298 #define LINES_Y 51
300 #elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
302 #define BLOCK_WIDTH 4
303 #define BLOCK_HEIGHT 3
304 #define BOARD_X 9
305 #define BOARD_Y 3
306 #define PREVIEW_X 59
307 #define PREVIEW_Y 5
308 #define LABEL_X 59
309 #define SCORE_Y 32
310 #define LEVEL_Y 13
311 #define LEVEL_X 78
312 #define LINES_Y 51
314 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
316 #define BLOCK_WIDTH 5
317 #define BLOCK_HEIGHT 5
318 #define BOARD_X 14
319 #define BOARD_Y 0
320 #define PREVIEW_X 98
321 #define PREVIEW_Y 88
322 #define LABEL_X 80
323 #define SCORE_Y 15
324 #define LEVEL_Y 45
325 #define LINES_Y 74
327 #endif
329 #ifndef LEVEL_X
330 #define LEVEL_X LABEL_X
331 #endif
333 #ifndef LINES_X
334 #define LINES_X LABEL_X
335 #endif
337 #define MYLCD(fn) rb->lcd_ ## fn
339 extern const fb_data rockblox_background[];
341 #else /* HAVE_LCD_CHARCELLS */
343 #define BOARD_HEIGHT 14
345 #define BLOCK_WIDTH 1
346 #define BLOCK_HEIGHT 1
347 #define BOARD_X 5
348 #define BOARD_Y 0
349 #define PREVIEW_X 15
350 #define PREVIEW_Y 1
352 #define MYLCD(fn) pgfx_ ## fn
354 #endif
356 /* <<Explanation on Rockblox shapes>>
359 %% - O has 1 orientation
361 %% %
362 %% %% - Z has 2 orientations
365 %% %
366 %% %% - S has 2 orientations
370 % %%%% - I has 2 orientations
373 % %%
374 % % % %%% - L has 4 orientations
375 %% %%% % %
377 % %%s
378 % % % %%% - J has 4 orientations
379 %% %%% % %
381 % % %%%
382 %% % %% % - T has 4 orientations
383 % %%% %
387 /* must have variable */
388 static struct plugin_api *rb;
390 static bool gameover = false;
391 /* c=current f=figure o=orientation n=next */
392 static int lines = 0, level = 0, score = 0, cx, cy, cf, co, nf;
393 static short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */
395 #ifdef SCROLL_WHEEL
396 int wheel_events = 0, last_wheel_event = 0;
397 bool wheel_enabled = false;
398 #endif
400 static const short scoring[4] = { /* scoring for each number of lines */
401 #if BOARD_HEIGHT == 20
402 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
403 #elif BOARD_HEIGHT == 14 /* Player special values */
404 60 /* single */ , 150 /* double */ , 500 /* triple */ , 2000 /* rockblox */
405 #endif
408 struct figure
410 #if LCD_DEPTH >= 2
411 unsigned short color[3]; /* color of figure (light,middle,shadow) */
412 #endif
413 unsigned short max_or; /* max orientations */
414 signed short shapeX[4], shapeY[4]; /* implementation of figures */
417 /* array of figures */
418 figures[BLOCKS_NUM] = {
419 /* O */
421 #if LCD_DEPTH >= 16
422 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
423 LCD_RGBPACK(0,153,153)},
424 #elif LCD_DEPTH == 2
425 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
426 #endif
428 {-1, 0, -1, 0},
429 {0, 0, 1, 1}
431 /* I */
433 #if LCD_DEPTH >= 16
434 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
435 LCD_RGBPACK (153, 0, 0)},
436 #elif LCD_DEPTH == 2
437 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
438 #endif
440 {-2, -1, 0, 1},
441 {0, 0, 0, 0}
443 /* 'Z' */
445 #if LCD_DEPTH >= 16
446 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
447 LCD_RGBPACK (0, 153, 0)},
448 #elif LCD_DEPTH == 2
449 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
450 #endif
452 {0, 1, -1, 0},
453 {0, 0, 1, 1}
455 /* 'S' */
457 #if LCD_DEPTH >= 16
458 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
459 LCD_RGBPACK (0, 0, 153)},
460 #elif LCD_DEPTH == 2
461 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
462 #endif
464 {-1, 0, 0, 1},
465 {0, 0, 1, 1}
467 /* 'L' */
469 #if LCD_DEPTH >= 16
470 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
471 LCD_RGBPACK (153, 153, 0)},
472 #elif LCD_DEPTH == 2
473 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
474 #endif
476 {-1, 0, 1, 1},
477 {0, 0, 0, 1}
479 /* 'J' */
481 #if LCD_DEPTH >= 16
482 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
483 LCD_RGBPACK (153, 0, 153)},
484 #elif LCD_DEPTH == 2
485 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
486 #endif
488 {-1, 0, 1, -1},
489 {0, 0, 0, 1}
491 /* 'T' */
493 #if LCD_DEPTH >= 16
494 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
495 LCD_RGBPACK (85, 85, 85)},
496 #elif LCD_DEPTH == 2
497 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
498 #endif
500 {-1, 0, 1, 0},
501 {0, 0, 0, 1}
505 /* Rockbox File System only supports full filenames inc dir */
506 #define HIGH_SCORE PLUGIN_GAMES_DIR "/rockblox.score"
507 #define MAX_HIGH_SCORES 5
508 /* Default High Scores... */
509 struct highscore Highest[MAX_HIGH_SCORES];
511 /* get random number from (0) to (range-1) */
512 static int t_rand (int range)
514 return rb->rand () % range;
517 /* init the board array to have no blocks */
518 static void init_board (void)
520 int i, j;
521 for (i = 0; i < BOARD_WIDTH; i++)
522 for (j = 0; j < BOARD_HEIGHT; j++)
523 board[j][i] = EMPTY_BLOCK;
526 /* show the score, level and lines */
527 static void show_details (void)
529 char str[25]; /* for strings */
531 #ifdef HAVE_LCD_BITMAP
532 #if LCD_DEPTH >= 2
533 rb->lcd_set_foreground (LCD_BLACK);
534 rb->lcd_set_background (LCD_WHITE);
535 #endif
536 rb->snprintf (str, sizeof (str), "%d", score);
537 rb->lcd_putsxy (LABEL_X, SCORE_Y, str);
538 rb->snprintf (str, sizeof (str), "%d", level);
539 rb->lcd_putsxy (LEVEL_X, LEVEL_Y, str);
540 rb->snprintf (str, sizeof (str), "%d", lines);
541 rb->lcd_putsxy (LINES_X, LINES_Y, str);
542 #else /* HAVE_LCD_CHARCELLS */
543 rb->snprintf (str, sizeof (str), "L%d/%d", level, lines);
544 rb->lcd_puts (5, 0, str);
545 rb->snprintf (str, sizeof (str), "S%d", score);
546 rb->lcd_puts (5, 1, str);
547 #endif
550 static void init_rockblox (void)
552 #ifdef HIGH_SCORE_Y
553 int i;
554 char str[25]; /* for strings */
555 #endif
556 highscore_update(score, level, Highest, MAX_HIGH_SCORES);
558 level = 1;
559 lines = 0;
560 score = 0;
561 gameover = false;
562 nf = t_rand (BLOCKS_NUM);
563 init_board ();
564 #ifdef HAVE_LCD_BITMAP
565 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
566 #else /* HAVE_LCD_CHARCELLS */
567 pgfx_display (0, 0);
568 pgfx_display_block (3, 0, 3, 1);
569 pgfx_display_block (4, 0, 3, 0);
570 pgfx_clear_display();
571 pgfx_fillrect (3, 0, 2, 14);
572 pgfx_fillrect (15, 7, 2, 7);
573 pgfx_update();
574 #endif
575 show_details ();
576 #ifdef HIGH_SCORE_Y
577 for (i = MAX_HIGH_SCORES-1; i>=0; i--)
579 rb->snprintf (str, sizeof (str), "%06d L%1d", Highest[i].score, Highest[i].level);
580 rb->lcd_putsxy (HIGH_LABEL_X, HIGH_SCORE_Y + (10 * ((MAX_HIGH_SCORES-1) - i)), str);
582 #endif
585 static inline int level_speed(int level)
587 #if BOARD_HEIGHT == 20
588 return (5*HZ) / (level + 9);
589 #elif BOARD_HEIGHT == 14
590 return (7*HZ) / (level + 9);
591 #endif
594 static int getRelativeX (int figure, int square, int orientation)
596 switch (orientation) {
597 case 0:
598 return figures[figure].shapeX[square];
599 case 1:
600 return figures[figure].shapeY[square];
601 case 2:
602 return -figures[figure].shapeX[square];
603 case 3:
604 return -figures[figure].shapeY[square];
605 default:
606 return 0;
610 static int getRelativeY (int figure, int square, int orientation)
612 switch (orientation) {
613 case 0:
614 return figures[figure].shapeY[square];
615 case 1:
616 return -figures[figure].shapeX[square];
617 case 2:
618 return -figures[figure].shapeY[square];
619 case 3:
620 return figures[figure].shapeX[square];
621 default:
622 return 0;
626 /* redraw the while board on the screen */
627 static void refresh_board (void)
629 int i, j, x, y, block;
631 #if LCD_DEPTH >= 2
632 rb->lcd_set_foreground (LCD_BLACK);
633 #elif LCD_DEPTH == 1
634 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
635 #endif
637 MYLCD(fillrect) (BOARD_X, BOARD_Y, BOARD_WIDTH * BLOCK_WIDTH,
638 BOARD_HEIGHT * BLOCK_HEIGHT);
640 #if LCD_DEPTH == 1
641 MYLCD(set_drawmode) (DRMODE_SOLID);
642 #endif
644 for (i = 0; i < BOARD_WIDTH; i++)
645 for (j = 0; j < BOARD_HEIGHT; j++) {
646 block = board[j][i];
647 if (block != EMPTY_BLOCK) {
648 #ifdef HAVE_LCD_BITMAP
649 #if LCD_DEPTH >= 2
650 /* middle drawing */
651 rb->lcd_set_foreground (figures[block].color[1]);
652 #endif
653 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
654 BOARD_Y + j * BLOCK_HEIGHT,
655 BLOCK_WIDTH, BLOCK_HEIGHT);
656 #if LCD_DEPTH >= 2
657 /* light drawing */
658 rb->lcd_set_foreground (figures[block].color[0]);
659 #endif
660 rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH,
661 BOARD_Y + j * BLOCK_HEIGHT,
662 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2);
663 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH,
664 BOARD_X + (i + 1) * BLOCK_WIDTH - 2,
665 BOARD_Y + j * BLOCK_HEIGHT);
666 #if LCD_DEPTH >= 2
667 /* shadow drawing */
668 rb->lcd_set_foreground (figures[block].color[2]);
669 #endif
670 rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
671 BOARD_Y + j * BLOCK_HEIGHT + 1,
672 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
673 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1,
674 BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
675 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
676 #else /* HAVE_LCD_CHARCELLS */
677 pgfx_drawpixel (BOARD_X + i, BOARD_Y + j);
678 #endif
682 for (i = 0; i < 4; i++) {
683 x = getRelativeX (cf, i, co) + cx;
684 y = getRelativeY (cf, i, co) + cy;
685 #ifdef HAVE_LCD_BITMAP
686 #if LCD_DEPTH >= 2
687 rb->lcd_set_foreground (figures[cf].color[1]); /* middle drawing */
688 #endif
689 rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH,
690 BOARD_Y + y * BLOCK_HEIGHT,
691 BLOCK_WIDTH, BLOCK_HEIGHT);
692 #if LCD_DEPTH >= 2
693 rb->lcd_set_foreground (figures[cf].color[0]); /* light drawing */
694 #endif
695 rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT,
696 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2);
697 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH,
698 BOARD_X + (x + 1) * BLOCK_WIDTH - 2,
699 BOARD_Y + y * BLOCK_HEIGHT);
700 #if LCD_DEPTH >= 2
701 rb->lcd_set_foreground (figures[cf].color[2]); /* shadow drawing */
702 #endif
703 rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
704 BOARD_Y + y * BLOCK_HEIGHT + 1,
705 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
706 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1,
707 BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
708 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
709 #else /* HAVE_LCD_CHARCELLS */
710 pgfx_drawpixel (BOARD_X + x, BOARD_Y + y);
711 #endif
713 MYLCD(update) ();
716 static bool canMoveTo (int x, int y, int newOrientation)
718 int i, rx, ry;
719 for (i = 0; i < 4; i++) {
720 ry = getRelativeY (cf, i, newOrientation) + y;
721 rx = getRelativeX (cf, i, newOrientation) + x;
722 if ((rx < 0 || rx >= BOARD_WIDTH) ||
723 (ry < 0 || ry >= BOARD_HEIGHT) || (board[ry][rx] != EMPTY_BLOCK))
724 return false;
726 return true;
729 /* draws the preview of next block in the preview window */
730 static void draw_next_block (void)
732 int i, rx, ry;
733 /* clear preview window first */
734 #if LCD_DEPTH >= 2
735 rb->lcd_set_foreground (LCD_BLACK);
736 #elif LCD_DEPTH == 1
737 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
738 #endif
740 /* 4x4 */
741 MYLCD(fillrect) (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4);
743 #if LCD_DEPTH == 1
744 MYLCD(set_drawmode) (DRMODE_SOLID);
745 #endif
747 /* draw the lightgray rectangles */
748 #if LCD_DEPTH >= 16
749 rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
750 #elif LCD_DEPTH == 2
751 rb->lcd_set_foreground (LCD_DARKGRAY);
752 #endif
754 #if LCD_DEPTH >= 2
755 for (rx = 0; rx < 4; rx++)
756 for (ry = 0; ry < 4; ry++)
757 rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH,
758 PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH,
759 BLOCK_HEIGHT);
760 #endif
762 /* draw the figure */
763 for (i = 0; i < 4; i++) {
764 rx = getRelativeX (nf, i, 0) + 2;
765 ry = getRelativeY (nf, i, 0) + 2;
766 #ifdef HAVE_LCD_BITMAP
767 #if LCD_DEPTH >= 2
768 rb->lcd_set_foreground (figures[nf].color[1]); /* middle drawing */
769 #endif
770 rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH,
771 PREVIEW_Y + ry * BLOCK_HEIGHT,
772 BLOCK_WIDTH, BLOCK_HEIGHT);
773 #if LCD_DEPTH >= 2
774 rb->lcd_set_foreground (figures[nf].color[0]); /* light drawing */
775 #endif
776 rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH,
777 PREVIEW_Y + ry * BLOCK_HEIGHT,
778 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2);
779 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH,
780 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2,
781 PREVIEW_Y + ry * BLOCK_HEIGHT);
782 #if LCD_DEPTH >= 2
783 rb->lcd_set_foreground (figures[nf].color[2]); /* shadow drawing */
784 #endif
785 rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
786 PREVIEW_Y + ry * BLOCK_HEIGHT + 1,
787 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
788 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1,
789 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
790 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
791 #else /* HAVE_LCD_CHARCELLS */
792 pgfx_drawpixel (PREVIEW_X + rx, PREVIEW_Y + ry);
793 #endif
798 /* move the block to a relative location */
799 static void move_block (int x, int y, int o)
801 if (canMoveTo (cx + x, cy + y, o)) {
802 cy += y;
803 cx += x;
804 co = o;
808 /* try to add a new block to play with (return true if gameover) */
809 static void new_block (void)
811 cy = 1;
812 cx = 5;
813 cf = nf;
814 co = 0; /* start at the same orientation all time */
815 nf = t_rand (BLOCKS_NUM);
816 gameover = !canMoveTo (cx, cy, co);
818 draw_next_block ();
822 /* check for filled lines and do what necessary */
823 static int check_lines (void)
825 int i, j, y;
826 int rockblox = 0;
828 for (j = 0; j < BOARD_HEIGHT; j++) {
829 for (i = 0; ((i < BOARD_WIDTH) && (board[j][i] != EMPTY_BLOCK)); i++);
830 if (i == BOARD_WIDTH) { /* woo hoo, we have a line */
831 rockblox++;
832 for (y = j; y > 0; y--)
833 for (i = 0; i < BOARD_WIDTH; i++)
834 board[y][i] = board[y - 1][i]; /* fall line */
838 return rockblox;
841 /* moves down the figure and returns true if gameover */
842 static void move_down (void)
844 int l, i, rx, ry;
846 if (!canMoveTo (cx, cy + 1, co)) {
847 /* save figure to board */
848 for (i = 0; i < 4; i++) {
849 rx = getRelativeX (cf, i, co) + cx;
850 ry = getRelativeY (cf, i, co) + cy;
851 board[ry][rx] = cf;
853 /* check if formed some lines */
854 l = check_lines ();
855 if (l) {
856 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
857 score += scoring[l - 1] * level;
858 lines += l;
859 level = (int) lines / 10 + 1;
862 /* show details */
863 show_details ();
865 /* generate a new figure */
866 new_block ();
867 } else
868 move_block (0, 1, co);
871 static int rockblox_loop (void)
873 int button;
874 int lastbutton = BUTTON_NONE;
875 long next_down_tick = *rb->current_tick + level_speed(level);
877 new_block ();
879 while (1) {
880 #ifdef HAS_BUTTON_HOLD
881 if (rb->button_hold ()) {
882 /* Turn on backlight timeout (revert to settings) */
883 backlight_use_settings(rb); /* backlight control in lib/helper.c */
884 rb->splash(0, "Paused");
885 while (rb->button_hold ())
886 rb->sleep(HZ/10);
888 /* Turn off backlight timeout */
889 backlight_force_on(rb); /* backlight control in lib/helper.c */
891 /* get rid of the splash text */
892 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
893 show_details ();
894 draw_next_block ();
895 refresh_board ();
897 #endif
899 button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1));
900 switch (button) {
901 #ifdef ROCKBLOX_RC_OFF
902 case ROCKBLOX_RC_OFF:
903 #endif
904 case ROCKBLOX_OFF:
905 return PLUGIN_OK;
907 #if defined(ROCKBLOX_ROTATE)
908 case ROCKBLOX_ROTATE:
909 #endif
910 case ROCKBLOX_ROTATE_RIGHT:
911 case ROCKBLOX_ROTATE_RIGHT | BUTTON_REPEAT:
912 #ifdef SCROLL_WHEEL
913 /* if the wheel is disabled, add an event to the stack. */
914 if(wheel_enabled == false)
915 wheel_events++;
917 /* if it's enabled, go ahead and rotate.. */
918 if(wheel_enabled)
919 #endif
920 move_block (0, 0, (co + 1) % figures[cf].max_or);
921 break;
923 case ROCKBLOX_ROTATE_LEFT:
924 case ROCKBLOX_ROTATE_LEFT | BUTTON_REPEAT:
925 #ifdef SCROLL_WHEEL
926 if(wheel_enabled == false)
927 wheel_events++;
929 if(wheel_enabled)
930 #endif
931 move_block (0, 0,
932 (co + figures[cf].max_or -
933 1) % figures[cf].max_or);
934 break;
936 #ifdef ROCKBLOX_ROTATE_RIGHT2
937 case ROCKBLOX_ROTATE_RIGHT2:
938 move_block (0, 0, (co + 1) % figures[cf].max_or);
939 break;
940 #endif
942 case ROCKBLOX_DOWN:
943 case ROCKBLOX_DOWN | BUTTON_REPEAT:
944 move_block (0, 1, co);
945 break;
947 case ROCKBLOX_RIGHT:
948 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
949 move_block (1, 0, co);
950 break;
952 case ROCKBLOX_LEFT:
953 case ROCKBLOX_LEFT | BUTTON_REPEAT:
954 move_block (-1, 0, co);
955 break;
957 case ROCKBLOX_DROP:
958 #ifdef ROCKBLOX_DROP_PRE
959 if (lastbutton != ROCKBLOX_DROP_PRE)
960 break;
961 #endif
962 while (canMoveTo (cx, cy + 1, co))
963 move_block (0, 1, co);
964 break;
965 #ifdef ROCKBLOX_RESTART
966 case ROCKBLOX_RESTART:
967 rb->splash (HZ * 1, "Restarting...");
968 init_rockblox ();
969 new_block ();
970 break;
971 #endif
973 default:
974 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
975 return PLUGIN_USB_CONNECTED;
976 break;
978 if (button != BUTTON_NONE)
979 lastbutton = button;
981 #ifdef SCROLL_WHEEL
982 /* check if we should enable the scroll wheel, if events
983 * begin to stack up... */
984 if(wheel_enabled == false)
986 /* stopped rotating the wheel, reset the count */
987 if(wheel_events == last_wheel_event)
989 last_wheel_event = 0;
990 wheel_events = 0;
992 /* rotated the wheel a while constantly, enable it. */
993 else if(wheel_events > 3)
995 wheel_enabled = true;
998 /* this evens out the last event and the "current" event.
999 * if we get an event next time through button reading, it will
1000 * remain ahead of last_event. if we don't, they'll end up equaling
1001 * each other.. thus, the scroll count will be reset. */
1002 if(wheel_enabled == false && wheel_events > last_wheel_event)
1003 last_wheel_event++;
1005 #endif
1007 if (TIME_AFTER(*rb->current_tick, next_down_tick)) {
1008 move_down ();
1009 next_down_tick += level_speed(level);
1010 if (TIME_AFTER(*rb->current_tick, next_down_tick))
1011 /* restart time "raster" when we had to wait longer than usual
1012 * (pause, game restart etc) */
1013 next_down_tick = *rb->current_tick + level_speed(level);
1016 if (gameover) {
1017 #if LCD_DEPTH >= 2
1018 rb->lcd_set_foreground (LCD_BLACK);
1019 #endif
1020 rb->splash (HZ * 2, "Game Over");
1021 init_rockblox ();
1022 new_block ();
1025 refresh_board ();
1028 return PLUGIN_OK;
1031 enum plugin_status plugin_start (struct plugin_api *api, void *parameter)
1033 int ret;
1035 (void) parameter;
1036 rb = api;
1038 rb->srand (*rb->current_tick);
1040 /* Load HighScore if any */
1041 highscore_init(rb);
1042 highscore_load(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1044 #if LCD_DEPTH > 1
1045 rb->lcd_set_backdrop(NULL);
1046 #endif
1048 #ifdef HAVE_LCD_BITMAP
1049 rb->lcd_setfont (FONT_SYSFIXED);
1050 #else
1051 if (!pgfx_init(rb, 4, 2))
1053 rb->splash(HZ*2, "Old LCD :(");
1054 return PLUGIN_OK;
1056 #endif
1057 /* Turn off backlight timeout */
1058 backlight_force_on(rb); /* backlight control in lib/helper.c */
1060 init_rockblox ();
1061 ret = rockblox_loop ();
1063 #ifdef HAVE_LCD_BITMAP
1064 rb->lcd_setfont (FONT_UI);
1065 #else
1066 pgfx_release();
1067 #endif
1068 /* Save user's HighScore */
1069 highscore_save(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1070 /* Restore user's original backlight setting */
1071 rb->backlight_set_timeout (rb->global_settings->backlight_timeout);
1073 return ret;