New makefile solution: A single invocation of 'make' to build the entire tree. Fully...
[kugel-rb.git] / apps / plugins / rockblox.c
blobd9b1c0aeb5188b1d93b2c5ed50e576e52b5209e3
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 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
23 #include "plugin.h"
24 #include "lib/highscore.h"
25 #include "lib/playergfx.h"
26 #include "lib/helper.h"
28 PLUGIN_HEADER
30 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
31 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
32 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
34 #define ROCKBLOX_OFF (BUTTON_MENU | BUTTON_SELECT)
35 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
36 #define ROCKBLOX_ROTATE_RIGHT2 (BUTTON_MENU | BUTTON_REL)
37 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
38 #define ROCKBLOX_LEFT BUTTON_LEFT
39 #define ROCKBLOX_RIGHT BUTTON_RIGHT
40 #define ROCKBLOX_DOWN BUTTON_PLAY
41 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_PLAY)
42 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
44 #define SCROLL_WHEEL
46 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
47 (CONFIG_KEYPAD == IRIVER_H300_PAD)
49 #define ROCKBLOX_OFF BUTTON_OFF
50 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
51 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
52 #define ROCKBLOX_DOWN BUTTON_DOWN
53 #define ROCKBLOX_LEFT BUTTON_LEFT
54 #define ROCKBLOX_RIGHT BUTTON_RIGHT
55 #define ROCKBLOX_DROP BUTTON_MODE
56 #define ROCKBLOX_RESTART BUTTON_ON
58 #define ROCKBLOX_RC_OFF BUTTON_RC_STOP
60 #elif CONFIG_KEYPAD == RECORDER_PAD
62 #define ROCKBLOX_OFF BUTTON_OFF
63 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
64 #define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
65 #define ROCKBLOX_DOWN BUTTON_DOWN
66 #define ROCKBLOX_LEFT BUTTON_LEFT
67 #define ROCKBLOX_RIGHT BUTTON_RIGHT
68 #define ROCKBLOX_DROP BUTTON_ON
69 #define ROCKBLOX_RESTART BUTTON_F1
71 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
73 #define ROCKBLOX_OFF BUTTON_OFF
74 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
75 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
76 #define ROCKBLOX_DOWN BUTTON_DOWN
77 #define ROCKBLOX_LEFT BUTTON_LEFT
78 #define ROCKBLOX_RIGHT BUTTON_RIGHT
79 #define ROCKBLOX_DROP BUTTON_ON
80 #define ROCKBLOX_RESTART BUTTON_F1
82 #elif CONFIG_KEYPAD == PLAYER_PAD
84 #define ROCKBLOX_OFF BUTTON_STOP
85 #define ROCKBLOX_ROTATE_RIGHT BUTTON_PLAY
86 #define ROCKBLOX_ROTATE_LEFT (BUTTON_ON|BUTTON_PLAY)
87 #define ROCKBLOX_DOWN BUTTON_MENU
88 #define ROCKBLOX_LEFT BUTTON_LEFT
89 #define ROCKBLOX_RIGHT BUTTON_RIGHT
90 #define ROCKBLOX_DROP_PRE BUTTON_ON
91 #define ROCKBLOX_DROP (BUTTON_ON|BUTTON_REL)
93 #elif CONFIG_KEYPAD == ONDIO_PAD
95 #define ROCKBLOX_OFF BUTTON_OFF
96 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
97 #define ROCKBLOX_ROTATE_LEFT (BUTTON_MENU|BUTTON_UP)
98 #define ROCKBLOX_DOWN BUTTON_DOWN
99 #define ROCKBLOX_LEFT BUTTON_LEFT
100 #define ROCKBLOX_RIGHT BUTTON_RIGHT
101 #define ROCKBLOX_DROP_PRE BUTTON_MENU
102 #define ROCKBLOX_DROP (BUTTON_MENU|BUTTON_REL)
104 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
106 #define ROCKBLOX_OFF BUTTON_POWER
107 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
108 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
109 #define ROCKBLOX_DOWN BUTTON_DOWN
110 #define ROCKBLOX_LEFT BUTTON_LEFT
111 #define ROCKBLOX_RIGHT BUTTON_RIGHT
112 #define ROCKBLOX_DROP BUTTON_REC
113 #define ROCKBLOX_RESTART BUTTON_PLAY
115 #elif CONFIG_KEYPAD == SANSA_E200_PAD
117 #define ROCKBLOX_OFF BUTTON_POWER
118 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
119 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
120 #define ROCKBLOX_DOWN BUTTON_DOWN
121 #define ROCKBLOX_LEFT BUTTON_LEFT
122 #define ROCKBLOX_RIGHT BUTTON_RIGHT
123 #define ROCKBLOX_DROP BUTTON_SELECT
124 #define ROCKBLOX_RESTART BUTTON_REC
126 #elif CONFIG_KEYPAD == SANSA_C200_PAD
128 #define ROCKBLOX_OFF BUTTON_POWER
129 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
130 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_VOL_DOWN
131 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
132 #define ROCKBLOX_DOWN BUTTON_DOWN
133 #define ROCKBLOX_LEFT BUTTON_LEFT
134 #define ROCKBLOX_RIGHT BUTTON_RIGHT
135 #define ROCKBLOX_DROP BUTTON_SELECT
136 #define ROCKBLOX_RESTART BUTTON_REC
138 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
140 #define ROCKBLOX_OFF BUTTON_POWER
141 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_UP
142 #define ROCKBLOX_ROTATE_LEFT BUTTON_REW
143 #define ROCKBLOX_DOWN BUTTON_SCROLL_DOWN
144 #define ROCKBLOX_LEFT BUTTON_LEFT
145 #define ROCKBLOX_RIGHT BUTTON_RIGHT
146 #define ROCKBLOX_DROP BUTTON_FF
147 #define ROCKBLOX_RESTART BUTTON_PLAY
149 #elif CONFIG_KEYPAD == GIGABEAT_PAD
151 #define ROCKBLOX_OFF BUTTON_POWER
152 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
153 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
154 #define ROCKBLOX_ROTATE BUTTON_UP
155 #define ROCKBLOX_DOWN BUTTON_DOWN
156 #define ROCKBLOX_LEFT BUTTON_LEFT
157 #define ROCKBLOX_RIGHT BUTTON_RIGHT
158 #define ROCKBLOX_DROP BUTTON_SELECT
159 #define ROCKBLOX_RESTART BUTTON_A
161 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
163 #define ROCKBLOX_OFF BUTTON_PLAY
164 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
165 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
166 #define ROCKBLOX_DOWN BUTTON_DOWN
167 #define ROCKBLOX_LEFT BUTTON_LEFT
168 #define ROCKBLOX_RIGHT BUTTON_RIGHT
169 #define ROCKBLOX_DROP BUTTON_MODE
170 #define ROCKBLOX_RESTART BUTTON_EQ
172 #elif CONFIG_KEYPAD == MROBE500_PAD
173 #define ROCKBLOX_OFF BUTTON_POWER
174 #define ROCKBLOX_ROTATE_RIGHT BUTTON_RC_VOL_UP
175 #define ROCKBLOX_ROTATE_LEFT BUTTON_RC_VOL_DOWN
176 #define ROCKBLOX_DOWN BUTTON_RC_DOWN
177 #define ROCKBLOX_LEFT BUTTON_LEFT
178 #define ROCKBLOX_RIGHT BUTTON_RIGHT
179 #define ROCKBLOX_DROP BUTTON_RC_HEART
180 #define ROCKBLOX_RESTART BUTTON_RC_MODE
182 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
183 #define ROCKBLOX_OFF BUTTON_BACK
184 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
185 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
186 #define ROCKBLOX_ROTATE BUTTON_UP
187 #define ROCKBLOX_DOWN BUTTON_DOWN
188 #define ROCKBLOX_LEFT BUTTON_LEFT
189 #define ROCKBLOX_RIGHT BUTTON_RIGHT
190 #define ROCKBLOX_DROP BUTTON_SELECT
191 #define ROCKBLOX_RESTART BUTTON_PLAY
193 #elif CONFIG_KEYPAD == MROBE100_PAD
195 #define ROCKBLOX_OFF BUTTON_POWER
196 #define ROCKBLOX_ROTATE_RIGHT BUTTON_MENU
197 #define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
198 #define ROCKBLOX_ROTATE BUTTON_UP
199 #define ROCKBLOX_DOWN BUTTON_DOWN
200 #define ROCKBLOX_LEFT BUTTON_LEFT
201 #define ROCKBLOX_RIGHT BUTTON_RIGHT
202 #define ROCKBLOX_DROP BUTTON_SELECT
203 #define ROCKBLOX_RESTART BUTTON_DISPLAY
205 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
207 #define ROCKBLOX_OFF BUTTON_RC_REC
208 #define ROCKBLOX_ROTATE_RIGHT BUTTON_RC_VOL_DOWN
209 #define ROCKBLOX_ROTATE_LEFT BUTTON_RC_VOL_UP
210 #define ROCKBLOX_DOWN BUTTON_RC_MENU
211 #define ROCKBLOX_LEFT BUTTON_RC_REW
212 #define ROCKBLOX_RIGHT BUTTON_RC_FF
213 #define ROCKBLOX_DROP BUTTON_RC_PLAY
214 #define ROCKBLOX_RESTART BUTTON_RC_MODE
216 #elif CONFIG_KEYPAD == COWOND2_PAD
217 #define ROCKBLOX_OFF BUTTON_POWER
218 #define ROCKBLOX_RESTART BUTTON_MENU
220 #elif CONFIG_KEYPAD == IAUDIO67_PAD
222 #define ROCKBLOX_OFF BUTTON_POWER
223 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOLDOWN
224 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOLUP
225 #define ROCKBLOX_DOWN BUTTON_STOP
226 #define ROCKBLOX_LEFT BUTTON_LEFT
227 #define ROCKBLOX_RIGHT BUTTON_RIGHT
228 #define ROCKBLOX_DROP BUTTON_PLAY
229 #define ROCKBLOX_RESTART BUTTON_MENU
231 #else
232 #error No keymap defined!
233 #endif
235 #ifdef HAVE_TOUCHSCREEN
236 #ifndef ROCKBLOX_OFF
237 #define ROCKBLOX_OFF BUTTON_TOPLEFT
238 #endif
239 #ifndef ROCKBLOX_ROTATE_RIGHT
240 #define ROCKBLOX_ROTATE_RIGHT BUTTON_BOTTOMRIGHT
241 #endif
242 #ifndef ROCKBLOX_ROTATE_LEFT
243 #define ROCKBLOX_ROTATE_LEFT BUTTON_BOTTOMLEFT
244 #endif
245 #ifndef ROCKBLOX_DOWN
246 #define ROCKBLOX_DOWN BUTTON_BOTTOMMIDDLE
247 #endif
248 #ifndef ROCKBLOX_LEFT
249 #define ROCKBLOX_LEFT BUTTON_MIDLEFT
250 #endif
251 #ifndef ROCKBLOX_RIGHT
252 #define ROCKBLOX_RIGHT BUTTON_MIDRIGHT
253 #endif
254 #ifndef ROCKBLOX_DROP
255 #define ROCKBLOX_DROP BUTTON_CENTER
256 #endif
257 #ifndef ROCKBLOX_RESTART
258 #define ROCKBLOX_RESTART BUTTON_TOPRIGHT
259 #endif
260 #endif
262 #define BLOCKS_NUM 7
263 #define EMPTY_BLOCK 7
265 #define BOARD_WIDTH 10
267 #ifdef HAVE_LCD_BITMAP
269 #define BOARD_HEIGHT 20
271 #if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
273 #define BLOCK_WIDTH 30
274 #define BLOCK_HEIGHT 30
275 #define BOARD_X 14
276 #define BOARD_Y 2
277 #define PREVIEW_X 342
278 #define PREVIEW_Y 482
279 #define LABEL_X 344
280 #define SCORE_Y 58
281 #define LEVEL_Y 142
282 #define LINES_Y 218
283 #define HIGH_LABEL_X 344
284 #define HIGH_SCORE_Y 326
285 #define HIGH_LEVEL_Y 344
287 #elif (LCD_WIDTH == 480) && (LCD_HEIGHT == 640)
289 #define BLOCK_WIDTH 30
290 #define BLOCK_HEIGHT 30
291 #define BOARD_X 14
292 #define BOARD_Y 2
293 #define PREVIEW_X 342
294 #define PREVIEW_Y 482
295 #define LABEL_X 344
296 #define SCORE_Y 58
297 #define LEVEL_Y 142
298 #define LINES_Y 218
299 #define HIGH_LABEL_X 344
300 #define HIGH_SCORE_Y 326
301 #define HIGH_LEVEL_Y 344
303 #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
305 #define BLOCK_WIDTH 12
306 #define BLOCK_HEIGHT 12
307 #define BOARD_X 86
308 #define BOARD_Y 0
309 #define PREVIEW_X 12
310 #define PREVIEW_Y 11
311 #define LABEL_X 242
312 #define SCORE_Y 25
313 #define LEVEL_Y 70
314 #define LINES_Y 105
316 #elif (LCD_WIDTH == 240) && (LCD_HEIGHT == 320)
318 #define BLOCK_WIDTH 15
319 #define BLOCK_HEIGHT 15
320 #define BOARD_X 7
321 #define BOARD_Y 1
322 #define PREVIEW_X 171
323 #define PREVIEW_Y 241
324 #define LABEL_X 172
325 #define SCORE_Y 29
326 #define LEVEL_Y 71
327 #define LINES_Y 109
328 #define HIGH_LABEL_X 172
329 #define HIGH_SCORE_Y 163
330 #define HIGH_LEVEL_Y 172
332 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
334 #define BLOCK_WIDTH 8
335 #define BLOCK_HEIGHT 8
336 #define BOARD_X 27
337 #define BOARD_Y 5
338 #define PREVIEW_X 158
339 #define PREVIEW_Y 130
340 #define LABEL_X 147
341 #define SCORE_Y 20
342 #define LEVEL_Y 65
343 #define LINES_Y 100
345 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
347 #define BLOCK_WIDTH 6
348 #define BLOCK_HEIGHT 6
349 #define BOARD_X 25
350 #define BOARD_Y 1
351 #define PREVIEW_X 126
352 #define PREVIEW_Y 102
353 #define LABEL_X 112
354 #define SCORE_Y 17
355 #define LEVEL_Y 49
356 #define LINES_Y 81
358 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
360 #define BLOCK_WIDTH 10
361 #define BLOCK_HEIGHT 10
362 #define BOARD_X 6
363 #define BOARD_Y 10
364 #define PREVIEW_X 124
365 #define PREVIEW_Y 167
366 #define LABEL_X 117
367 #define SCORE_Y 24
368 #define LEVEL_Y 65
369 #define LINES_Y 103
370 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
372 #define BLOCK_WIDTH 6
373 #define BLOCK_HEIGHT 6
374 #define BOARD_X 22
375 #define BOARD_Y 3
376 #define PREVIEW_X 114
377 #define PREVIEW_Y 100
378 #define LABEL_X 101
379 #define SCORE_Y 17
380 #define LEVEL_Y 49
381 #define LINES_Y 82
383 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
385 #define BLOCK_WIDTH 5
386 #define BLOCK_HEIGHT 5
387 #define BOARD_X 14
388 #define BOARD_Y 0
389 #define PREVIEW_X 98
390 #define PREVIEW_Y 88
391 #define LABEL_X 80
392 #define SCORE_Y 15
393 #define LEVEL_Y 45
394 #define LINES_Y 74
396 #elif (LCD_WIDTH == 132) && (LCD_HEIGHT == 80)
398 #define BLOCK_WIDTH 4
399 #define BLOCK_HEIGHT 4
400 #define BOARD_X 10
401 #define BOARD_Y 0
402 #define PREVIEW_X 89
403 #define PREVIEW_Y 61
404 #define LABEL_X 78
405 #define SCORE_Y 10
406 #define LEVEL_Y 30
407 #define LINES_Y 50
409 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
411 #define BLOCK_WIDTH 6
412 #define BLOCK_HEIGHT 6
413 #define BOARD_X 4
414 #define BOARD_Y 3
415 #define PREVIEW_X 84
416 #define PREVIEW_Y 100
417 #define LABEL_X 71
418 #define SCORE_Y 17
419 #define LEVEL_Y 49
420 #define LINES_Y 82
422 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 96)
424 #define BLOCK_WIDTH 4
425 #define BLOCK_HEIGHT 4
426 #define BOARD_X 14
427 #define BOARD_Y 2
428 #define PREVIEW_X 89
429 #define PREVIEW_Y 76
430 #define LABEL_X 70
431 #define SCORE_Y 14
432 #define LEVEL_Y 39
433 #define LINES_Y 64
435 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 64)
437 #define BLOCK_WIDTH 3
438 #define BLOCK_HEIGHT 3
439 #define BOARD_X 9
440 #define BOARD_Y 3
441 #define PREVIEW_X 53
442 #define PREVIEW_Y 5
443 #define LABEL_X 70
444 #define SCORE_Y 32
445 #define LEVEL_Y 13
446 #define LINES_Y 51
448 #elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
450 #define BLOCK_WIDTH 4
451 #define BLOCK_HEIGHT 3
452 #define BOARD_X 9
453 #define BOARD_Y 3
454 #define PREVIEW_X 59
455 #define PREVIEW_Y 5
456 #define LABEL_X 59
457 #define SCORE_Y 32
458 #define LEVEL_Y 13
459 #define LEVEL_X 78
460 #define LINES_Y 51
462 #endif
464 #ifndef LEVEL_X
465 #define LEVEL_X LABEL_X
466 #endif
468 #ifndef LINES_X
469 #define LINES_X LABEL_X
470 #endif
472 #define MYLCD(fn) rb->lcd_ ## fn
474 extern const fb_data rockblox_background[];
476 #else /* HAVE_LCD_CHARCELLS */
478 #define BOARD_HEIGHT 14
480 #define BLOCK_WIDTH 1
481 #define BLOCK_HEIGHT 1
482 #define BOARD_X 5
483 #define BOARD_Y 0
484 #define PREVIEW_X 15
485 #define PREVIEW_Y 1
487 #define MYLCD(fn) pgfx_ ## fn
489 #endif
491 /* <<Explanation on Rockblox shapes>>
494 %% - O has 1 orientation
496 %% %
497 %% %% - Z has 2 orientations
500 %% %
501 %% %% - S has 2 orientations
505 % %%%% - I has 2 orientations
508 % %%
509 % % % %%% - L has 4 orientations
510 %% %%% % %
512 % %%s
513 % % % %%% - J has 4 orientations
514 %% %%% % %
516 % % %%%
517 %% % %% % - T has 4 orientations
518 % %%% %
522 /* must have variable */
523 static const struct plugin_api *rb;
525 static bool gameover = false;
526 /* c=current f=figure o=orientation n=next */
527 static int lines = 0, level = 0, score = 0, cx, cy, cf, co, nf;
528 static short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */
530 #ifdef SCROLL_WHEEL
531 int wheel_events = 0, last_wheel_event = 0;
532 bool wheel_enabled = false;
533 #endif
535 static const short scoring[4] = { /* scoring for each number of lines */
536 #if BOARD_HEIGHT == 20
537 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
538 #elif BOARD_HEIGHT == 14 /* Player special values */
539 60 /* single */ , 150 /* double */ , 500 /* triple */ , 2000 /* rockblox */
540 #endif
543 struct figure
545 #if LCD_DEPTH >= 2
546 unsigned short color[3]; /* color of figure (light,middle,shadow) */
547 #endif
548 unsigned short max_or; /* max orientations */
549 signed short shapeX[4], shapeY[4]; /* implementation of figures */
552 /* array of figures */
553 figures[BLOCKS_NUM] = {
554 /* O */
556 #if LCD_DEPTH >= 16
557 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
558 LCD_RGBPACK(0,153,153)},
559 #elif LCD_DEPTH == 2
560 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
561 #endif
563 {-1, 0, -1, 0},
564 {0, 0, 1, 1}
566 /* I */
568 #if LCD_DEPTH >= 16
569 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
570 LCD_RGBPACK (153, 0, 0)},
571 #elif LCD_DEPTH == 2
572 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
573 #endif
575 {-2, -1, 0, 1},
576 {0, 0, 0, 0}
578 /* 'Z' */
580 #if LCD_DEPTH >= 16
581 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
582 LCD_RGBPACK (0, 153, 0)},
583 #elif LCD_DEPTH == 2
584 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
585 #endif
587 {0, 1, -1, 0},
588 {0, 0, 1, 1}
590 /* 'S' */
592 #if LCD_DEPTH >= 16
593 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
594 LCD_RGBPACK (0, 0, 153)},
595 #elif LCD_DEPTH == 2
596 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
597 #endif
599 {-1, 0, 0, 1},
600 {0, 0, 1, 1}
602 /* 'L' */
604 #if LCD_DEPTH >= 16
605 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
606 LCD_RGBPACK (153, 153, 0)},
607 #elif LCD_DEPTH == 2
608 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
609 #endif
611 {-1, 0, 1, 1},
612 {0, 0, 0, 1}
614 /* 'J' */
616 #if LCD_DEPTH >= 16
617 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
618 LCD_RGBPACK (153, 0, 153)},
619 #elif LCD_DEPTH == 2
620 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
621 #endif
623 {-1, 0, 1, -1},
624 {0, 0, 0, 1}
626 /* 'T' */
628 #if LCD_DEPTH >= 16
629 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
630 LCD_RGBPACK (85, 85, 85)},
631 #elif LCD_DEPTH == 2
632 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
633 #endif
635 {-1, 0, 1, 0},
636 {0, 0, 0, 1}
640 /* Rockbox File System only supports full filenames inc dir */
641 #define HIGH_SCORE PLUGIN_GAMES_DIR "/rockblox.score"
642 #define MAX_HIGH_SCORES 5
643 /* Default High Scores... */
644 struct highscore Highest[MAX_HIGH_SCORES];
646 /* get random number from (0) to (range-1) */
647 static int t_rand (int range)
649 return rb->rand () % range;
652 /* init the board array to have no blocks */
653 static void init_board (void)
655 int i, j;
656 for (i = 0; i < BOARD_WIDTH; i++)
657 for (j = 0; j < BOARD_HEIGHT; j++)
658 board[j][i] = EMPTY_BLOCK;
661 /* show the score, level and lines */
662 static void show_details (void)
664 char str[25]; /* for strings */
666 #ifdef HAVE_LCD_BITMAP
667 #if LCD_DEPTH >= 2
668 rb->lcd_set_foreground (LCD_BLACK);
669 rb->lcd_set_background (LCD_WHITE);
670 #endif
671 rb->snprintf (str, sizeof (str), "%d", score);
672 rb->lcd_putsxy (LABEL_X, SCORE_Y, str);
673 rb->snprintf (str, sizeof (str), "%d", level);
674 rb->lcd_putsxy (LEVEL_X, LEVEL_Y, str);
675 rb->snprintf (str, sizeof (str), "%d", lines);
676 rb->lcd_putsxy (LINES_X, LINES_Y, str);
677 #else /* HAVE_LCD_CHARCELLS */
678 rb->snprintf (str, sizeof (str), "L%d/%d", level, lines);
679 rb->lcd_puts (5, 0, str);
680 rb->snprintf (str, sizeof (str), "S%d", score);
681 rb->lcd_puts (5, 1, str);
682 #endif
685 #ifdef HIGH_SCORE_Y
686 static void show_highscores (void)
688 int i;
689 char str[25]; /* for strings */
691 for (i = MAX_HIGH_SCORES-1; i>=0; i--)
693 rb->snprintf (str, sizeof (str), "%06d L%1d", Highest[i].score, Highest[i].level);
694 rb->lcd_putsxy (HIGH_LABEL_X, HIGH_SCORE_Y + (10 * ((MAX_HIGH_SCORES-1) - i)), str);
697 #endif
699 static void init_rockblox (void)
701 highscore_update(score, level, Highest, MAX_HIGH_SCORES);
703 level = 1;
704 lines = 0;
705 score = 0;
706 gameover = false;
707 nf = t_rand (BLOCKS_NUM);
708 init_board ();
709 #ifdef HAVE_LCD_BITMAP
710 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
711 #else /* HAVE_LCD_CHARCELLS */
712 pgfx_display (0, 0);
713 pgfx_display_block (3, 0, 3, 1);
714 pgfx_display_block (4, 0, 3, 0);
715 pgfx_clear_display();
716 pgfx_fillrect (3, 0, 2, 14);
717 pgfx_fillrect (15, 7, 2, 7);
718 pgfx_update();
719 #endif
720 show_details ();
721 #ifdef HIGH_SCORE_Y
722 show_highscores ();
723 #endif
726 static inline int level_speed(int level)
728 #if BOARD_HEIGHT == 20
729 return (5*HZ) / (level + 9);
730 #elif BOARD_HEIGHT == 14
731 return (7*HZ) / (level + 9);
732 #endif
735 static int getRelativeX (int figure, int square, int orientation)
737 switch (orientation) {
738 case 0:
739 return figures[figure].shapeX[square];
740 case 1:
741 return figures[figure].shapeY[square];
742 case 2:
743 return -figures[figure].shapeX[square];
744 case 3:
745 return -figures[figure].shapeY[square];
746 default:
747 return 0;
751 static int getRelativeY (int figure, int square, int orientation)
753 switch (orientation) {
754 case 0:
755 return figures[figure].shapeY[square];
756 case 1:
757 return -figures[figure].shapeX[square];
758 case 2:
759 return -figures[figure].shapeY[square];
760 case 3:
761 return figures[figure].shapeX[square];
762 default:
763 return 0;
767 /* redraw the while board on the screen */
768 static void refresh_board (void)
770 int i, j, x, y, block;
772 #if LCD_DEPTH >= 2
773 rb->lcd_set_foreground (LCD_BLACK);
774 #elif LCD_DEPTH == 1
775 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
776 #endif
778 MYLCD(fillrect) (BOARD_X, BOARD_Y, BOARD_WIDTH * BLOCK_WIDTH,
779 BOARD_HEIGHT * BLOCK_HEIGHT);
781 #if LCD_DEPTH == 1
782 MYLCD(set_drawmode) (DRMODE_SOLID);
783 #endif
785 for (i = 0; i < BOARD_WIDTH; i++)
786 for (j = 0; j < BOARD_HEIGHT; j++) {
787 block = board[j][i];
788 if (block != EMPTY_BLOCK) {
789 #ifdef HAVE_LCD_BITMAP
790 #if LCD_DEPTH >= 2
791 /* middle drawing */
792 rb->lcd_set_foreground (figures[block].color[1]);
793 #endif
794 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
795 BOARD_Y + j * BLOCK_HEIGHT,
796 BLOCK_WIDTH, BLOCK_HEIGHT);
797 #if LCD_DEPTH >= 2
798 /* light drawing */
799 rb->lcd_set_foreground (figures[block].color[0]);
800 #endif
801 rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH,
802 BOARD_Y + j * BLOCK_HEIGHT,
803 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2);
804 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH,
805 BOARD_X + (i + 1) * BLOCK_WIDTH - 2,
806 BOARD_Y + j * BLOCK_HEIGHT);
807 #if LCD_DEPTH >= 2
808 /* shadow drawing */
809 rb->lcd_set_foreground (figures[block].color[2]);
810 #endif
811 rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
812 BOARD_Y + j * BLOCK_HEIGHT + 1,
813 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
814 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1,
815 BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
816 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
817 #else /* HAVE_LCD_CHARCELLS */
818 pgfx_drawpixel (BOARD_X + i, BOARD_Y + j);
819 #endif
823 for (i = 0; i < 4; i++) {
824 x = getRelativeX (cf, i, co) + cx;
825 y = getRelativeY (cf, i, co) + cy;
826 #ifdef HAVE_LCD_BITMAP
827 #if LCD_DEPTH >= 2
828 rb->lcd_set_foreground (figures[cf].color[1]); /* middle drawing */
829 #endif
830 rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH,
831 BOARD_Y + y * BLOCK_HEIGHT,
832 BLOCK_WIDTH, BLOCK_HEIGHT);
833 #if LCD_DEPTH >= 2
834 rb->lcd_set_foreground (figures[cf].color[0]); /* light drawing */
835 #endif
836 rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT,
837 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2);
838 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH,
839 BOARD_X + (x + 1) * BLOCK_WIDTH - 2,
840 BOARD_Y + y * BLOCK_HEIGHT);
841 #if LCD_DEPTH >= 2
842 rb->lcd_set_foreground (figures[cf].color[2]); /* shadow drawing */
843 #endif
844 rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
845 BOARD_Y + y * BLOCK_HEIGHT + 1,
846 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
847 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1,
848 BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
849 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
850 #else /* HAVE_LCD_CHARCELLS */
851 pgfx_drawpixel (BOARD_X + x, BOARD_Y + y);
852 #endif
854 MYLCD(update) ();
857 static bool canMoveTo (int x, int y, int newOrientation)
859 int i, rx, ry;
860 for (i = 0; i < 4; i++) {
861 ry = getRelativeY (cf, i, newOrientation) + y;
862 rx = getRelativeX (cf, i, newOrientation) + x;
863 if ((rx < 0 || rx >= BOARD_WIDTH) ||
864 (ry < 0 || ry >= BOARD_HEIGHT) || (board[ry][rx] != EMPTY_BLOCK))
865 return false;
867 return true;
870 /* draws the preview of next block in the preview window */
871 static void draw_next_block (void)
873 int i, rx, ry;
874 /* clear preview window first */
875 #if LCD_DEPTH >= 2
876 rb->lcd_set_foreground (LCD_BLACK);
877 #elif LCD_DEPTH == 1
878 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
879 #endif
881 /* 4x4 */
882 MYLCD(fillrect) (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4);
884 #if LCD_DEPTH == 1
885 MYLCD(set_drawmode) (DRMODE_SOLID);
886 #endif
888 /* draw the lightgray rectangles */
889 #if LCD_DEPTH >= 16
890 rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
891 #elif LCD_DEPTH == 2
892 rb->lcd_set_foreground (LCD_DARKGRAY);
893 #endif
895 #if LCD_DEPTH >= 2
896 for (rx = 0; rx < 4; rx++)
897 for (ry = 0; ry < 4; ry++)
898 rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH,
899 PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH,
900 BLOCK_HEIGHT);
901 #endif
903 /* draw the figure */
904 for (i = 0; i < 4; i++) {
905 rx = getRelativeX (nf, i, 0) + 2;
906 ry = getRelativeY (nf, i, 0) + 2;
907 #ifdef HAVE_LCD_BITMAP
908 #if LCD_DEPTH >= 2
909 rb->lcd_set_foreground (figures[nf].color[1]); /* middle drawing */
910 #endif
911 rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH,
912 PREVIEW_Y + ry * BLOCK_HEIGHT,
913 BLOCK_WIDTH, BLOCK_HEIGHT);
914 #if LCD_DEPTH >= 2
915 rb->lcd_set_foreground (figures[nf].color[0]); /* light drawing */
916 #endif
917 rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH,
918 PREVIEW_Y + ry * BLOCK_HEIGHT,
919 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2);
920 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH,
921 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2,
922 PREVIEW_Y + ry * BLOCK_HEIGHT);
923 #if LCD_DEPTH >= 2
924 rb->lcd_set_foreground (figures[nf].color[2]); /* shadow drawing */
925 #endif
926 rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
927 PREVIEW_Y + ry * BLOCK_HEIGHT + 1,
928 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
929 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1,
930 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
931 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
932 #else /* HAVE_LCD_CHARCELLS */
933 pgfx_drawpixel (PREVIEW_X + rx, PREVIEW_Y + ry);
934 #endif
939 /* move the block to a relative location */
940 static void move_block (int x, int y, int o)
942 if (canMoveTo (cx + x, cy + y, o)) {
943 cy += y;
944 cx += x;
945 co = o;
949 /* try to add a new block to play with (return true if gameover) */
950 static void new_block (void)
952 cy = 1;
953 cx = 5;
954 cf = nf;
955 co = 0; /* start at the same orientation all time */
956 nf = t_rand (BLOCKS_NUM);
957 gameover = !canMoveTo (cx, cy, co);
959 draw_next_block ();
963 /* check for filled lines and do what necessary */
964 static int check_lines (void)
966 int i, j, y;
967 int rockblox = 0;
969 for (j = 0; j < BOARD_HEIGHT; j++) {
970 for (i = 0; ((i < BOARD_WIDTH) && (board[j][i] != EMPTY_BLOCK)); i++);
971 if (i == BOARD_WIDTH) { /* woo hoo, we have a line */
972 rockblox++;
973 for (y = j; y > 0; y--)
974 for (i = 0; i < BOARD_WIDTH; i++)
975 board[y][i] = board[y - 1][i]; /* fall line */
979 return rockblox;
982 /* moves down the figure and returns true if gameover */
983 static void move_down (void)
985 int l, i, rx, ry;
987 if (!canMoveTo (cx, cy + 1, co)) {
988 /* save figure to board */
989 for (i = 0; i < 4; i++) {
990 rx = getRelativeX (cf, i, co) + cx;
991 ry = getRelativeY (cf, i, co) + cy;
992 board[ry][rx] = cf;
994 /* check if formed some lines */
995 l = check_lines ();
996 if (l) {
997 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
998 score += scoring[l - 1] * level;
999 lines += l;
1000 level = (int) lines / 10 + 1;
1003 /* show details */
1004 show_details ();
1006 /* generate a new figure */
1007 new_block ();
1008 } else
1009 move_block (0, 1, co);
1012 static int rockblox_loop (void)
1014 int button;
1015 int lastbutton = BUTTON_NONE;
1016 long next_down_tick = *rb->current_tick + level_speed(level);
1018 new_block ();
1020 while (1) {
1021 #ifdef HAS_BUTTON_HOLD
1022 if (rb->button_hold ()) {
1023 /* Turn on backlight timeout (revert to settings) */
1024 backlight_use_settings(rb); /* backlight control in lib/helper.c */
1025 rb->splash(0, "Paused");
1026 while (rb->button_hold ())
1027 rb->sleep(HZ/10);
1029 /* Turn off backlight timeout */
1030 backlight_force_on(rb); /* backlight control in lib/helper.c */
1032 /* get rid of the splash text */
1033 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
1034 show_details ();
1035 #ifdef HIGH_SCORE_Y
1036 show_highscores ();
1037 #endif
1038 draw_next_block ();
1039 refresh_board ();
1041 #endif
1043 button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1));
1044 switch (button) {
1045 #ifdef ROCKBLOX_RC_OFF
1046 case ROCKBLOX_RC_OFF:
1047 #endif
1048 case ROCKBLOX_OFF:
1049 return PLUGIN_OK;
1051 #if defined(ROCKBLOX_ROTATE)
1052 case ROCKBLOX_ROTATE:
1053 #endif
1054 case ROCKBLOX_ROTATE_RIGHT:
1055 case ROCKBLOX_ROTATE_RIGHT | BUTTON_REPEAT:
1056 #ifdef SCROLL_WHEEL
1057 /* if the wheel is disabled, add an event to the stack. */
1058 if(wheel_enabled == false)
1059 wheel_events++;
1061 /* if it's enabled, go ahead and rotate.. */
1062 if(wheel_enabled)
1063 #endif
1064 move_block (0, 0, (co + 1) % figures[cf].max_or);
1065 break;
1067 case ROCKBLOX_ROTATE_LEFT:
1068 case ROCKBLOX_ROTATE_LEFT | BUTTON_REPEAT:
1069 #ifdef SCROLL_WHEEL
1070 if(wheel_enabled == false)
1071 wheel_events++;
1073 if(wheel_enabled)
1074 #endif
1075 move_block (0, 0,
1076 (co + figures[cf].max_or -
1077 1) % figures[cf].max_or);
1078 break;
1080 #ifdef ROCKBLOX_ROTATE_RIGHT2
1081 case ROCKBLOX_ROTATE_RIGHT2:
1082 move_block (0, 0, (co + 1) % figures[cf].max_or);
1083 break;
1084 #endif
1086 case ROCKBLOX_DOWN:
1087 case ROCKBLOX_DOWN | BUTTON_REPEAT:
1088 move_block (0, 1, co);
1089 break;
1091 case ROCKBLOX_RIGHT:
1092 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
1093 move_block (1, 0, co);
1094 break;
1096 case ROCKBLOX_LEFT:
1097 case ROCKBLOX_LEFT | BUTTON_REPEAT:
1098 move_block (-1, 0, co);
1099 break;
1101 case ROCKBLOX_DROP:
1102 #ifdef ROCKBLOX_DROP_PRE
1103 if (lastbutton != ROCKBLOX_DROP_PRE)
1104 break;
1105 #endif
1106 while (canMoveTo (cx, cy + 1, co))
1107 move_block (0, 1, co);
1108 break;
1109 #ifdef ROCKBLOX_RESTART
1110 case ROCKBLOX_RESTART:
1111 rb->splash (HZ * 1, "Restarting...");
1112 init_rockblox ();
1113 new_block ();
1114 break;
1115 #endif
1117 default:
1118 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
1119 return PLUGIN_USB_CONNECTED;
1120 break;
1122 if (button != BUTTON_NONE)
1123 lastbutton = button;
1125 #ifdef SCROLL_WHEEL
1126 /* check if we should enable the scroll wheel, if events
1127 * begin to stack up... */
1128 if(wheel_enabled == false)
1130 /* stopped rotating the wheel, reset the count */
1131 if(wheel_events == last_wheel_event)
1133 last_wheel_event = 0;
1134 wheel_events = 0;
1136 /* rotated the wheel a while constantly, enable it. */
1137 else if(wheel_events > 3)
1139 wheel_enabled = true;
1142 /* this evens out the last event and the "current" event.
1143 * if we get an event next time through button reading, it will
1144 * remain ahead of last_event. if we don't, they'll end up equaling
1145 * each other.. thus, the scroll count will be reset. */
1146 if(wheel_enabled == false && wheel_events > last_wheel_event)
1147 last_wheel_event++;
1149 #endif
1151 if (TIME_AFTER(*rb->current_tick, next_down_tick)) {
1152 move_down ();
1153 next_down_tick += level_speed(level);
1154 if (TIME_AFTER(*rb->current_tick, next_down_tick))
1155 /* restart time "raster" when we had to wait longer than usual
1156 * (pause, game restart etc) */
1157 next_down_tick = *rb->current_tick + level_speed(level);
1160 if (gameover) {
1161 #if LCD_DEPTH >= 2
1162 rb->lcd_set_foreground (LCD_BLACK);
1163 #endif
1164 rb->splash (HZ * 2, "Game Over");
1165 init_rockblox ();
1166 new_block ();
1169 refresh_board ();
1172 return PLUGIN_OK;
1175 enum plugin_status plugin_start (const struct plugin_api *api, const void *parameter)
1177 int ret;
1179 (void) parameter;
1180 rb = api;
1182 rb->srand (*rb->current_tick);
1184 /* Load HighScore if any */
1185 highscore_init(rb);
1186 highscore_load(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1188 #if LCD_DEPTH > 1
1189 rb->lcd_set_backdrop(NULL);
1190 #endif
1192 #ifdef HAVE_LCD_BITMAP
1193 rb->lcd_setfont (FONT_SYSFIXED);
1194 #else
1195 if (!pgfx_init(rb, 4, 2))
1197 rb->splash(HZ*2, "Old LCD :(");
1198 return PLUGIN_OK;
1200 #endif
1201 /* Turn off backlight timeout */
1202 backlight_force_on(rb); /* backlight control in lib/helper.c */
1204 init_rockblox ();
1205 ret = rockblox_loop ();
1207 #ifdef HAVE_LCD_BITMAP
1208 rb->lcd_setfont (FONT_UI);
1209 #else
1210 pgfx_release();
1211 #endif
1212 /* Save user's HighScore */
1213 highscore_save(HIGH_SCORE,Highest,MAX_HIGH_SCORES);
1214 backlight_use_settings(rb); /* backlight control in lib/helper.c */
1216 return ret;