1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
24 #include "lib/highscore.h"
25 #include "lib/playergfx.h"
26 #include "lib/helper.h"
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 #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_PRE BUTTON_STOP
83 #define ROCKBLOX_OFF (BUTTON_STOP|BUTTON_REL)
84 #define ROCKBLOX_ROTATE_RIGHT BUTTON_PLAY
85 #define ROCKBLOX_ROTATE_LEFT (BUTTON_ON|BUTTON_PLAY)
86 #define ROCKBLOX_DOWN BUTTON_MENU
87 #define ROCKBLOX_LEFT BUTTON_LEFT
88 #define ROCKBLOX_RIGHT BUTTON_RIGHT
89 #define ROCKBLOX_DROP_PRE BUTTON_ON
90 #define ROCKBLOX_DROP (BUTTON_ON|BUTTON_REL)
91 #define ROCKBLOX_RESTART (BUTTON_STOP|BUTTON_MENU)
93 #elif CONFIG_KEYPAD == ONDIO_PAD
95 #define ROCKBLOX_OFF_PRE BUTTON_OFF
96 #define ROCKBLOX_OFF (BUTTON_OFF|BUTTON_REL)
97 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
98 #define ROCKBLOX_ROTATE_LEFT (BUTTON_MENU|BUTTON_UP)
99 #define ROCKBLOX_DOWN BUTTON_DOWN
100 #define ROCKBLOX_LEFT BUTTON_LEFT
101 #define ROCKBLOX_RIGHT BUTTON_RIGHT
102 #define ROCKBLOX_DROP_PRE BUTTON_MENU
103 #define ROCKBLOX_DROP (BUTTON_MENU|BUTTON_REL)
104 #define ROCKBLOX_RESTART (BUTTON_OFF|BUTTON_MENU)
106 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
108 #define ROCKBLOX_OFF BUTTON_POWER
109 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
110 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
111 #define ROCKBLOX_DOWN BUTTON_DOWN
112 #define ROCKBLOX_LEFT BUTTON_LEFT
113 #define ROCKBLOX_RIGHT BUTTON_RIGHT
114 #define ROCKBLOX_DROP BUTTON_REC
115 #define ROCKBLOX_RESTART BUTTON_PLAY
117 #elif CONFIG_KEYPAD == SANSA_E200_PAD
119 #define ROCKBLOX_OFF BUTTON_POWER
120 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
121 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_UP
122 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
123 #define ROCKBLOX_DOWN BUTTON_DOWN
124 #define ROCKBLOX_LEFT BUTTON_LEFT
125 #define ROCKBLOX_RIGHT BUTTON_RIGHT
126 #define ROCKBLOX_DROP BUTTON_SELECT
127 #define ROCKBLOX_RESTART BUTTON_REC
129 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
131 #define ROCKBLOX_OFF (BUTTON_HOME|BUTTON_REPEAT)
132 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
133 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_UP
134 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
135 #define ROCKBLOX_DOWN BUTTON_DOWN
136 #define ROCKBLOX_LEFT BUTTON_LEFT
137 #define ROCKBLOX_RIGHT BUTTON_RIGHT
138 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
139 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_UP)
142 #elif CONFIG_KEYPAD == SANSA_C200_PAD
144 #define ROCKBLOX_OFF BUTTON_POWER
145 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
146 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_VOL_DOWN
147 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
148 #define ROCKBLOX_DOWN BUTTON_DOWN
149 #define ROCKBLOX_LEFT BUTTON_LEFT
150 #define ROCKBLOX_RIGHT BUTTON_RIGHT
151 #define ROCKBLOX_DROP BUTTON_SELECT
152 #define ROCKBLOX_RESTART BUTTON_REC
154 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
156 #define ROCKBLOX_OFF BUTTON_POWER
157 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
158 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_VOL_DOWN
159 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
160 #define ROCKBLOX_DOWN BUTTON_DOWN
161 #define ROCKBLOX_LEFT BUTTON_LEFT
162 #define ROCKBLOX_RIGHT BUTTON_RIGHT
163 #define ROCKBLOX_DROP BUTTON_SELECT
164 #define ROCKBLOX_RESTART BUTTON_HOME
166 #elif CONFIG_KEYPAD == SANSA_M200_PAD
168 #define ROCKBLOX_OFF BUTTON_POWER
169 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
170 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_VOL_DOWN
171 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
172 #define ROCKBLOX_DOWN BUTTON_DOWN
173 #define ROCKBLOX_LEFT BUTTON_LEFT
174 #define ROCKBLOX_RIGHT BUTTON_RIGHT
175 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_UP)
176 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
178 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
180 #define ROCKBLOX_OFF BUTTON_POWER
181 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_UP
182 #define ROCKBLOX_ROTATE_LEFT BUTTON_REW
183 #define ROCKBLOX_DOWN BUTTON_SCROLL_DOWN
184 #define ROCKBLOX_LEFT BUTTON_LEFT
185 #define ROCKBLOX_RIGHT BUTTON_RIGHT
186 #define ROCKBLOX_DROP BUTTON_FF
187 #define ROCKBLOX_RESTART BUTTON_PLAY
189 #elif CONFIG_KEYPAD == GIGABEAT_PAD
191 #define ROCKBLOX_OFF BUTTON_POWER
192 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
193 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
194 #define ROCKBLOX_ROTATE BUTTON_UP
195 #define ROCKBLOX_DOWN BUTTON_DOWN
196 #define ROCKBLOX_LEFT BUTTON_LEFT
197 #define ROCKBLOX_RIGHT BUTTON_RIGHT
198 #define ROCKBLOX_DROP BUTTON_SELECT
199 #define ROCKBLOX_RESTART BUTTON_A
201 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
203 #define ROCKBLOX_OFF BUTTON_PLAY
204 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
205 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
206 #define ROCKBLOX_DOWN BUTTON_DOWN
207 #define ROCKBLOX_LEFT BUTTON_LEFT
208 #define ROCKBLOX_RIGHT BUTTON_RIGHT
209 #define ROCKBLOX_DROP BUTTON_MODE
210 #define ROCKBLOX_RESTART BUTTON_EQ
212 #elif CONFIG_KEYPAD == MROBE500_PAD
213 #define ROCKBLOX_OFF BUTTON_POWER
215 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
216 #define ROCKBLOX_OFF BUTTON_BACK
217 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
218 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
219 #define ROCKBLOX_ROTATE BUTTON_UP
220 #define ROCKBLOX_DOWN BUTTON_DOWN
221 #define ROCKBLOX_LEFT BUTTON_LEFT
222 #define ROCKBLOX_RIGHT BUTTON_RIGHT
223 #define ROCKBLOX_DROP BUTTON_SELECT
224 #define ROCKBLOX_RESTART BUTTON_PLAY
226 #elif CONFIG_KEYPAD == MROBE100_PAD
228 #define ROCKBLOX_OFF BUTTON_POWER
229 #define ROCKBLOX_ROTATE_RIGHT BUTTON_MENU
230 #define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
231 #define ROCKBLOX_ROTATE BUTTON_UP
232 #define ROCKBLOX_DOWN BUTTON_DOWN
233 #define ROCKBLOX_LEFT BUTTON_LEFT
234 #define ROCKBLOX_RIGHT BUTTON_RIGHT
235 #define ROCKBLOX_DROP BUTTON_SELECT
236 #define ROCKBLOX_RESTART BUTTON_DISPLAY
238 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
240 #define ROCKBLOX_OFF BUTTON_RC_REC
241 #define ROCKBLOX_ROTATE_RIGHT BUTTON_RC_VOL_DOWN
242 #define ROCKBLOX_ROTATE_LEFT BUTTON_RC_VOL_UP
243 #define ROCKBLOX_DOWN BUTTON_RC_MENU
244 #define ROCKBLOX_LEFT BUTTON_RC_REW
245 #define ROCKBLOX_RIGHT BUTTON_RC_FF
246 #define ROCKBLOX_DROP BUTTON_RC_PLAY
247 #define ROCKBLOX_RESTART BUTTON_RC_MODE
249 #elif CONFIG_KEYPAD == COWOND2_PAD
250 #define ROCKBLOX_OFF BUTTON_POWER
251 #define ROCKBLOX_RESTART BUTTON_MENU
253 #elif CONFIG_KEYPAD == IAUDIO67_PAD
255 #define ROCKBLOX_OFF BUTTON_POWER
256 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOLDOWN
257 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOLUP
258 #define ROCKBLOX_DOWN BUTTON_STOP
259 #define ROCKBLOX_LEFT BUTTON_LEFT
260 #define ROCKBLOX_RIGHT BUTTON_RIGHT
261 #define ROCKBLOX_DROP BUTTON_PLAY
262 #define ROCKBLOX_RESTART BUTTON_MENU
264 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
265 #define ROCKBLOX_OFF BUTTON_BACK
266 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
267 #define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
268 #define ROCKBLOX_DOWN BUTTON_DOWN
269 #define ROCKBLOX_LEFT BUTTON_LEFT
270 #define ROCKBLOX_RIGHT BUTTON_RIGHT
271 #define ROCKBLOX_DROP BUTTON_SELECT
272 #define ROCKBLOX_RESTART BUTTON_CUSTOM
274 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
276 #define ROCKBLOX_OFF BUTTON_POWER
277 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
278 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
279 #define ROCKBLOX_ROTATE BUTTON_UP
280 #define ROCKBLOX_DOWN BUTTON_DOWN
281 #define ROCKBLOX_LEFT BUTTON_LEFT
282 #define ROCKBLOX_RIGHT BUTTON_RIGHT
283 #define ROCKBLOX_DROP BUTTON_SELECT
284 #define ROCKBLOX_RESTART BUTTON_MENU
286 #elif CONFIG_KEYPAD == ONDAVX747_PAD
287 #define ROCKBLOX_OFF BUTTON_POWER
288 #define ROCKBLOX_RESTART BUTTON_MENU
290 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
292 #define ROCKBLOX_OFF (BUTTON_REC|BUTTON_PLAY)
293 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
294 #define ROCKBLOX_ROTATE_LEFT BUTTON_DOWN
295 #define ROCKBLOX_DOWN BUTTON_REW
296 #define ROCKBLOX_LEFT BUTTON_LEFT
297 #define ROCKBLOX_RIGHT BUTTON_RIGHT
298 #define ROCKBLOX_DROP BUTTON_FFWD
299 #define ROCKBLOX_RESTART (BUTTON_REC|BUTTON_REW)
302 #error No keymap defined!
305 #ifdef HAVE_TOUCHSCREEN
307 #define ROCKBLOX_OFF BUTTON_TOPLEFT
309 #ifndef ROCKBLOX_ROTATE_RIGHT
310 #define ROCKBLOX_ROTATE_RIGHT BUTTON_BOTTOMRIGHT
312 #ifndef ROCKBLOX_ROTATE_LEFT
313 #define ROCKBLOX_ROTATE_LEFT BUTTON_BOTTOMLEFT
315 #ifndef ROCKBLOX_DOWN
316 #define ROCKBLOX_DOWN BUTTON_BOTTOMMIDDLE
318 #ifndef ROCKBLOX_LEFT
319 #define ROCKBLOX_LEFT BUTTON_MIDLEFT
321 #ifndef ROCKBLOX_RIGHT
322 #define ROCKBLOX_RIGHT BUTTON_MIDRIGHT
324 #ifndef ROCKBLOX_DROP
325 #define ROCKBLOX_DROP BUTTON_CENTER
327 #ifndef ROCKBLOX_RESTART
328 #define ROCKBLOX_RESTART BUTTON_TOPRIGHT
333 #define EMPTY_BLOCK 7
335 #define BOARD_WIDTH 10
337 #ifdef HAVE_LCD_BITMAP
339 #define BOARD_HEIGHT 20
341 #if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
343 #define BLOCK_WIDTH 24
344 #define BLOCK_HEIGHT 24
354 #elif (LCD_WIDTH == 480) && (LCD_HEIGHT == 640)
356 #define BLOCK_WIDTH 30
357 #define BLOCK_HEIGHT 30
360 #define PREVIEW_X 342
361 #define PREVIEW_Y 482
367 #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
369 #define BLOCK_WIDTH 12
370 #define BLOCK_HEIGHT 12
380 #elif (LCD_WIDTH == 240) && ((LCD_HEIGHT == 320) || (LCD_HEIGHT == 400))
382 #define BLOCK_WIDTH 15
383 #define BLOCK_HEIGHT 15
386 #define PREVIEW_X 171
387 #define PREVIEW_Y 241
392 #define HIGH_LABEL_X 172
393 #define HIGH_SCORE_Y 163
394 #define HIGH_LEVEL_Y 172
396 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
398 #define BLOCK_WIDTH 8
399 #define BLOCK_HEIGHT 8
402 #define PREVIEW_X 158
403 #define PREVIEW_Y 130
409 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
411 #define BLOCK_WIDTH 6
412 #define BLOCK_HEIGHT 6
415 #define PREVIEW_X 126
416 #define PREVIEW_Y 102
422 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
424 /* no room for the space in the highscore list */
427 #define BLOCK_WIDTH 10
428 #define BLOCK_HEIGHT 10
431 #define PREVIEW_X 124
432 #define PREVIEW_Y 174
437 #define HIGH_SCORE_Y 119
438 #define HIGH_LEVEL_Y 126
439 #define HIGH_LABEL_X 114
441 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
444 #define BLOCK_WIDTH 6
445 #define BLOCK_HEIGHT 6
448 #define PREVIEW_X 114
449 #define PREVIEW_Y 100
455 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
457 #define BLOCK_WIDTH 5
458 #define BLOCK_HEIGHT 5
468 #elif (LCD_WIDTH == 132) && (LCD_HEIGHT == 80)
470 #define BLOCK_WIDTH 4
471 #define BLOCK_HEIGHT 4
481 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
483 #define BLOCK_WIDTH 6
484 #define BLOCK_HEIGHT 6
488 #define PREVIEW_Y 100
494 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 96)
496 #define BLOCK_WIDTH 4
497 #define BLOCK_HEIGHT 4
507 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 64)
509 #define BLOCK_WIDTH 3
510 #define BLOCK_HEIGHT 3
520 #elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
522 #define BLOCK_WIDTH 4
523 #define BLOCK_HEIGHT 3
537 #define LEVEL_X LABEL_X
541 #define LINES_X LABEL_X
544 #define MYLCD(fn) rb->lcd_ ## fn
546 extern const fb_data rockblox_background
[];
548 #else /* HAVE_LCD_CHARCELLS */
550 #define BOARD_HEIGHT 14
552 #define BLOCK_WIDTH 1
553 #define BLOCK_HEIGHT 1
559 #define MYLCD(fn) pgfx_ ## fn
566 /* <<Explanation on Rockblox shapes>>
569 %% - O has 1 orientation
572 %% %% - Z has 2 orientations
576 %% %% - S has 2 orientations
580 % %%%% - I has 2 orientations
584 % % % %%% - L has 4 orientations
588 % % % %%% - J has 4 orientations
592 %% % %% % - T has 4 orientations
596 /* c=current f=figure o=orientation n=next */
597 static struct _rockblox_status
608 short board
[BOARD_HEIGHT
][BOARD_WIDTH
]; /* 20 rows of 10 blocks */
612 static void draw_next_block(void);
613 static void new_block(void);
615 #ifdef HAVE_SCROLLWHEEL
616 int wheel_events
= 0, last_wheel_event
= 0;
617 bool wheel_enabled
= false;
620 static const short scoring
[4] = { /* scoring for each number of lines */
621 #if BOARD_HEIGHT == 20
622 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
623 #elif BOARD_HEIGHT == 14 /* Player special values */
624 60 /* single */ , 150 /* double */ , 500 /* triple */ , 2000 /* rockblox */
631 unsigned short color
[3]; /* color of figure (light,middle,shadow) */
633 unsigned short max_or
; /* max orientations */
634 signed short shapeX
[4], shapeY
[4]; /* implementation of figures */
637 /* array of figures */
638 figures
[BLOCKS_NUM
] = {
642 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
643 LCD_RGBPACK(0,153,153)},
645 {LCD_WHITE
, LCD_LIGHTGRAY
, LCD_DARKGRAY
},
654 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
655 LCD_RGBPACK (153, 0, 0)},
657 {LCD_WHITE
, LCD_LIGHTGRAY
, LCD_DARKGRAY
},
666 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
667 LCD_RGBPACK (0, 153, 0)},
669 {LCD_WHITE
, LCD_LIGHTGRAY
, LCD_DARKGRAY
},
678 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
679 LCD_RGBPACK (0, 0, 153)},
681 {LCD_WHITE
, LCD_LIGHTGRAY
, LCD_DARKGRAY
},
690 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
691 LCD_RGBPACK (153, 153, 0)},
693 {LCD_WHITE
, LCD_LIGHTGRAY
, LCD_DARKGRAY
},
702 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
703 LCD_RGBPACK (153, 0, 153)},
705 {LCD_WHITE
, LCD_LIGHTGRAY
, LCD_DARKGRAY
},
714 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
715 LCD_RGBPACK (85, 85, 85)},
717 {LCD_WHITE
, LCD_LIGHTGRAY
, LCD_DARKGRAY
},
725 /* Rockbox File System only supports full filenames inc dir */
726 #define HIGH_SCORE PLUGIN_GAMES_DIR "/rockblox.score"
727 #define RESUME_FILE PLUGIN_GAMES_DIR "/rockblox.resume"
728 #define MAX_HIGH_SCORES 5
730 /* Default High Scores... */
731 struct highscore highest
[MAX_HIGH_SCORES
];
733 /* get random number from (0) to (range-1) */
734 static int t_rand (int range
)
736 return rb
->rand () % range
;
739 static inline void show_game_over (void)
741 rb
->splash(HZ
,"Game over!");
744 /* init the board array to have no blocks */
745 static void init_board (void)
748 for (i
= 0; i
< BOARD_WIDTH
; i
++)
749 for (j
= 0; j
< BOARD_HEIGHT
; j
++)
750 rockblox_status
.board
[j
][i
] = EMPTY_BLOCK
;
753 /* show the score, level and lines */
754 static void show_details (void)
756 char str
[25]; /* for strings */
758 #ifdef HAVE_LCD_BITMAP
760 rb
->lcd_set_foreground (LCD_BLACK
);
761 rb
->lcd_set_background (LCD_WHITE
);
763 rb
->snprintf (str
, sizeof (str
), "%d", rockblox_status
.score
);
764 rb
->lcd_putsxy (LABEL_X
, SCORE_Y
, str
);
765 rb
->snprintf (str
, sizeof (str
), "%d", rockblox_status
.level
);
766 rb
->lcd_putsxy (LEVEL_X
, LEVEL_Y
, str
);
767 rb
->snprintf (str
, sizeof (str
), "%d", rockblox_status
.lines
);
768 rb
->lcd_putsxy (LINES_X
, LINES_Y
, str
);
769 #else /* HAVE_LCD_CHARCELLS */
770 rb
->snprintf (str
, sizeof (str
), "L%d/%d", rockblox_status
.level
,
771 rockblox_status
.lines
);
772 rb
->lcd_puts (5, 0, str
);
773 rb
->snprintf (str
, sizeof (str
), "S%d", rockblox_status
.score
);
774 rb
->lcd_puts (5, 1, str
);
779 static void show_highscores (void)
782 char str
[25]; /* for strings */
784 for (i
= 0; i
<MAX_HIGH_SCORES
; i
++)
786 rb
->snprintf (str
, sizeof (str
), "%06d" _SPACE
"L%1d",
787 highest
[i
].score
, highest
[i
].level
);
788 rb
->lcd_putsxy (HIGH_LABEL_X
, HIGH_SCORE_Y
+ (10 * i
), str
);
793 /* Returns >0 on successful read AND if the game wasn't over, else 0 */
794 static int load_resume(void)
797 fd
= rb
->open(RESUME_FILE
, O_RDONLY
);
801 if (rb
->read(fd
, &rockblox_status
, sizeof(struct _rockblox_status
))
802 < (ssize_t
)sizeof(struct _rockblox_status
))
804 rb
->splash(HZ
/2, "Loading Rockblox resume info failed");
810 if (rockblox_status
.gameover
)
813 return !rockblox_status
.gameover
;
816 /* Returns >0 on success, else 0 */
817 static int dump_resume(void)
821 fd
= rb
->open(RESUME_FILE
, O_WRONLY
|O_CREAT
);
825 if (rb
->write(fd
, &rockblox_status
, sizeof(struct _rockblox_status
))
835 rb
->splash(HZ
/2, "Writing Rockblox resume info failed");
838 static void init_rockblox (bool resume
)
844 rb
->snprintf(score_name
, sizeof(score_name
), "%04d%02d%02d %02d%02d%02d",
845 tm
->tm_year
+ 1900, tm
->tm_mon
+ 1, tm
->tm_mday
,
846 tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
848 highscore_update(rockblox_status
.score
, rockblox_status
.level
,
849 score_name
, highest
, MAX_HIGH_SCORES
);
851 #ifdef HAVE_LCD_BITMAP
852 rb
->lcd_bitmap (rockblox_background
, 0, 0, LCD_WIDTH
, LCD_HEIGHT
);
853 #else /* HAVE_LCD_CHARCELLS */
855 pgfx_display_block (3, 0, 3, 1);
856 pgfx_display_block (4, 0, 3, 0);
857 pgfx_clear_display();
858 pgfx_fillrect (3, 0, 2, 14);
859 pgfx_fillrect (15, 7, 2, 7);
862 if (!resume
|| !load_resume())
864 rockblox_status
.level
= 1;
865 rockblox_status
.lines
= 0;
866 rockblox_status
.score
= 0;
867 rockblox_status
.nf
= t_rand(BLOCKS_NUM
);
879 static inline int level_speed(int level
)
881 #if BOARD_HEIGHT == 20
882 return (5*HZ
) / (level
+ 9);
883 #elif BOARD_HEIGHT == 14
884 return (7*HZ
) / (level
+ 9);
888 static int getRelativeX (int figure
, int square
, int orientation
)
890 switch (orientation
) {
892 return figures
[figure
].shapeX
[square
];
894 return figures
[figure
].shapeY
[square
];
896 return -figures
[figure
].shapeX
[square
];
898 return -figures
[figure
].shapeY
[square
];
904 static int getRelativeY (int figure
, int square
, int orientation
)
906 switch (orientation
) {
908 return figures
[figure
].shapeY
[square
];
910 return -figures
[figure
].shapeX
[square
];
912 return -figures
[figure
].shapeY
[square
];
914 return figures
[figure
].shapeX
[square
];
920 /* redraw the while board on the screen */
921 static void refresh_board (void)
923 int i
, j
, x
, y
, block
;
926 rb
->lcd_set_foreground (LCD_BLACK
);
928 MYLCD(set_drawmode
) (DRMODE_SOLID
| DRMODE_INVERSEVID
);
931 MYLCD(fillrect
) (BOARD_X
, BOARD_Y
, BOARD_WIDTH
* BLOCK_WIDTH
,
932 BOARD_HEIGHT
* BLOCK_HEIGHT
);
935 MYLCD(set_drawmode
) (DRMODE_SOLID
);
938 for (i
= 0; i
< BOARD_WIDTH
; i
++)
939 for (j
= 0; j
< BOARD_HEIGHT
; j
++) {
940 block
= rockblox_status
.board
[j
][i
];
941 if (block
!= EMPTY_BLOCK
) {
942 #ifdef HAVE_LCD_BITMAP
945 rb
->lcd_set_foreground (figures
[block
].color
[1]);
947 rb
->lcd_fillrect (BOARD_X
+ i
* BLOCK_WIDTH
,
948 BOARD_Y
+ j
* BLOCK_HEIGHT
,
949 BLOCK_WIDTH
, BLOCK_HEIGHT
);
952 rb
->lcd_set_foreground (figures
[block
].color
[0]);
954 rb
->lcd_vline (BOARD_X
+ i
* BLOCK_WIDTH
,
955 BOARD_Y
+ j
* BLOCK_HEIGHT
,
956 BOARD_Y
+ (j
+ 1) * BLOCK_HEIGHT
- 2);
957 rb
->lcd_hline (BOARD_X
+ i
* BLOCK_WIDTH
,
958 BOARD_X
+ (i
+ 1) * BLOCK_WIDTH
- 2,
959 BOARD_Y
+ j
* BLOCK_HEIGHT
);
962 rb
->lcd_set_foreground (figures
[block
].color
[2]);
964 rb
->lcd_vline (BOARD_X
+ (i
+ 1) * BLOCK_WIDTH
- 1,
965 BOARD_Y
+ j
* BLOCK_HEIGHT
+ 1,
966 BOARD_Y
+ (j
+ 1) * BLOCK_HEIGHT
- 1);
967 rb
->lcd_hline (BOARD_X
+ i
* BLOCK_WIDTH
+ 1,
968 BOARD_X
+ (i
+ 1) * BLOCK_WIDTH
- 1,
969 BOARD_Y
+ (j
+ 1) * BLOCK_HEIGHT
- 1);
970 #else /* HAVE_LCD_CHARCELLS */
971 pgfx_drawpixel (BOARD_X
+ i
, BOARD_Y
+ j
);
976 for (i
= 0; i
< 4; i
++) {
977 x
= getRelativeX (rockblox_status
.cf
, i
, rockblox_status
.co
)
978 + rockblox_status
.cx
;
979 y
= getRelativeY (rockblox_status
.cf
, i
, rockblox_status
.co
)
980 + rockblox_status
.cy
;
981 #ifdef HAVE_LCD_BITMAP
984 rb
->lcd_set_foreground (figures
[rockblox_status
.cf
].color
[1]);
986 rb
->lcd_fillrect (BOARD_X
+ x
* BLOCK_WIDTH
,
987 BOARD_Y
+ y
* BLOCK_HEIGHT
,
988 BLOCK_WIDTH
, BLOCK_HEIGHT
);
991 rb
->lcd_set_foreground (figures
[rockblox_status
.cf
].color
[0]);
993 rb
->lcd_vline (BOARD_X
+ x
* BLOCK_WIDTH
, BOARD_Y
+ y
* BLOCK_HEIGHT
,
994 BOARD_Y
+ (y
+ 1) * BLOCK_HEIGHT
- 2);
995 rb
->lcd_hline (BOARD_X
+ x
* BLOCK_WIDTH
,
996 BOARD_X
+ (x
+ 1) * BLOCK_WIDTH
- 2,
997 BOARD_Y
+ y
* BLOCK_HEIGHT
);
1000 rb
->lcd_set_foreground (figures
[rockblox_status
.cf
].color
[2]);
1002 rb
->lcd_vline (BOARD_X
+ (x
+ 1) * BLOCK_WIDTH
- 1,
1003 BOARD_Y
+ y
* BLOCK_HEIGHT
+ 1,
1004 BOARD_Y
+ (y
+ 1) * BLOCK_HEIGHT
- 1);
1005 rb
->lcd_hline (BOARD_X
+ x
* BLOCK_WIDTH
+ 1,
1006 BOARD_X
+ (x
+ 1) * BLOCK_WIDTH
- 1,
1007 BOARD_Y
+ (y
+ 1) * BLOCK_HEIGHT
- 1);
1008 #else /* HAVE_LCD_CHARCELLS */
1009 pgfx_drawpixel (BOARD_X
+ x
, BOARD_Y
+ y
);
1015 static bool canMoveTo (int x
, int y
, int newOrientation
)
1018 for (i
= 0; i
< 4; i
++) {
1019 ry
= getRelativeY (rockblox_status
.cf
, i
, newOrientation
) + y
;
1020 rx
= getRelativeX (rockblox_status
.cf
, i
, newOrientation
) + x
;
1021 if ((rx
< 0 || rx
>= BOARD_WIDTH
) ||
1022 (ry
< 0 || ry
>= BOARD_HEIGHT
) ||
1023 (rockblox_status
.board
[ry
][rx
] != EMPTY_BLOCK
))
1029 /* draws the preview of next block in the preview window */
1030 static void draw_next_block (void)
1033 /* clear preview window first */
1035 rb
->lcd_set_foreground (LCD_BLACK
);
1036 #elif LCD_DEPTH == 1
1037 MYLCD(set_drawmode
) (DRMODE_SOLID
| DRMODE_INVERSEVID
);
1041 MYLCD(fillrect
) (PREVIEW_X
, PREVIEW_Y
, BLOCK_WIDTH
* 4, BLOCK_HEIGHT
* 4);
1044 MYLCD(set_drawmode
) (DRMODE_SOLID
);
1047 /* draw the lightgray rectangles */
1049 rb
->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
1050 #elif LCD_DEPTH == 2
1051 rb
->lcd_set_foreground (LCD_DARKGRAY
);
1055 for (rx
= 0; rx
< 4; rx
++)
1056 for (ry
= 0; ry
< 4; ry
++)
1057 rb
->lcd_drawrect (PREVIEW_X
+ rx
* BLOCK_WIDTH
,
1058 PREVIEW_Y
+ ry
* BLOCK_HEIGHT
, BLOCK_WIDTH
,
1062 /* draw the figure */
1063 for (i
= 0; i
< 4; i
++) {
1064 rx
= getRelativeX (rockblox_status
.nf
, i
, 0) + 2;
1065 ry
= getRelativeY (rockblox_status
.nf
, i
, 0) + 2;
1066 #ifdef HAVE_LCD_BITMAP
1068 rb
->lcd_set_foreground (figures
[rockblox_status
.nf
].color
[1]); /* middle drawing */
1070 rb
->lcd_fillrect (PREVIEW_X
+ rx
* BLOCK_WIDTH
,
1071 PREVIEW_Y
+ ry
* BLOCK_HEIGHT
,
1072 BLOCK_WIDTH
, BLOCK_HEIGHT
);
1074 rb
->lcd_set_foreground (figures
[rockblox_status
.nf
].color
[0]); /* light drawing */
1076 rb
->lcd_vline (PREVIEW_X
+ rx
* BLOCK_WIDTH
,
1077 PREVIEW_Y
+ ry
* BLOCK_HEIGHT
,
1078 PREVIEW_Y
+ (ry
+ 1) * BLOCK_HEIGHT
- 2);
1079 rb
->lcd_hline (PREVIEW_X
+ rx
* BLOCK_WIDTH
,
1080 PREVIEW_X
+ (rx
+ 1) * BLOCK_WIDTH
- 2,
1081 PREVIEW_Y
+ ry
* BLOCK_HEIGHT
);
1083 rb
->lcd_set_foreground (figures
[rockblox_status
.nf
].color
[2]); /* shadow drawing */
1085 rb
->lcd_vline (PREVIEW_X
+ (rx
+ 1) * BLOCK_WIDTH
- 1,
1086 PREVIEW_Y
+ ry
* BLOCK_HEIGHT
+ 1,
1087 PREVIEW_Y
+ (ry
+ 1) * BLOCK_HEIGHT
- 1);
1088 rb
->lcd_hline (PREVIEW_X
+ rx
* BLOCK_WIDTH
+ 1,
1089 PREVIEW_X
+ (rx
+ 1) * BLOCK_WIDTH
- 1,
1090 PREVIEW_Y
+ (ry
+ 1) * BLOCK_HEIGHT
- 1);
1091 #else /* HAVE_LCD_CHARCELLS */
1092 pgfx_drawpixel (PREVIEW_X
+ rx
, PREVIEW_Y
+ ry
);
1098 /* move the block to a relative location */
1099 static void move_block (int x
, int y
, int o
)
1101 if (canMoveTo (rockblox_status
.cx
+ x
, rockblox_status
.cy
+ y
, o
)) {
1102 rockblox_status
.cy
+= y
;
1103 rockblox_status
.cx
+= x
;
1104 rockblox_status
.co
= o
;
1108 /* try to add a new block to play with (return true if gameover) */
1109 static void new_block (void)
1111 rockblox_status
.cy
= 1;
1112 rockblox_status
.cx
= 5;
1113 rockblox_status
.cf
= rockblox_status
.nf
;
1114 rockblox_status
.co
= 0; /* start at the same orientation all time */
1115 rockblox_status
.nf
= t_rand (BLOCKS_NUM
);
1116 rockblox_status
.gameover
= !canMoveTo (rockblox_status
.cx
,
1117 rockblox_status
.cy
, rockblox_status
.co
);
1123 /* check for filled rockblox_status.lines and do what necessary */
1124 static int check_lines (void)
1130 for (j
= 0; j
< BOARD_HEIGHT
; j
++) {
1131 for (i
= 0; ((i
< BOARD_WIDTH
) &&
1132 (rockblox_status
.board
[j
][i
] != EMPTY_BLOCK
)); i
++);
1133 if (i
== BOARD_WIDTH
) { /* woo hoo, we have a line */
1135 for (y
= j
; y
> 0; y
--)
1137 for (i
= 0; i
< BOARD_WIDTH
; i
++)
1139 rockblox_status
.board
[y
][i
] = rockblox_status
.board
[y
- 1][i
];
1148 /* moves down the figure and returns true if gameover */
1149 static void move_down (void)
1153 if (!canMoveTo (rockblox_status
.cx
, rockblox_status
.cy
+ 1, rockblox_status
.co
)) {
1154 /* save figure to board */
1155 for (i
= 0; i
< 4; i
++) {
1156 rx
= getRelativeX (rockblox_status
.cf
, i
, rockblox_status
.co
) + rockblox_status
.cx
;
1157 ry
= getRelativeY (rockblox_status
.cf
, i
, rockblox_status
.co
) + rockblox_status
.cy
;
1158 rockblox_status
.board
[ry
][rx
] = rockblox_status
.cf
;
1160 /* check if formed some lines */
1163 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
1164 rockblox_status
.score
+= scoring
[l
- 1] * rockblox_status
.level
;
1165 rockblox_status
.lines
+= l
;
1166 rockblox_status
.level
= (int) rockblox_status
.lines
/ 10 + 1;
1172 /* generate a new figure */
1175 move_block (0, 1, rockblox_status
.co
);
1178 static int rockblox_loop (void)
1181 int lastbutton
= BUTTON_NONE
;
1182 long next_down_tick
= *rb
->current_tick
+ level_speed(rockblox_status
.level
);
1185 #ifdef HAS_BUTTON_HOLD
1186 if (rb
->button_hold ()) {
1187 /* Turn on backlight timeout (revert to settings) */
1188 backlight_use_settings(); /* backlight control in lib/helper.c */
1189 rb
->splash(0, "Paused");
1190 while (rb
->button_hold ())
1193 /* Turn off backlight timeout */
1194 backlight_force_on(); /* backlight control in lib/helper.c */
1196 /* get rid of the splash text */
1197 rb
->lcd_bitmap (rockblox_background
, 0, 0, LCD_WIDTH
, LCD_HEIGHT
);
1207 button
= rb
->button_get_w_tmo (MAX(next_down_tick
- *rb
->current_tick
, 1));
1209 #ifdef ROCKBLOX_RC_OFF
1210 case ROCKBLOX_RC_OFF
:
1213 #ifdef ROCKBLOX_OFF_PRE
1214 if (lastbutton
!= ROCKBLOX_OFF_PRE
)
1219 #if defined(ROCKBLOX_ROTATE)
1220 case ROCKBLOX_ROTATE
:
1222 case ROCKBLOX_ROTATE_RIGHT
:
1223 case ROCKBLOX_ROTATE_RIGHT
| BUTTON_REPEAT
:
1224 #ifdef HAVE_SCROLLWHEEL
1225 /* if the wheel is disabled, add an event to the stack. */
1226 if(wheel_enabled
== false)
1229 /* if it's enabled, go ahead and rotate.. */
1232 move_block (0, 0, (rockblox_status
.co
+ 1) % figures
[rockblox_status
.cf
].max_or
);
1235 case ROCKBLOX_ROTATE_LEFT
:
1236 case ROCKBLOX_ROTATE_LEFT
| BUTTON_REPEAT
:
1237 #ifdef HAVE_SCROLLWHEEL
1238 if(wheel_enabled
== false)
1244 (rockblox_status
.co
+ figures
[rockblox_status
.cf
].max_or
-
1245 1) % figures
[rockblox_status
.cf
].max_or
);
1248 #ifdef ROCKBLOX_ROTATE_RIGHT2
1249 case ROCKBLOX_ROTATE_RIGHT2
:
1250 move_block (0, 0, (rockblox_status
.co
+ 1) % figures
[rockblox_status
.cf
].max_or
);
1255 case ROCKBLOX_DOWN
| BUTTON_REPEAT
:
1256 move_block (0, 1, rockblox_status
.co
);
1259 case ROCKBLOX_RIGHT
:
1260 case ROCKBLOX_RIGHT
| BUTTON_REPEAT
:
1261 move_block (1, 0, rockblox_status
.co
);
1265 case ROCKBLOX_LEFT
| BUTTON_REPEAT
:
1266 move_block (-1, 0, rockblox_status
.co
);
1270 #ifdef ROCKBLOX_DROP_PRE
1271 if (lastbutton
!= ROCKBLOX_DROP_PRE
)
1274 while (canMoveTo (rockblox_status
.cx
, rockblox_status
.cy
+ 1, rockblox_status
.co
))
1275 move_block (0, 1, rockblox_status
.co
);
1277 #ifdef ROCKBLOX_RESTART
1278 case ROCKBLOX_RESTART
:
1279 rb
->splash (HZ
* 1, "Restarting...");
1280 init_rockblox (false);
1285 if (rb
->default_event_handler (button
) == SYS_USB_CONNECTED
)
1286 return PLUGIN_USB_CONNECTED
;
1289 if (button
!= BUTTON_NONE
)
1290 lastbutton
= button
;
1292 #ifdef HAVE_SCROLLWHEEL
1293 /* check if we should enable the scroll wheel, if events
1294 * begin to stack up... */
1295 if(wheel_enabled
== false)
1297 /* stopped rotating the wheel, reset the count */
1298 if(wheel_events
== last_wheel_event
)
1300 last_wheel_event
= 0;
1303 /* rotated the wheel a while constantly, enable it. */
1304 else if(wheel_events
> 3)
1306 wheel_enabled
= true;
1309 /* this evens out the last event and the "current" event.
1310 * if we get an event next time through button reading, it will
1311 * remain ahead of last_event. if we don't, they'll end up equaling
1312 * each other.. thus, the scroll count will be reset. */
1313 if(wheel_enabled
== false && wheel_events
> last_wheel_event
)
1318 if (TIME_AFTER(*rb
->current_tick
, next_down_tick
)) {
1320 next_down_tick
+= level_speed(rockblox_status
.level
);
1321 if (TIME_AFTER(*rb
->current_tick
, next_down_tick
))
1322 /* restart time "raster" when we had to wait longer than usual
1323 * (pause, game restart etc) */
1324 next_down_tick
= *rb
->current_tick
+ level_speed(rockblox_status
.level
);
1327 if (rockblox_status
.gameover
) {
1329 rb
->lcd_set_foreground (LCD_BLACK
);
1332 init_rockblox (false);
1341 enum plugin_status
plugin_start (const void *parameter
)
1347 rb
->srand (*rb
->current_tick
);
1349 /* Load HighScore if any */
1350 highscore_load(HIGH_SCORE
, highest
, MAX_HIGH_SCORES
);
1353 rb
->lcd_set_backdrop(NULL
);
1356 #ifdef HAVE_LCD_BITMAP
1357 rb
->lcd_setfont (FONT_SYSFIXED
);
1359 if (!pgfx_init(4, 2))
1361 rb
->splash(HZ
*2, "Old LCD :(");
1365 /* Turn off backlight timeout */
1366 backlight_force_on(); /* backlight control in lib/helper.c */
1368 init_rockblox (true);
1369 ret
= rockblox_loop ();
1371 #ifndef HAVE_LCD_BITMAP
1374 /* Save user's HighScore */
1375 highscore_save(HIGH_SCORE
, highest
, MAX_HIGH_SCORES
);
1376 backlight_use_settings(); /* backlight control in lib/helper.c */