New plugin: FFT, A frequency analyzer plugin
[kugel-rb.git] / apps / plugins / rockblox.c
blob95a793fb8c6a05f2179dda3e69a5481edce3e6c3
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/display_text.h"
25 #include "lib/helper.h"
26 #include "lib/highscore.h"
27 #include "lib/playback_control.h"
28 #include "lib/playergfx.h"
30 PLUGIN_HEADER
32 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
33 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
34 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
36 #define ROCKBLOX_OFF (BUTTON_MENU | BUTTON_SELECT)
37 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
38 #define ROCKBLOX_ROTATE_RIGHT2 (BUTTON_MENU | BUTTON_REL)
39 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
40 #define ROCKBLOX_LEFT BUTTON_LEFT
41 #define ROCKBLOX_RIGHT BUTTON_RIGHT
42 #define ROCKBLOX_DOWN BUTTON_PLAY
43 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_PLAY)
44 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
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_PRE BUTTON_STOP
85 #define ROCKBLOX_OFF (BUTTON_STOP|BUTTON_REL)
86 #define ROCKBLOX_ROTATE_RIGHT BUTTON_PLAY
87 #define ROCKBLOX_ROTATE_LEFT (BUTTON_ON|BUTTON_PLAY)
88 #define ROCKBLOX_DOWN BUTTON_MENU
89 #define ROCKBLOX_LEFT BUTTON_LEFT
90 #define ROCKBLOX_RIGHT BUTTON_RIGHT
91 #define ROCKBLOX_DROP_PRE BUTTON_ON
92 #define ROCKBLOX_DROP (BUTTON_ON|BUTTON_REL)
93 #define ROCKBLOX_RESTART (BUTTON_STOP|BUTTON_MENU)
95 #elif CONFIG_KEYPAD == ONDIO_PAD
97 #define ROCKBLOX_OFF_PRE BUTTON_OFF
98 #define ROCKBLOX_OFF (BUTTON_OFF|BUTTON_REL)
99 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
100 #define ROCKBLOX_ROTATE_LEFT (BUTTON_MENU|BUTTON_UP)
101 #define ROCKBLOX_DOWN BUTTON_DOWN
102 #define ROCKBLOX_LEFT BUTTON_LEFT
103 #define ROCKBLOX_RIGHT BUTTON_RIGHT
104 #define ROCKBLOX_DROP_PRE BUTTON_MENU
105 #define ROCKBLOX_DROP (BUTTON_MENU|BUTTON_REL)
106 #define ROCKBLOX_RESTART (BUTTON_OFF|BUTTON_MENU)
108 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
110 #define ROCKBLOX_OFF BUTTON_POWER
111 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
112 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
113 #define ROCKBLOX_DOWN BUTTON_DOWN
114 #define ROCKBLOX_LEFT BUTTON_LEFT
115 #define ROCKBLOX_RIGHT BUTTON_RIGHT
116 #define ROCKBLOX_DROP BUTTON_REC
117 #define ROCKBLOX_RESTART BUTTON_PLAY
119 #elif CONFIG_KEYPAD == SANSA_E200_PAD
121 #define ROCKBLOX_OFF BUTTON_POWER
122 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
123 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_UP
124 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
125 #define ROCKBLOX_DOWN BUTTON_DOWN
126 #define ROCKBLOX_LEFT BUTTON_LEFT
127 #define ROCKBLOX_RIGHT BUTTON_RIGHT
128 #define ROCKBLOX_DROP BUTTON_SELECT
129 #define ROCKBLOX_RESTART BUTTON_REC
131 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
133 #define ROCKBLOX_OFF (BUTTON_HOME|BUTTON_REPEAT)
134 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
135 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_UP
136 #define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
137 #define ROCKBLOX_DOWN BUTTON_DOWN
138 #define ROCKBLOX_LEFT BUTTON_LEFT
139 #define ROCKBLOX_RIGHT BUTTON_RIGHT
140 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
141 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_UP)
144 #elif CONFIG_KEYPAD == SANSA_C200_PAD
146 #define ROCKBLOX_OFF BUTTON_POWER
147 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
148 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_VOL_DOWN
149 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
150 #define ROCKBLOX_DOWN BUTTON_DOWN
151 #define ROCKBLOX_LEFT BUTTON_LEFT
152 #define ROCKBLOX_RIGHT BUTTON_RIGHT
153 #define ROCKBLOX_DROP BUTTON_SELECT
154 #define ROCKBLOX_RESTART BUTTON_REC
156 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
158 #define ROCKBLOX_OFF BUTTON_POWER
159 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
160 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_VOL_DOWN
161 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
162 #define ROCKBLOX_DOWN BUTTON_DOWN
163 #define ROCKBLOX_LEFT BUTTON_LEFT
164 #define ROCKBLOX_RIGHT BUTTON_RIGHT
165 #define ROCKBLOX_DROP BUTTON_SELECT
166 #define ROCKBLOX_RESTART BUTTON_HOME
168 #elif CONFIG_KEYPAD == SANSA_M200_PAD
170 #define ROCKBLOX_OFF BUTTON_POWER
171 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
172 #define ROCKBLOX_ROTATE_RIGHT2 BUTTON_VOL_DOWN
173 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
174 #define ROCKBLOX_DOWN BUTTON_DOWN
175 #define ROCKBLOX_LEFT BUTTON_LEFT
176 #define ROCKBLOX_RIGHT BUTTON_RIGHT
177 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_UP)
178 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
180 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
182 #define ROCKBLOX_OFF BUTTON_POWER
183 #define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_UP
184 #define ROCKBLOX_ROTATE_LEFT BUTTON_REW
185 #define ROCKBLOX_DOWN BUTTON_SCROLL_DOWN
186 #define ROCKBLOX_LEFT BUTTON_LEFT
187 #define ROCKBLOX_RIGHT BUTTON_RIGHT
188 #define ROCKBLOX_DROP BUTTON_FF
189 #define ROCKBLOX_RESTART BUTTON_PLAY
191 #elif CONFIG_KEYPAD == GIGABEAT_PAD
193 #define ROCKBLOX_OFF BUTTON_POWER
194 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
195 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
196 #define ROCKBLOX_ROTATE BUTTON_UP
197 #define ROCKBLOX_DOWN BUTTON_DOWN
198 #define ROCKBLOX_LEFT BUTTON_LEFT
199 #define ROCKBLOX_RIGHT BUTTON_RIGHT
200 #define ROCKBLOX_DROP BUTTON_SELECT
201 #define ROCKBLOX_RESTART BUTTON_A
203 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
205 #define ROCKBLOX_OFF BUTTON_PLAY
206 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
207 #define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
208 #define ROCKBLOX_DOWN BUTTON_DOWN
209 #define ROCKBLOX_LEFT BUTTON_LEFT
210 #define ROCKBLOX_RIGHT BUTTON_RIGHT
211 #define ROCKBLOX_DROP BUTTON_MODE
212 #define ROCKBLOX_RESTART BUTTON_EQ
214 #elif CONFIG_KEYPAD == MROBE500_PAD
215 #define ROCKBLOX_OFF BUTTON_POWER
217 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
218 #define ROCKBLOX_OFF BUTTON_BACK
219 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
220 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
221 #define ROCKBLOX_ROTATE BUTTON_UP
222 #define ROCKBLOX_DOWN BUTTON_DOWN
223 #define ROCKBLOX_LEFT BUTTON_LEFT
224 #define ROCKBLOX_RIGHT BUTTON_RIGHT
225 #define ROCKBLOX_DROP BUTTON_SELECT
226 #define ROCKBLOX_RESTART BUTTON_PLAY
228 #elif CONFIG_KEYPAD == MROBE100_PAD
230 #define ROCKBLOX_OFF BUTTON_POWER
231 #define ROCKBLOX_ROTATE_RIGHT BUTTON_MENU
232 #define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
233 #define ROCKBLOX_ROTATE BUTTON_UP
234 #define ROCKBLOX_DOWN BUTTON_DOWN
235 #define ROCKBLOX_LEFT BUTTON_LEFT
236 #define ROCKBLOX_RIGHT BUTTON_RIGHT
237 #define ROCKBLOX_DROP BUTTON_SELECT
238 #define ROCKBLOX_RESTART BUTTON_DISPLAY
240 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
242 #define ROCKBLOX_OFF BUTTON_RC_REC
243 #define ROCKBLOX_ROTATE_RIGHT BUTTON_RC_VOL_DOWN
244 #define ROCKBLOX_ROTATE_LEFT BUTTON_RC_VOL_UP
245 #define ROCKBLOX_DOWN BUTTON_RC_MENU
246 #define ROCKBLOX_LEFT BUTTON_RC_REW
247 #define ROCKBLOX_RIGHT BUTTON_RC_FF
248 #define ROCKBLOX_DROP BUTTON_RC_PLAY
249 #define ROCKBLOX_RESTART BUTTON_RC_MODE
251 #elif CONFIG_KEYPAD == COWON_D2_PAD
252 #define ROCKBLOX_OFF BUTTON_POWER
253 #define ROCKBLOX_RESTART BUTTON_MENU
255 #elif CONFIG_KEYPAD == IAUDIO67_PAD
257 #define ROCKBLOX_OFF BUTTON_POWER
258 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOLDOWN
259 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOLUP
260 #define ROCKBLOX_DOWN BUTTON_STOP
261 #define ROCKBLOX_LEFT BUTTON_LEFT
262 #define ROCKBLOX_RIGHT BUTTON_RIGHT
263 #define ROCKBLOX_DROP BUTTON_PLAY
264 #define ROCKBLOX_RESTART BUTTON_MENU
266 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
267 #define ROCKBLOX_OFF BUTTON_BACK
268 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
269 #define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
270 #define ROCKBLOX_DOWN BUTTON_DOWN
271 #define ROCKBLOX_LEFT BUTTON_LEFT
272 #define ROCKBLOX_RIGHT BUTTON_RIGHT
273 #define ROCKBLOX_DROP BUTTON_SELECT
274 #define ROCKBLOX_RESTART BUTTON_CUSTOM
276 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
278 #define ROCKBLOX_OFF BUTTON_POWER
279 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
280 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
281 #define ROCKBLOX_ROTATE BUTTON_UP
282 #define ROCKBLOX_DOWN BUTTON_DOWN
283 #define ROCKBLOX_LEFT BUTTON_LEFT
284 #define ROCKBLOX_RIGHT BUTTON_RIGHT
285 #define ROCKBLOX_DROP BUTTON_SELECT
286 #define ROCKBLOX_RESTART BUTTON_MENU
288 # elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
290 #define ROCKBLOX_OFF BUTTON_POWER
291 #define ROCKBLOX_ROTATE_RIGHT BUTTON_VOL_DOWN
292 #define ROCKBLOX_ROTATE_LEFT BUTTON_VOL_UP
293 #define ROCKBLOX_ROTATE BUTTON_UP
294 #define ROCKBLOX_DOWN BUTTON_DOWN
295 #define ROCKBLOX_LEFT BUTTON_PREV
296 #define ROCKBLOX_RIGHT BUTTON_NEXT
297 #define ROCKBLOX_DROP BUTTON_PLAY
298 #define ROCKBLOX_RESTART BUTTON_MENU
300 #elif CONFIG_KEYPAD == ONDAVX747_PAD
301 #define ROCKBLOX_OFF BUTTON_POWER
302 #define ROCKBLOX_RESTART BUTTON_MENU
303 #elif CONFIG_KEYPAD == ONDAVX777_PAD
304 #define ROCKBLOX_OFF BUTTON_POWER
306 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
308 #define ROCKBLOX_OFF (BUTTON_REC|BUTTON_PLAY)
309 #define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
310 #define ROCKBLOX_ROTATE_LEFT BUTTON_DOWN
311 #define ROCKBLOX_DOWN BUTTON_REW
312 #define ROCKBLOX_LEFT BUTTON_LEFT
313 #define ROCKBLOX_RIGHT BUTTON_RIGHT
314 #define ROCKBLOX_DROP BUTTON_FFWD
315 #define ROCKBLOX_RESTART (BUTTON_REC|BUTTON_REW)
317 #else
318 #error No keymap defined!
319 #endif
321 #ifdef HAVE_TOUCHSCREEN
322 #ifndef ROCKBLOX_OFF
323 #define ROCKBLOX_OFF BUTTON_TOPLEFT
324 #endif
325 #ifndef ROCKBLOX_ROTATE_RIGHT
326 #define ROCKBLOX_ROTATE_RIGHT BUTTON_BOTTOMRIGHT
327 #endif
328 #ifndef ROCKBLOX_ROTATE_LEFT
329 #define ROCKBLOX_ROTATE_LEFT BUTTON_BOTTOMLEFT
330 #endif
331 #ifndef ROCKBLOX_DOWN
332 #define ROCKBLOX_DOWN BUTTON_BOTTOMMIDDLE
333 #endif
334 #ifndef ROCKBLOX_LEFT
335 #define ROCKBLOX_LEFT BUTTON_MIDLEFT
336 #endif
337 #ifndef ROCKBLOX_RIGHT
338 #define ROCKBLOX_RIGHT BUTTON_MIDRIGHT
339 #endif
340 #ifndef ROCKBLOX_DROP
341 #define ROCKBLOX_DROP BUTTON_CENTER
342 #endif
343 #ifndef ROCKBLOX_RESTART
344 #define ROCKBLOX_RESTART BUTTON_TOPRIGHT
345 #endif
346 #endif
348 #define BLOCKS_NUM 7
349 #define EMPTY_BLOCK 7
351 #define BOARD_WIDTH 10
353 #ifdef HAVE_LCD_BITMAP
355 #define BOARD_HEIGHT 20
357 #if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
359 #define BLOCK_WIDTH 24
360 #define BLOCK_HEIGHT 24
361 #define BOARD_X 172
362 #define BOARD_Y 0
363 #define PREVIEW_X 24
364 #define PREVIEW_Y 22
365 #define LABEL_X 482
366 #define SCORE_Y 50
367 #define LEVEL_Y 140
368 #define LINES_Y 210
370 #elif (LCD_WIDTH == 480) && (LCD_HEIGHT == 640)
372 #define BLOCK_WIDTH 30
373 #define BLOCK_HEIGHT 30
374 #define BOARD_X 14
375 #define BOARD_Y 2
376 #define PREVIEW_X 342
377 #define PREVIEW_Y 482
378 #define LABEL_X 344
379 #define SCORE_Y 58
380 #define LEVEL_Y 142
381 #define LINES_Y 218
383 #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
385 #define BLOCK_WIDTH 12
386 #define BLOCK_HEIGHT 12
387 #define BOARD_X 86
388 #define BOARD_Y 0
389 #define PREVIEW_X 12
390 #define PREVIEW_Y 11
391 #define LABEL_X 242
392 #define SCORE_Y 25
393 #define LEVEL_Y 70
394 #define LINES_Y 105
396 #elif (LCD_WIDTH == 240) && ((LCD_HEIGHT == 320) || (LCD_HEIGHT == 400))
398 #define BLOCK_WIDTH 15
399 #define BLOCK_HEIGHT 15
400 #define BOARD_X 7
401 #define BOARD_Y 1
402 #define PREVIEW_X 171
403 #define PREVIEW_Y 241
404 #define LABEL_X 172
405 #define SCORE_Y 29
406 #define LEVEL_Y 71
407 #define LINES_Y 109
408 #define HIGH_LABEL_X 172
409 #define HIGH_SCORE_Y 163
410 #define HIGH_LEVEL_Y 172
412 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
414 #define BLOCK_WIDTH 8
415 #define BLOCK_HEIGHT 8
416 #define BOARD_X 27
417 #define BOARD_Y 5
418 #define PREVIEW_X 158
419 #define PREVIEW_Y 130
420 #define LABEL_X 147
421 #define SCORE_Y 20
422 #define LEVEL_Y 65
423 #define LINES_Y 100
425 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
427 #define BLOCK_WIDTH 6
428 #define BLOCK_HEIGHT 6
429 #define BOARD_X 25
430 #define BOARD_Y 1
431 #define PREVIEW_X 126
432 #define PREVIEW_Y 102
433 #define LABEL_X 112
434 #define SCORE_Y 17
435 #define LEVEL_Y 49
436 #define LINES_Y 81
438 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
440 /* no room for the space in the highscore list */
441 #define _SPACE ""
443 #define BLOCK_WIDTH 10
444 #define BLOCK_HEIGHT 10
445 #define BOARD_X 6
446 #define BOARD_Y 10
447 #define PREVIEW_X 124
448 #define PREVIEW_Y 174
449 #define LABEL_X 117
450 #define SCORE_Y 18
451 #define LEVEL_Y 52
452 #define LINES_Y 85
453 #define HIGH_SCORE_Y 119
454 #define HIGH_LEVEL_Y 126
455 #define HIGH_LABEL_X 114
457 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
460 #define BLOCK_WIDTH 6
461 #define BLOCK_HEIGHT 6
462 #define BOARD_X 22
463 #define BOARD_Y 3
464 #define PREVIEW_X 114
465 #define PREVIEW_Y 100
466 #define LABEL_X 101
467 #define SCORE_Y 17
468 #define LEVEL_Y 49
469 #define LINES_Y 82
471 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
473 #define BLOCK_WIDTH 5
474 #define BLOCK_HEIGHT 5
475 #define BOARD_X 14
476 #define BOARD_Y 0
477 #define PREVIEW_X 98
478 #define PREVIEW_Y 88
479 #define LABEL_X 80
480 #define SCORE_Y 15
481 #define LEVEL_Y 45
482 #define LINES_Y 74
484 #elif (LCD_WIDTH == 132) && (LCD_HEIGHT == 80)
486 #define BLOCK_WIDTH 4
487 #define BLOCK_HEIGHT 4
488 #define BOARD_X 10
489 #define BOARD_Y 0
490 #define PREVIEW_X 89
491 #define PREVIEW_Y 61
492 #define LABEL_X 78
493 #define SCORE_Y 10
494 #define LEVEL_Y 30
495 #define LINES_Y 50
497 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
499 #define BLOCK_WIDTH 6
500 #define BLOCK_HEIGHT 6
501 #define BOARD_X 4
502 #define BOARD_Y 3
503 #define PREVIEW_X 84
504 #define PREVIEW_Y 100
505 #define LABEL_X 71
506 #define SCORE_Y 17
507 #define LEVEL_Y 49
508 #define LINES_Y 82
510 /* NOTE: This is for the GoGear SA9200 and is only
511 temporary until I can get better coordinates! */
512 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 160)
514 #define BLOCK_WIDTH 6
515 #define BLOCK_HEIGHT 6
516 #define BOARD_X 4
517 #define BOARD_Y 3
518 #define PREVIEW_X 84
519 #define PREVIEW_Y 100
520 #define LABEL_X 71
521 #define SCORE_Y 17
522 #define LEVEL_Y 49
523 #define LINES_Y 82
525 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 96)
527 #define BLOCK_WIDTH 4
528 #define BLOCK_HEIGHT 4
529 #define BOARD_X 14
530 #define BOARD_Y 2
531 #define PREVIEW_X 89
532 #define PREVIEW_Y 76
533 #define LABEL_X 70
534 #define SCORE_Y 14
535 #define LEVEL_Y 39
536 #define LINES_Y 64
538 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 64)
540 #define BLOCK_WIDTH 3
541 #define BLOCK_HEIGHT 3
542 #define BOARD_X 9
543 #define BOARD_Y 3
544 #define PREVIEW_X 53
545 #define PREVIEW_Y 5
546 #define LABEL_X 70
547 #define SCORE_Y 32
548 #define LEVEL_Y 13
549 #define LINES_Y 51
551 #elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
553 #define BLOCK_WIDTH 4
554 #define BLOCK_HEIGHT 3
555 #define BOARD_X 9
556 #define BOARD_Y 3
557 #define PREVIEW_X 59
558 #define PREVIEW_Y 5
559 #define LABEL_X 59
560 #define SCORE_Y 32
561 #define LEVEL_Y 13
562 #define LEVEL_X 78
563 #define LINES_Y 51
565 #endif
567 #ifndef LEVEL_X
568 #define LEVEL_X LABEL_X
569 #endif
571 #ifndef LINES_X
572 #define LINES_X LABEL_X
573 #endif
575 #define MYLCD(fn) rb->lcd_ ## fn
577 extern const fb_data rockblox_background[];
579 #else /* HAVE_LCD_CHARCELLS */
581 #define BOARD_HEIGHT 14
583 #define BLOCK_WIDTH 1
584 #define BLOCK_HEIGHT 1
585 #define BOARD_X 5
586 #define BOARD_Y 0
587 #define PREVIEW_X 15
588 #define PREVIEW_Y 1
590 #define MYLCD(fn) pgfx_ ## fn
592 #endif
594 #ifndef _SPACE
595 #define _SPACE " "
596 #endif
597 /* <<Explanation on Rockblox shapes>>
600 %% - O has 1 orientation
602 %% %
603 %% %% - Z has 2 orientations
606 %% %
607 %% %% - S has 2 orientations
611 % %%%% - I has 2 orientations
614 % %%
615 % % % %%% - L has 4 orientations
616 %% %%% % %
618 % %%
619 % % % %%% - J has 4 orientations
620 %% %%% % %
622 % % %%%
623 %% % %% % - T has 4 orientations
624 % %%% %
627 /* c=current f=figure o=orientation n=next */
628 static struct _rockblox_status
630 int gameover;
631 int lines;
632 int level;
633 int score;
634 int cx;
635 int cy;
636 int cf;
637 int co;
638 int nf;
639 short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */
640 } rockblox_status;
642 /* prototypes */
643 static void draw_next_block(void);
644 static void new_block(void);
646 #ifdef HAVE_SCROLLWHEEL
647 int wheel_events = 0, last_wheel_event = 0;
648 bool wheel_enabled = false;
649 #endif
651 static const short scoring[4] = { /* scoring for each number of lines */
652 #if BOARD_HEIGHT == 20
653 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
654 #elif BOARD_HEIGHT == 14 /* Player special values */
655 60 /* single */ , 150 /* double */ , 500 /* triple */ , 2000 /* rockblox */
656 #endif
659 struct figure
661 #if LCD_DEPTH >= 2
662 unsigned short color[3]; /* color of figure (light,middle,shadow) */
663 #endif
664 unsigned short max_or; /* max orientations */
665 signed short shapeX[4], shapeY[4]; /* implementation of figures */
668 /* array of figures */
669 figures[BLOCKS_NUM] = {
670 /* O */
672 #if LCD_DEPTH >= 16
673 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
674 LCD_RGBPACK(0,153,153)},
675 #elif LCD_DEPTH == 2
676 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
677 #endif
679 {-1, 0, -1, 0},
680 {0, 0, 1, 1}
682 /* I */
684 #if LCD_DEPTH >= 16
685 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
686 LCD_RGBPACK (153, 0, 0)},
687 #elif LCD_DEPTH == 2
688 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
689 #endif
691 {-2, -1, 0, 1},
692 {0, 0, 0, 0}
694 /* 'Z' */
696 #if LCD_DEPTH >= 16
697 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
698 LCD_RGBPACK (0, 153, 0)},
699 #elif LCD_DEPTH == 2
700 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
701 #endif
703 {0, 1, -1, 0},
704 {0, 0, 1, 1}
706 /* 'S' */
708 #if LCD_DEPTH >= 16
709 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
710 LCD_RGBPACK (0, 0, 153)},
711 #elif LCD_DEPTH == 2
712 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
713 #endif
715 {-1, 0, 0, 1},
716 {0, 0, 1, 1}
718 /* 'L' */
720 #if LCD_DEPTH >= 16
721 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
722 LCD_RGBPACK (153, 153, 0)},
723 #elif LCD_DEPTH == 2
724 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
725 #endif
727 {-1, 0, 1, 1},
728 {0, 0, 0, 1}
730 /* 'J' */
732 #if LCD_DEPTH >= 16
733 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
734 LCD_RGBPACK (153, 0, 153)},
735 #elif LCD_DEPTH == 2
736 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
737 #endif
739 {-1, 0, 1, -1},
740 {0, 0, 0, 1}
742 /* 'T' */
744 #if LCD_DEPTH >= 16
745 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
746 LCD_RGBPACK (85, 85, 85)},
747 #elif LCD_DEPTH == 2
748 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
749 #endif
751 {-1, 0, 1, 0},
752 {0, 0, 0, 1}
755 bool resume = false;
756 bool resume_file = false;
758 /* Rockbox File System only supports full filenames inc dir */
759 #define HIGH_SCORE PLUGIN_GAMES_DIR "/rockblox.score"
760 #define RESUME_FILE PLUGIN_GAMES_DIR "/rockblox.resume"
761 #define MAX_HIGH_SCORES 5
763 /* Default High Scores... */
764 struct highscore highest[MAX_HIGH_SCORES];
766 /* get random number from (0) to (range-1) */
767 static int t_rand (int range)
769 return rb->rand () % range;
772 static inline void show_game_over (void)
774 rb->splash(HZ,"Game over!");
777 /* init the board array to have no blocks */
778 static void init_board (void)
780 int i, j;
781 for (i = 0; i < BOARD_WIDTH; i++)
782 for (j = 0; j < BOARD_HEIGHT; j++)
783 rockblox_status.board[j][i] = EMPTY_BLOCK;
786 /* show the score, level and lines */
787 static void show_details (void)
789 char str[25]; /* for strings */
791 #ifdef HAVE_LCD_BITMAP
792 #if LCD_DEPTH >= 2
793 rb->lcd_set_foreground (LCD_BLACK);
794 rb->lcd_set_background (LCD_WHITE);
795 #endif
796 rb->snprintf (str, sizeof (str), "%d", rockblox_status.score);
797 rb->lcd_putsxy (LABEL_X, SCORE_Y, str);
798 rb->snprintf (str, sizeof (str), "%d", rockblox_status.level);
799 rb->lcd_putsxy (LEVEL_X, LEVEL_Y, str);
800 rb->snprintf (str, sizeof (str), "%d", rockblox_status.lines);
801 rb->lcd_putsxy (LINES_X, LINES_Y, str);
802 #else /* HAVE_LCD_CHARCELLS */
803 rb->snprintf (str, sizeof (str), "L%d/%d", rockblox_status.level,
804 rockblox_status.lines);
805 rb->lcd_puts (5, 0, str);
806 rb->snprintf (str, sizeof (str), "S%d", rockblox_status.score);
807 rb->lcd_puts (5, 1, str);
808 #endif
811 #ifdef HIGH_SCORE_Y
812 static void show_highscores (void)
814 int i;
815 char str[25]; /* for strings */
817 for (i = 0; i<MAX_HIGH_SCORES; i++)
819 rb->snprintf (str, sizeof (str), "%06d" _SPACE "L%1d",
820 highest[i].score, highest[i].level);
821 rb->lcd_putsxy (HIGH_LABEL_X, HIGH_SCORE_Y + (10 * i), str);
824 #endif
826 static void load_game(void)
828 int fd;
830 resume = false;
832 fd = rb->open(RESUME_FILE, O_RDONLY);
833 if (fd < 0) return;
835 if (rb->read(fd, &rockblox_status, sizeof(struct _rockblox_status))
836 < (ssize_t)sizeof(struct _rockblox_status))
838 rb->splash(HZ/2, "Loading Rockblox resume info failed");
839 return;
840 } else {
841 resume = true;
844 rb->close(fd);
846 return;
849 static void dump_resume(void)
851 int fd;
853 fd = rb->open(RESUME_FILE, O_WRONLY|O_CREAT);
854 if (fd < 0)
855 goto fail;
857 if (rb->write(fd, &rockblox_status, sizeof(struct _rockblox_status))
858 <= 0)
860 rb->close(fd);
861 goto fail;
863 rb->close(fd);
864 return;
866 fail:
867 rb->splash(HZ/2, "Writing Rockblox resume info failed");
868 return;
871 static void init_rockblox (bool resume)
873 char score_name[50];
874 struct tm* tm;
876 tm = rb->get_time();
877 rb->snprintf(score_name, sizeof(score_name), "%04d%02d%02d %02d%02d%02d",
878 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
879 tm->tm_hour, tm->tm_min, tm->tm_sec);
881 #ifdef HAVE_LCD_BITMAP
882 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
883 #else /* HAVE_LCD_CHARCELLS */
884 pgfx_display (0, 0);
885 pgfx_display_block (3, 0, 3, 1);
886 pgfx_display_block (4, 0, 3, 0);
887 pgfx_clear_display();
888 pgfx_fillrect (3, 0, 2, 14);
889 pgfx_fillrect (15, 7, 2, 7);
890 pgfx_update();
891 #endif
892 if (!resume)
894 rockblox_status.level = 1;
895 rockblox_status.lines = 0;
896 rockblox_status.score = 0;
897 rockblox_status.nf = t_rand(BLOCKS_NUM);
898 init_board ();
899 new_block ();
901 draw_next_block();
903 show_details ();
904 #ifdef HIGH_SCORE_Y
905 show_highscores ();
906 #endif
909 static inline int level_speed(int level)
911 #if BOARD_HEIGHT == 20
912 return (5*HZ) / (level + 9);
913 #elif BOARD_HEIGHT == 14
914 return (7*HZ) / (level + 9);
915 #endif
918 static int getRelativeX (int figure, int square, int orientation)
920 switch (orientation) {
921 case 0:
922 return figures[figure].shapeX[square];
923 case 1:
924 return figures[figure].shapeY[square];
925 case 2:
926 return -figures[figure].shapeX[square];
927 case 3:
928 return -figures[figure].shapeY[square];
929 default:
930 return 0;
934 static int getRelativeY (int figure, int square, int orientation)
936 switch (orientation) {
937 case 0:
938 return figures[figure].shapeY[square];
939 case 1:
940 return -figures[figure].shapeX[square];
941 case 2:
942 return -figures[figure].shapeY[square];
943 case 3:
944 return figures[figure].shapeX[square];
945 default:
946 return 0;
950 /* redraw the while board on the screen */
951 static void refresh_board (void)
953 int i, j, x, y, block;
955 #if LCD_DEPTH >= 2
956 rb->lcd_set_foreground (LCD_BLACK);
957 #elif LCD_DEPTH == 1
958 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
959 #endif
961 MYLCD(fillrect) (BOARD_X, BOARD_Y, BOARD_WIDTH * BLOCK_WIDTH,
962 BOARD_HEIGHT * BLOCK_HEIGHT);
964 #if LCD_DEPTH == 1
965 MYLCD(set_drawmode) (DRMODE_SOLID);
966 #endif
968 for (i = 0; i < BOARD_WIDTH; i++)
969 for (j = 0; j < BOARD_HEIGHT; j++) {
970 block = rockblox_status.board[j][i];
971 if (block != EMPTY_BLOCK) {
972 #ifdef HAVE_LCD_BITMAP
973 #if LCD_DEPTH >= 2
974 /* middle drawing */
975 rb->lcd_set_foreground (figures[block].color[1]);
976 #endif
977 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
978 BOARD_Y + j * BLOCK_HEIGHT,
979 BLOCK_WIDTH, BLOCK_HEIGHT);
980 #if LCD_DEPTH >= 2
981 /* light drawing */
982 rb->lcd_set_foreground (figures[block].color[0]);
983 #endif
984 rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH,
985 BOARD_Y + j * BLOCK_HEIGHT,
986 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2);
987 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH,
988 BOARD_X + (i + 1) * BLOCK_WIDTH - 2,
989 BOARD_Y + j * BLOCK_HEIGHT);
990 #if LCD_DEPTH >= 2
991 /* shadow drawing */
992 rb->lcd_set_foreground (figures[block].color[2]);
993 #endif
994 rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
995 BOARD_Y + j * BLOCK_HEIGHT + 1,
996 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
997 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1,
998 BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
999 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
1000 #else /* HAVE_LCD_CHARCELLS */
1001 pgfx_drawpixel (BOARD_X + i, BOARD_Y + j);
1002 #endif
1006 for (i = 0; i < 4; i++) {
1007 x = getRelativeX (rockblox_status.cf, i, rockblox_status.co)
1008 + rockblox_status.cx;
1009 y = getRelativeY (rockblox_status.cf, i, rockblox_status.co)
1010 + rockblox_status.cy;
1011 #ifdef HAVE_LCD_BITMAP
1012 #if LCD_DEPTH >= 2
1013 /* middle drawing */
1014 rb->lcd_set_foreground (figures[rockblox_status.cf].color[1]);
1015 #endif
1016 rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH,
1017 BOARD_Y + y * BLOCK_HEIGHT,
1018 BLOCK_WIDTH, BLOCK_HEIGHT);
1019 #if LCD_DEPTH >= 2
1020 /* light drawing */
1021 rb->lcd_set_foreground (figures[rockblox_status.cf].color[0]);
1022 #endif
1023 rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT,
1024 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2);
1025 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH,
1026 BOARD_X + (x + 1) * BLOCK_WIDTH - 2,
1027 BOARD_Y + y * BLOCK_HEIGHT);
1028 #if LCD_DEPTH >= 2
1029 /* shadow drawing */
1030 rb->lcd_set_foreground (figures[rockblox_status.cf].color[2]);
1031 #endif
1032 rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
1033 BOARD_Y + y * BLOCK_HEIGHT + 1,
1034 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
1035 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1,
1036 BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
1037 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
1038 #else /* HAVE_LCD_CHARCELLS */
1039 pgfx_drawpixel (BOARD_X + x, BOARD_Y + y);
1040 #endif
1042 MYLCD(update) ();
1045 static bool canMoveTo (int x, int y, int newOrientation)
1047 int i, rx, ry;
1048 for (i = 0; i < 4; i++) {
1049 ry = getRelativeY (rockblox_status.cf, i, newOrientation) + y;
1050 rx = getRelativeX (rockblox_status.cf, i, newOrientation) + x;
1051 if ((rx < 0 || rx >= BOARD_WIDTH) ||
1052 (ry < 0 || ry >= BOARD_HEIGHT) ||
1053 (rockblox_status.board[ry][rx] != EMPTY_BLOCK))
1054 return false;
1056 return true;
1059 /* draws the preview of next block in the preview window */
1060 static void draw_next_block (void)
1062 int i, rx, ry;
1063 /* clear preview window first */
1064 #if LCD_DEPTH >= 2
1065 rb->lcd_set_foreground (LCD_BLACK);
1066 #elif LCD_DEPTH == 1
1067 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
1068 #endif
1070 /* 4x4 */
1071 MYLCD(fillrect) (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4);
1073 #if LCD_DEPTH == 1
1074 MYLCD(set_drawmode) (DRMODE_SOLID);
1075 #endif
1077 /* draw the lightgray rectangles */
1078 #if LCD_DEPTH >= 16
1079 rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
1080 #elif LCD_DEPTH == 2
1081 rb->lcd_set_foreground (LCD_DARKGRAY);
1082 #endif
1084 #if LCD_DEPTH >= 2
1085 for (rx = 0; rx < 4; rx++)
1086 for (ry = 0; ry < 4; ry++)
1087 rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH,
1088 PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH,
1089 BLOCK_HEIGHT);
1090 #endif
1092 /* draw the figure */
1093 for (i = 0; i < 4; i++) {
1094 rx = getRelativeX (rockblox_status.nf, i, 0) + 2;
1095 ry = getRelativeY (rockblox_status.nf, i, 0) + 2;
1096 #ifdef HAVE_LCD_BITMAP
1097 #if LCD_DEPTH >= 2
1098 rb->lcd_set_foreground (figures[rockblox_status.nf].color[1]); /* middle drawing */
1099 #endif
1100 rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH,
1101 PREVIEW_Y + ry * BLOCK_HEIGHT,
1102 BLOCK_WIDTH, BLOCK_HEIGHT);
1103 #if LCD_DEPTH >= 2
1104 rb->lcd_set_foreground (figures[rockblox_status.nf].color[0]); /* light drawing */
1105 #endif
1106 rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH,
1107 PREVIEW_Y + ry * BLOCK_HEIGHT,
1108 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2);
1109 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH,
1110 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2,
1111 PREVIEW_Y + ry * BLOCK_HEIGHT);
1112 #if LCD_DEPTH >= 2
1113 rb->lcd_set_foreground (figures[rockblox_status.nf].color[2]); /* shadow drawing */
1114 #endif
1115 rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
1116 PREVIEW_Y + ry * BLOCK_HEIGHT + 1,
1117 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
1118 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1,
1119 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
1120 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
1121 #else /* HAVE_LCD_CHARCELLS */
1122 pgfx_drawpixel (PREVIEW_X + rx, PREVIEW_Y + ry);
1123 #endif
1128 /* move the block to a relative location */
1129 static void move_block (int x, int y, int o)
1131 if (canMoveTo (rockblox_status.cx + x, rockblox_status.cy + y, o)) {
1132 rockblox_status.cy += y;
1133 rockblox_status.cx += x;
1134 rockblox_status.co = o;
1138 /* try to add a new block to play with (return true if gameover) */
1139 static void new_block (void)
1141 rockblox_status.cy = 1;
1142 rockblox_status.cx = 5;
1143 rockblox_status.cf = rockblox_status.nf;
1144 rockblox_status.co = 0; /* start at the same orientation all time */
1145 rockblox_status.nf = t_rand (BLOCKS_NUM);
1146 rockblox_status.gameover = !canMoveTo (rockblox_status.cx,
1147 rockblox_status.cy, rockblox_status.co);
1149 draw_next_block ();
1153 /* check for filled rockblox_status.lines and do what necessary */
1154 static int check_lines (void)
1157 int i, j, y;
1158 int rockblox = 0;
1160 for (j = 0; j < BOARD_HEIGHT; j++) {
1161 for (i = 0; ((i < BOARD_WIDTH) &&
1162 (rockblox_status.board[j][i] != EMPTY_BLOCK)); i++);
1163 if (i == BOARD_WIDTH) { /* woo hoo, we have a line */
1164 rockblox++;
1165 for (y = j; y > 0; y--)
1167 for (i = 0; i < BOARD_WIDTH; i++)
1168 { /* fall line */
1169 rockblox_status.board[y][i] = rockblox_status.board[y - 1][i];
1175 return rockblox;
1178 /* moves down the figure and returns true if gameover */
1179 static void move_down (void)
1181 int l, i, rx, ry;
1183 if (!canMoveTo (rockblox_status.cx, rockblox_status.cy + 1, rockblox_status.co)) {
1184 /* save figure to board */
1185 for (i = 0; i < 4; i++) {
1186 rx = getRelativeX (rockblox_status.cf, i, rockblox_status.co) + rockblox_status.cx;
1187 ry = getRelativeY (rockblox_status.cf, i, rockblox_status.co) + rockblox_status.cy;
1188 rockblox_status.board[ry][rx] = rockblox_status.cf;
1190 /* check if formed some lines */
1191 l = check_lines ();
1192 if (l) {
1193 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
1194 rockblox_status.score += scoring[l - 1] * rockblox_status.level;
1195 rockblox_status.lines += l;
1196 rockblox_status.level = (int) rockblox_status.lines / 10 + 1;
1199 /* show details */
1200 show_details ();
1202 /* generate a new figure */
1203 new_block ();
1204 } else
1205 move_block (0, 1, rockblox_status.co);
1208 static bool rockblox_help(void)
1210 int button;
1212 #define WORDS (sizeof help_text / sizeof (char*))
1213 char *help_text[] = {
1214 "Rockblox", "", "Aim", "", "Make", "the", "falling", "blocks", "of", "different",
1215 "shapes", "form", "full", "rows.", "Whenever", "a", "row", "is", "completed,", "it",
1216 "will", "be", "cleared", "away", "and", "you", "gain", "points."
1219 static struct style_text formation[]={
1220 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1221 { 2, C_RED },
1222 { -1, 0 }
1224 #ifdef HAVE_LCD_BITMAP
1225 rb->lcd_setfont(FONT_UI);
1226 #endif
1227 #ifdef HAVE_LCD_COLOR
1228 rb->lcd_set_background(LCD_BLACK);
1229 rb->lcd_set_foreground(LCD_WHITE);
1230 #endif
1231 if (display_text(WORDS, help_text, formation, NULL))
1232 return true;
1233 do {
1234 button = rb->button_get(true);
1235 if ( rb->default_event_handler( button ) == SYS_USB_CONNECTED )
1236 return true;
1237 } while( ( button == BUTTON_NONE )
1238 || ( button & (BUTTON_REL|BUTTON_REPEAT) ) );
1239 #ifdef HAVE_LCD_BITMAP
1240 rb->lcd_setfont(FONT_SYSFIXED);
1241 #endif
1242 return false;
1245 static int rockblox_menu_cb(int action, const struct menu_item_ex *this_item)
1247 int i = ((intptr_t)this_item);
1248 if(action == ACTION_REQUEST_MENUITEM
1249 && !resume && (i==0 || i==5))
1250 return ACTION_EXIT_MENUITEM;
1251 return action;
1254 static int rockblox_menu(void)
1256 int selected = 0;
1258 MENUITEM_STRINGLIST(main_menu, "Rockblox Menu", rockblox_menu_cb,
1259 "Resume Game", "Start New Game",
1260 "Help", "High Scores", "Playback Control",
1261 "Quit without Saving", "Quit");
1263 rb->button_clear_queue();
1264 while (true) {
1265 switch (rb->do_menu(&main_menu, &selected, NULL, false)) {
1266 case 0:
1267 if(resume_file)
1268 rb->remove(RESUME_FILE);
1269 init_rockblox(true);
1270 return 0;
1271 case 1:
1272 init_rockblox(false);
1273 return 0;
1274 case 2:
1275 if (rockblox_help())
1276 return 1;
1277 break;
1278 case 3:
1279 #ifdef HAVE_LCD_BITMAP
1280 highscore_show(MAX_HIGH_SCORES, highest, MAX_HIGH_SCORES, true);
1281 #else
1282 rb->splashf(2*HZ, "High Score: %d", highest[0].score);
1283 #endif
1284 break;
1285 case 4:
1286 if (playback_control(NULL))
1287 return 1;
1288 break;
1289 case 5:
1290 return 1;
1291 case 6:
1292 if (resume) {
1293 rb->splash(HZ*1, "Saving game ...");
1294 dump_resume();
1296 return 1;
1297 case MENU_ATTACHED_USB:
1298 return 1;
1299 default:
1300 return 1;
1301 break;
1307 static int rockblox_loop (void)
1309 int button;
1310 int lastbutton = BUTTON_NONE;
1311 long next_down_tick = *rb->current_tick + level_speed(rockblox_status.level);
1313 if (rockblox_menu()) {
1314 return 1;
1316 resume = false;
1317 resume_file = false;
1319 while (1) {
1320 #ifdef HAS_BUTTON_HOLD
1321 if (rb->button_hold ()) {
1322 /* Turn on backlight timeout (revert to settings) */
1323 backlight_use_settings(); /* backlight control in lib/helper.c */
1324 rb->splash(0, "Paused");
1325 while (rb->button_hold ())
1326 rb->sleep(HZ/10);
1328 /* Turn off backlight timeout */
1329 backlight_force_on(); /* backlight control in lib/helper.c */
1331 /* get rid of the splash text */
1332 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
1333 show_details ();
1334 #ifdef HIGH_SCORE_Y
1335 show_highscores ();
1336 #endif
1337 draw_next_block ();
1338 refresh_board ();
1340 #endif
1342 button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1));
1343 switch (button) {
1344 #ifdef ROCKBLOX_RC_OFF
1345 case ROCKBLOX_RC_OFF:
1346 #endif
1347 case ROCKBLOX_OFF:
1348 #ifdef ROCKBLOX_OFF_PRE
1349 if (lastbutton != ROCKBLOX_OFF_PRE)
1350 break;
1351 #endif
1352 resume = true;
1353 return 0;
1354 break;
1356 #if defined(ROCKBLOX_ROTATE)
1357 case ROCKBLOX_ROTATE:
1358 #endif
1359 case ROCKBLOX_ROTATE_RIGHT:
1360 case ROCKBLOX_ROTATE_RIGHT | BUTTON_REPEAT:
1361 #ifdef HAVE_SCROLLWHEEL
1362 /* if the wheel is disabled, add an event to the stack. */
1363 if(wheel_enabled == false)
1364 wheel_events++;
1366 /* if it's enabled, go ahead and rotate.. */
1367 if(wheel_enabled)
1368 #endif
1369 move_block (0, 0, (rockblox_status.co + 1) % figures[rockblox_status.cf].max_or);
1370 break;
1372 case ROCKBLOX_ROTATE_LEFT:
1373 case ROCKBLOX_ROTATE_LEFT | BUTTON_REPEAT:
1374 #ifdef HAVE_SCROLLWHEEL
1375 if(wheel_enabled == false)
1376 wheel_events++;
1378 if(wheel_enabled)
1379 #endif
1380 move_block (0, 0,
1381 (rockblox_status.co + figures[rockblox_status.cf].max_or -
1382 1) % figures[rockblox_status.cf].max_or);
1383 break;
1385 #ifdef ROCKBLOX_ROTATE_RIGHT2
1386 case ROCKBLOX_ROTATE_RIGHT2:
1387 move_block (0, 0, (rockblox_status.co + 1) % figures[rockblox_status.cf].max_or);
1388 break;
1389 #endif
1391 case ROCKBLOX_DOWN:
1392 case ROCKBLOX_DOWN | BUTTON_REPEAT:
1393 move_block (0, 1, rockblox_status.co);
1394 break;
1396 case ROCKBLOX_RIGHT:
1397 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
1398 move_block (1, 0, rockblox_status.co);
1399 break;
1401 case ROCKBLOX_LEFT:
1402 case ROCKBLOX_LEFT | BUTTON_REPEAT:
1403 move_block (-1, 0, rockblox_status.co);
1404 break;
1406 case ROCKBLOX_DROP:
1407 #ifdef ROCKBLOX_DROP_PRE
1408 if (lastbutton != ROCKBLOX_DROP_PRE)
1409 break;
1410 #endif
1411 while (canMoveTo (rockblox_status.cx, rockblox_status.cy + 1, rockblox_status.co))
1412 move_block (0, 1, rockblox_status.co);
1413 break;
1414 #ifdef ROCKBLOX_RESTART
1415 case ROCKBLOX_RESTART:
1416 rb->splash (HZ * 1, "Restarting...");
1417 init_rockblox (false);
1418 break;
1419 #endif
1421 default:
1422 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
1423 return PLUGIN_USB_CONNECTED;
1424 break;
1426 if (button != BUTTON_NONE)
1427 lastbutton = button;
1429 #ifdef HAVE_SCROLLWHEEL
1430 /* check if we should enable the scroll wheel, if events
1431 * begin to stack up... */
1432 if(wheel_enabled == false)
1434 /* stopped rotating the wheel, reset the count */
1435 if(wheel_events == last_wheel_event)
1437 last_wheel_event = 0;
1438 wheel_events = 0;
1440 /* rotated the wheel a while constantly, enable it. */
1441 else if(wheel_events > 3)
1443 wheel_enabled = true;
1446 /* this evens out the last event and the "current" event.
1447 * if we get an event next time through button reading, it will
1448 * remain ahead of last_event. if we don't, they'll end up equaling
1449 * each other.. thus, the scroll count will be reset. */
1450 if(wheel_enabled == false && wheel_events > last_wheel_event)
1451 last_wheel_event++;
1453 #endif
1455 if (TIME_AFTER(*rb->current_tick, next_down_tick)) {
1456 move_down ();
1457 next_down_tick += level_speed(rockblox_status.level);
1458 if (TIME_AFTER(*rb->current_tick, next_down_tick))
1459 /* restart time "raster" when we had to wait longer than usual
1460 * (pause, game restart etc) */
1461 next_down_tick = *rb->current_tick + level_speed(rockblox_status.level);
1464 if (rockblox_status.gameover) {
1465 #if LCD_DEPTH >= 2
1466 rb->lcd_set_foreground (LCD_BLACK);
1467 #endif
1468 show_game_over();
1469 resume = false;
1470 return 0;
1473 refresh_board ();
1476 return 0;
1479 enum plugin_status plugin_start (const void *parameter)
1482 (void) parameter;
1484 rb->srand (*rb->current_tick);
1486 /* Load HighScore if any */
1487 highscore_load(HIGH_SCORE, highest, MAX_HIGH_SCORES);
1489 #if LCD_DEPTH > 1
1490 rb->lcd_set_backdrop(NULL);
1491 #endif
1493 #ifdef HAVE_LCD_BITMAP
1494 rb->lcd_setfont (FONT_SYSFIXED);
1495 #else
1496 if (!pgfx_init(4, 2))
1498 rb->splash(HZ*2, "Old LCD :(");
1499 return PLUGIN_OK;
1501 #endif
1502 /* Turn off backlight timeout */
1503 backlight_force_on(); /* backlight control in lib/helper.c */
1504 load_game();
1505 resume_file = resume;
1506 while(!rockblox_loop()) {
1507 if(!resume) {
1508 int position = highscore_update(rockblox_status.score, rockblox_status.level, "", highest,
1509 MAX_HIGH_SCORES);
1510 if (position == 0) {
1511 rb->splash(HZ*2, "New High Score");
1513 if (position != -1) {
1514 #ifdef HAVE_LCD_BITMAP
1515 highscore_show(position, highest, MAX_HIGH_SCORES, true);
1516 #else
1517 rb->splashf(2*HZ, "High Score: %d", highest[position].score);
1518 #endif
1523 #ifndef HAVE_LCD_BITMAP
1524 pgfx_release();
1525 #endif
1526 /* Save user's HighScore */
1527 highscore_save(HIGH_SCORE, highest, MAX_HIGH_SCORES);
1528 backlight_use_settings(); /* backlight control in lib/helper.c */
1530 return PLUGIN_OK;