Use a more natural guard for the callback definition
[kugel-rb.git] / apps / plugins / rockblox.c
blob871a3088839385611f5534a9a024f4c713e24cb4
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_CCW BUTTON_SCROLL_BACK
38 #define ROCKBLOX_ROTATE_CCW2 (BUTTON_MENU | BUTTON_REL)
39 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_UP
51 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_UP
64 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_UP
75 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_PLAY
87 #define ROCKBLOX_ROTATE_CW (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_CCW BUTTON_UP
100 #define ROCKBLOX_ROTATE_CW (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_CCW BUTTON_UP
112 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_SCROLL_BACK
123 #define ROCKBLOX_ROTATE_CCW2 BUTTON_UP
124 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_SCROLL_BACK
135 #define ROCKBLOX_ROTATE_CCW2 BUTTON_UP
136 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_UP
148 #define ROCKBLOX_ROTATE_CCW2 BUTTON_VOL_DOWN
149 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_UP
160 #define ROCKBLOX_ROTATE_CCW2 BUTTON_VOL_DOWN
161 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_UP
172 #define ROCKBLOX_ROTATE_CCW2 BUTTON_VOL_DOWN
173 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_SCROLL_UP
184 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_VOL_DOWN
195 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_UP
207 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_VOL_DOWN
220 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_MENU
232 #define ROCKBLOX_ROTATE_CW 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_CCW BUTTON_RC_VOL_DOWN
244 #define ROCKBLOX_ROTATE_CW 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
253 #define ROCKBLOX_OFF BUTTON_POWER
254 #define ROCKBLOX_RESTART BUTTON_MENU
256 #elif CONFIG_KEYPAD == IAUDIO67_PAD
258 #define ROCKBLOX_OFF BUTTON_POWER
259 #define ROCKBLOX_ROTATE_CCW BUTTON_VOLDOWN
260 #define ROCKBLOX_ROTATE_CW BUTTON_VOLUP
261 #define ROCKBLOX_DOWN BUTTON_STOP
262 #define ROCKBLOX_LEFT BUTTON_LEFT
263 #define ROCKBLOX_RIGHT BUTTON_RIGHT
264 #define ROCKBLOX_DROP BUTTON_PLAY
265 #define ROCKBLOX_RESTART BUTTON_MENU
267 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
268 #define ROCKBLOX_OFF BUTTON_BACK
269 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
270 #define ROCKBLOX_ROTATE_CW BUTTON_PLAY
271 #define ROCKBLOX_DOWN BUTTON_DOWN
272 #define ROCKBLOX_LEFT BUTTON_LEFT
273 #define ROCKBLOX_RIGHT BUTTON_RIGHT
274 #define ROCKBLOX_DROP BUTTON_SELECT
275 #define ROCKBLOX_RESTART BUTTON_CUSTOM
277 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
279 #define ROCKBLOX_OFF BUTTON_POWER
280 #define ROCKBLOX_ROTATE_CCW BUTTON_VOL_DOWN
281 #define ROCKBLOX_ROTATE_CW BUTTON_VOL_UP
282 #define ROCKBLOX_ROTATE BUTTON_UP
283 #define ROCKBLOX_DOWN BUTTON_DOWN
284 #define ROCKBLOX_LEFT BUTTON_LEFT
285 #define ROCKBLOX_RIGHT BUTTON_RIGHT
286 #define ROCKBLOX_DROP BUTTON_SELECT
287 #define ROCKBLOX_RESTART BUTTON_MENU
289 # elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
291 #define ROCKBLOX_OFF BUTTON_POWER
292 #define ROCKBLOX_ROTATE_CCW BUTTON_VOL_DOWN
293 #define ROCKBLOX_ROTATE_CW BUTTON_VOL_UP
294 #define ROCKBLOX_ROTATE BUTTON_UP
295 #define ROCKBLOX_DOWN BUTTON_DOWN
296 #define ROCKBLOX_LEFT BUTTON_PREV
297 #define ROCKBLOX_RIGHT BUTTON_NEXT
298 #define ROCKBLOX_DROP BUTTON_PLAY
299 #define ROCKBLOX_RESTART BUTTON_MENU
301 #elif CONFIG_KEYPAD == ONDAVX747_PAD
302 #define ROCKBLOX_OFF BUTTON_POWER
303 #define ROCKBLOX_RESTART BUTTON_MENU
304 #elif CONFIG_KEYPAD == ONDAVX777_PAD
305 #define ROCKBLOX_OFF BUTTON_POWER
307 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
309 #define ROCKBLOX_OFF (BUTTON_REC|BUTTON_PLAY)
310 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
311 #define ROCKBLOX_ROTATE_CW BUTTON_DOWN
312 #define ROCKBLOX_DOWN BUTTON_REW
313 #define ROCKBLOX_LEFT BUTTON_LEFT
314 #define ROCKBLOX_RIGHT BUTTON_RIGHT
315 #define ROCKBLOX_DROP BUTTON_FFWD
316 #define ROCKBLOX_RESTART (BUTTON_REC|BUTTON_REW)
318 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
320 #define ROCKBLOX_OFF BUTTON_REC
321 #define ROCKBLOX_ROTATE_CCW BUTTON_PLAY
322 #define ROCKBLOX_ROTATE_CW BUTTON_MENU
323 #define ROCKBLOX_DOWN BUTTON_DOWN
324 #define ROCKBLOX_LEFT BUTTON_PREV
325 #define ROCKBLOX_RIGHT BUTTON_NEXT
326 #define ROCKBLOX_DROP BUTTON_OK
327 #define ROCKBLOX_RESTART BUTTON_CANCEL
329 #else
330 #error No keymap defined!
331 #endif
333 #ifdef HAVE_TOUCHSCREEN
334 #ifndef ROCKBLOX_OFF
335 #define ROCKBLOX_OFF BUTTON_TOPLEFT
336 #endif
337 #ifdef ROCKBLOX_ROTATE_CCW
338 #define ROCKBLOX_ROTATE_CCW2 BUTTON_BOTTOMLEFT
339 #else
340 #define ROCKBLOX_ROTATE_CCW BUTTON_BOTTOMLEFT
341 #endif
342 #ifdef ROCKBLOX_ROTATE_CW
343 #define ROCKBLOX_ROTATE_CW2 BUTTON_BOTTOMRIGHT
344 #else
345 #define ROCKBLOX_ROTATE_CW BUTTON_BOTTOMRIGHT
346 #define ROCKBLOX_ROTATE_CW2 BUTTON_TOPMIDDLE
347 #endif
348 #ifndef ROCKBLOX_DOWN
349 #define ROCKBLOX_DOWN BUTTON_BOTTOMMIDDLE
350 #endif
351 #ifndef ROCKBLOX_LEFT
352 #define ROCKBLOX_LEFT BUTTON_MIDLEFT
353 #endif
354 #ifndef ROCKBLOX_RIGHT
355 #define ROCKBLOX_RIGHT BUTTON_MIDRIGHT
356 #endif
357 #ifndef ROCKBLOX_DROP
358 #define ROCKBLOX_DROP BUTTON_CENTER
359 #endif
360 #ifndef ROCKBLOX_RESTART
361 #define ROCKBLOX_RESTART BUTTON_TOPRIGHT
362 #endif
363 #endif
365 #define BLOCKS_NUM 7
366 #define EMPTY_BLOCK 7
368 #define BOARD_WIDTH 10
370 #ifdef HAVE_LCD_BITMAP
372 #define BOARD_HEIGHT 20
374 #if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
376 #define BLOCK_WIDTH 24
377 #define BLOCK_HEIGHT 24
378 #define BOARD_X 172
379 #define BOARD_Y 0
380 #define PREVIEW_X 24
381 #define PREVIEW_Y 22
382 #define LABEL_X 482
383 #define SCORE_Y 50
384 #define LEVEL_Y 140
385 #define LINES_Y 210
387 #elif (LCD_WIDTH == 480) && (LCD_HEIGHT == 640)
389 #define BLOCK_WIDTH 30
390 #define BLOCK_HEIGHT 30
391 #define BOARD_X 14
392 #define BOARD_Y 2
393 #define PREVIEW_X 342
394 #define PREVIEW_Y 482
395 #define LABEL_X 344
396 #define SCORE_Y 58
397 #define LEVEL_Y 142
398 #define LINES_Y 218
400 #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
402 #define BLOCK_WIDTH 12
403 #define BLOCK_HEIGHT 12
404 #define BOARD_X 86
405 #define BOARD_Y 0
406 #define PREVIEW_X 12
407 #define PREVIEW_Y 11
408 #define LABEL_X 242
409 #define SCORE_Y 25
410 #define LEVEL_Y 70
411 #define LINES_Y 105
413 #elif (LCD_WIDTH == 240) && ((LCD_HEIGHT == 320) || (LCD_HEIGHT == 400))
415 #define BLOCK_WIDTH 15
416 #define BLOCK_HEIGHT 15
417 #define BOARD_X 7
418 #define BOARD_Y 1
419 #define PREVIEW_X 171
420 #define PREVIEW_Y 241
421 #define LABEL_X 172
422 #define SCORE_Y 29
423 #define LEVEL_Y 71
424 #define LINES_Y 109
425 #define HIGH_LABEL_X 172
426 #define HIGH_SCORE_Y 163
427 #define HIGH_LEVEL_Y 172
429 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
431 #define BLOCK_WIDTH 8
432 #define BLOCK_HEIGHT 8
433 #define BOARD_X 27
434 #define BOARD_Y 5
435 #define PREVIEW_X 158
436 #define PREVIEW_Y 130
437 #define LABEL_X 147
438 #define SCORE_Y 20
439 #define LEVEL_Y 65
440 #define LINES_Y 100
442 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
444 #define BLOCK_WIDTH 6
445 #define BLOCK_HEIGHT 6
446 #define BOARD_X 25
447 #define BOARD_Y 1
448 #define PREVIEW_X 126
449 #define PREVIEW_Y 102
450 #define LABEL_X 112
451 #define SCORE_Y 17
452 #define LEVEL_Y 49
453 #define LINES_Y 81
455 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
457 /* no room for the space in the highscore list */
458 #define _SPACE ""
460 #define BLOCK_WIDTH 10
461 #define BLOCK_HEIGHT 10
462 #define BOARD_X 6
463 #define BOARD_Y 10
464 #define PREVIEW_X 124
465 #define PREVIEW_Y 174
466 #define LABEL_X 117
467 #define SCORE_Y 18
468 #define LEVEL_Y 52
469 #define LINES_Y 85
470 #define HIGH_SCORE_Y 119
471 #define HIGH_LEVEL_Y 126
472 #define HIGH_LABEL_X 114
474 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
477 #define BLOCK_WIDTH 6
478 #define BLOCK_HEIGHT 6
479 #define BOARD_X 22
480 #define BOARD_Y 3
481 #define PREVIEW_X 114
482 #define PREVIEW_Y 100
483 #define LABEL_X 101
484 #define SCORE_Y 17
485 #define LEVEL_Y 49
486 #define LINES_Y 82
488 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
490 #define BLOCK_WIDTH 5
491 #define BLOCK_HEIGHT 5
492 #define BOARD_X 14
493 #define BOARD_Y 0
494 #define PREVIEW_X 98
495 #define PREVIEW_Y 88
496 #define LABEL_X 80
497 #define SCORE_Y 15
498 #define LEVEL_Y 45
499 #define LINES_Y 74
501 #elif (LCD_WIDTH == 132) && (LCD_HEIGHT == 80)
503 #define BLOCK_WIDTH 4
504 #define BLOCK_HEIGHT 4
505 #define BOARD_X 10
506 #define BOARD_Y 0
507 #define PREVIEW_X 89
508 #define PREVIEW_Y 61
509 #define LABEL_X 78
510 #define SCORE_Y 10
511 #define LEVEL_Y 30
512 #define LINES_Y 50
514 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
516 #define BLOCK_WIDTH 6
517 #define BLOCK_HEIGHT 6
518 #define BOARD_X 4
519 #define BOARD_Y 3
520 #define PREVIEW_X 84
521 #define PREVIEW_Y 100
522 #define LABEL_X 71
523 #define SCORE_Y 17
524 #define LEVEL_Y 49
525 #define LINES_Y 82
527 /* NOTE: This is for the GoGear SA9200 and is only
528 temporary until I can get better coordinates! */
529 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 160)
531 #define BLOCK_WIDTH 6
532 #define BLOCK_HEIGHT 6
533 #define BOARD_X 4
534 #define BOARD_Y 3
535 #define PREVIEW_X 84
536 #define PREVIEW_Y 100
537 #define LABEL_X 71
538 #define SCORE_Y 17
539 #define LEVEL_Y 49
540 #define LINES_Y 82
542 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 96)
544 #define BLOCK_WIDTH 4
545 #define BLOCK_HEIGHT 4
546 #define BOARD_X 14
547 #define BOARD_Y 2
548 #define PREVIEW_X 89
549 #define PREVIEW_Y 76
550 #define LABEL_X 70
551 #define SCORE_Y 14
552 #define LEVEL_Y 39
553 #define LINES_Y 64
555 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 64)
557 #define BLOCK_WIDTH 3
558 #define BLOCK_HEIGHT 3
559 #define BOARD_X 9
560 #define BOARD_Y 3
561 #define PREVIEW_X 53
562 #define PREVIEW_Y 5
563 #define LABEL_X 70
564 #define SCORE_Y 32
565 #define LEVEL_Y 13
566 #define LINES_Y 51
568 #elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
570 #define BLOCK_WIDTH 4
571 #define BLOCK_HEIGHT 3
572 #define BOARD_X 9
573 #define BOARD_Y 3
574 #define PREVIEW_X 59
575 #define PREVIEW_Y 5
576 #define LABEL_X 59
577 #define SCORE_Y 32
578 #define LEVEL_Y 13
579 #define LEVEL_X 78
580 #define LINES_Y 51
582 #endif
584 #ifndef LEVEL_X
585 #define LEVEL_X LABEL_X
586 #endif
588 #ifndef LINES_X
589 #define LINES_X LABEL_X
590 #endif
592 #define MYLCD(fn) rb->lcd_ ## fn
594 extern const fb_data rockblox_background[];
596 #else /* HAVE_LCD_CHARCELLS */
598 #define BOARD_HEIGHT 14
600 #define BLOCK_WIDTH 1
601 #define BLOCK_HEIGHT 1
602 #define BOARD_X 5
603 #define BOARD_Y 0
604 #define PREVIEW_X 15
605 #define PREVIEW_Y 1
607 #define MYLCD(fn) pgfx_ ## fn
609 #endif
611 #ifndef _SPACE
612 #define _SPACE " "
613 #endif
614 /* <<Explanation on Rockblox shapes>>
617 %% - O has 1 orientation
619 %% %
620 %% %% - Z has 2 orientations
623 %% %
624 %% %% - S has 2 orientations
628 % %%%% - I has 2 orientations
631 % %%
632 % % % %%% - L has 4 orientations
633 %% %%% % %
635 % %%
636 % % % %%% - J has 4 orientations
637 %% %%% % %
639 % % %%%
640 %% % %% % - T has 4 orientations
641 % %%% %
644 /* c=current f=figure o=orientation n=next */
645 static struct _rockblox_status
647 int gameover;
648 int lines;
649 int level;
650 int score;
651 int cx;
652 int cy;
653 int cf;
654 int co;
655 int nf;
656 short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */
657 } rockblox_status;
659 /* prototypes */
660 static void draw_next_block(void);
661 static void new_block(void);
663 #ifdef HAVE_SCROLLWHEEL
664 int wheel_events = 0, last_wheel_event = 0;
665 bool wheel_enabled = false;
666 #endif
668 static const short scoring[4] = { /* scoring for each number of lines */
669 #if BOARD_HEIGHT == 20
670 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
671 #elif BOARD_HEIGHT == 14 /* Player special values */
672 60 /* single */ , 150 /* double */ , 500 /* triple */ , 2000 /* rockblox */
673 #endif
676 struct figure
678 #if LCD_DEPTH >= 2
679 unsigned short color[3]; /* color of figure (light,middle,shadow) */
680 #endif
681 unsigned short max_or; /* max orientations */
682 signed short shapeX[4], shapeY[4]; /* implementation of figures */
685 /* array of figures */
686 figures[BLOCKS_NUM] = {
687 /* O */
689 #if LCD_DEPTH >= 16
690 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
691 LCD_RGBPACK(0,153,153)},
692 #elif LCD_DEPTH == 2
693 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
694 #endif
696 {-1, 0, -1, 0},
697 {0, 0, 1, 1}
699 /* I */
701 #if LCD_DEPTH >= 16
702 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
703 LCD_RGBPACK (153, 0, 0)},
704 #elif LCD_DEPTH == 2
705 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
706 #endif
708 {-2, -1, 0, 1},
709 {0, 0, 0, 0}
711 /* 'Z' */
713 #if LCD_DEPTH >= 16
714 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
715 LCD_RGBPACK (0, 153, 0)},
716 #elif LCD_DEPTH == 2
717 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
718 #endif
720 {0, 1, -1, 0},
721 {0, 0, 1, 1}
723 /* 'S' */
725 #if LCD_DEPTH >= 16
726 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
727 LCD_RGBPACK (0, 0, 153)},
728 #elif LCD_DEPTH == 2
729 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
730 #endif
732 {-1, 0, 0, 1},
733 {0, 0, 1, 1}
735 /* 'L' */
737 #if LCD_DEPTH >= 16
738 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
739 LCD_RGBPACK (153, 153, 0)},
740 #elif LCD_DEPTH == 2
741 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
742 #endif
744 {-1, 0, 1, 1},
745 {0, 0, 0, 1}
747 /* 'J' */
749 #if LCD_DEPTH >= 16
750 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
751 LCD_RGBPACK (153, 0, 153)},
752 #elif LCD_DEPTH == 2
753 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
754 #endif
756 {-1, 0, 1, -1},
757 {0, 0, 0, 1}
759 /* 'T' */
761 #if LCD_DEPTH >= 16
762 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
763 LCD_RGBPACK (85, 85, 85)},
764 #elif LCD_DEPTH == 2
765 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
766 #endif
768 {-1, 0, 1, 0},
769 {0, 0, 0, 1}
772 bool resume = false;
773 bool resume_file = false;
775 /* Rockbox File System only supports full filenames inc dir */
776 #define SCORE_FILE PLUGIN_GAMES_DIR "/rockblox.score"
777 #define RESUME_FILE PLUGIN_GAMES_DIR "/rockblox.resume"
778 #define NUM_SCORES 5
780 /* Default High Scores... */
781 struct highscore highscores[NUM_SCORES];
783 /* get random number from (0) to (range-1) */
784 static int t_rand (int range)
786 return rb->rand () % range;
789 static inline void show_game_over (void)
791 rb->splash(HZ,"Game over!");
794 /* init the board array to have no blocks */
795 static void init_board (void)
797 int i, j;
798 for (i = 0; i < BOARD_WIDTH; i++)
799 for (j = 0; j < BOARD_HEIGHT; j++)
800 rockblox_status.board[j][i] = EMPTY_BLOCK;
803 /* show the score, level and lines */
804 static void show_details (void)
806 char str[25]; /* for strings */
808 #ifdef HAVE_LCD_BITMAP
809 #if LCD_DEPTH >= 2
810 rb->lcd_set_foreground (LCD_BLACK);
811 rb->lcd_set_background (LCD_WHITE);
812 #endif
813 rb->snprintf (str, sizeof (str), "%d", rockblox_status.score);
814 rb->lcd_putsxy (LABEL_X, SCORE_Y, str);
815 rb->snprintf (str, sizeof (str), "%d", rockblox_status.level);
816 rb->lcd_putsxy (LEVEL_X, LEVEL_Y, str);
817 rb->snprintf (str, sizeof (str), "%d", rockblox_status.lines);
818 rb->lcd_putsxy (LINES_X, LINES_Y, str);
819 #else /* HAVE_LCD_CHARCELLS */
820 rb->snprintf (str, sizeof (str), "L%d/%d", rockblox_status.level,
821 rockblox_status.lines);
822 rb->lcd_puts (5, 0, str);
823 rb->snprintf (str, sizeof (str), "S%d", rockblox_status.score);
824 rb->lcd_puts (5, 1, str);
825 #endif
828 #ifdef HIGH_SCORE_Y
829 static void show_highscores (void)
831 int i;
832 char str[25]; /* for strings */
834 for (i = 0; i<NUM_SCORES; i++)
836 rb->snprintf (str, sizeof (str), "%06d" _SPACE "L%1d",
837 highscores[i].score, highscores[i].level);
838 rb->lcd_putsxy (HIGH_LABEL_X, HIGH_SCORE_Y + (10 * i), str);
841 #endif
843 static void load_game(void)
845 int fd;
847 resume = false;
849 fd = rb->open(RESUME_FILE, O_RDONLY);
850 if (fd < 0) return;
852 if (rb->read(fd, &rockblox_status, sizeof(struct _rockblox_status))
853 < (ssize_t)sizeof(struct _rockblox_status))
855 rb->splash(HZ/2, "Loading Rockblox resume info failed");
856 return;
857 } else {
858 resume = true;
861 rb->close(fd);
863 return;
866 static void dump_resume(void)
868 int fd;
870 fd = rb->open(RESUME_FILE, O_WRONLY|O_CREAT);
871 if (fd < 0)
872 goto fail;
874 if (rb->write(fd, &rockblox_status, sizeof(struct _rockblox_status))
875 <= 0)
877 rb->close(fd);
878 goto fail;
880 rb->close(fd);
881 return;
883 fail:
884 rb->splash(HZ/2, "Writing Rockblox resume info failed");
885 return;
888 static void init_rockblox (bool resume)
890 char score_name[50];
891 struct tm* tm;
893 tm = rb->get_time();
894 rb->snprintf(score_name, sizeof(score_name), "%04d%02d%02d %02d%02d%02d",
895 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
896 tm->tm_hour, tm->tm_min, tm->tm_sec);
898 #ifdef HAVE_LCD_BITMAP
899 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
900 #else /* HAVE_LCD_CHARCELLS */
901 pgfx_display (0, 0);
902 pgfx_display_block (3, 0, 3, 1);
903 pgfx_display_block (4, 0, 3, 0);
904 pgfx_clear_display();
905 pgfx_fillrect (3, 0, 2, 14);
906 pgfx_fillrect (15, 7, 2, 7);
907 pgfx_update();
908 #endif
909 if (!resume)
911 rockblox_status.level = 1;
912 rockblox_status.lines = 0;
913 rockblox_status.score = 0;
914 rockblox_status.nf = t_rand(BLOCKS_NUM);
915 init_board ();
916 new_block ();
918 draw_next_block();
920 show_details ();
921 #ifdef HIGH_SCORE_Y
922 show_highscores ();
923 #endif
926 static inline int level_speed(int level)
928 #if BOARD_HEIGHT == 20
929 return (5*HZ) / (level + 9);
930 #elif BOARD_HEIGHT == 14
931 return (7*HZ) / (level + 9);
932 #endif
935 static int getRelativeX (int figure, int square, int orientation)
937 switch (orientation) {
938 case 0:
939 return figures[figure].shapeX[square];
940 case 1:
941 return figures[figure].shapeY[square];
942 case 2:
943 return -figures[figure].shapeX[square];
944 case 3:
945 return -figures[figure].shapeY[square];
946 default:
947 return 0;
951 static int getRelativeY (int figure, int square, int orientation)
953 switch (orientation) {
954 case 0:
955 return figures[figure].shapeY[square];
956 case 1:
957 return -figures[figure].shapeX[square];
958 case 2:
959 return -figures[figure].shapeY[square];
960 case 3:
961 return figures[figure].shapeX[square];
962 default:
963 return 0;
967 /* redraw the while board on the screen */
968 static void refresh_board (void)
970 int i, j, x, y, block;
972 #if LCD_DEPTH >= 2
973 rb->lcd_set_foreground (LCD_BLACK);
974 #elif LCD_DEPTH == 1
975 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
976 #endif
978 MYLCD(fillrect) (BOARD_X, BOARD_Y, BOARD_WIDTH * BLOCK_WIDTH,
979 BOARD_HEIGHT * BLOCK_HEIGHT);
981 #if LCD_DEPTH == 1
982 MYLCD(set_drawmode) (DRMODE_SOLID);
983 #endif
985 for (i = 0; i < BOARD_WIDTH; i++)
986 for (j = 0; j < BOARD_HEIGHT; j++) {
987 block = rockblox_status.board[j][i];
988 if (block != EMPTY_BLOCK) {
989 #ifdef HAVE_LCD_BITMAP
990 #if LCD_DEPTH >= 2
991 /* middle drawing */
992 rb->lcd_set_foreground (figures[block].color[1]);
993 #endif
994 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
995 BOARD_Y + j * BLOCK_HEIGHT,
996 BLOCK_WIDTH, BLOCK_HEIGHT);
997 #if LCD_DEPTH >= 2
998 /* light drawing */
999 rb->lcd_set_foreground (figures[block].color[0]);
1000 #endif
1001 rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH,
1002 BOARD_Y + j * BLOCK_HEIGHT,
1003 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2);
1004 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH,
1005 BOARD_X + (i + 1) * BLOCK_WIDTH - 2,
1006 BOARD_Y + j * BLOCK_HEIGHT);
1007 #if LCD_DEPTH >= 2
1008 /* shadow drawing */
1009 rb->lcd_set_foreground (figures[block].color[2]);
1010 #endif
1011 rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
1012 BOARD_Y + j * BLOCK_HEIGHT + 1,
1013 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
1014 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1,
1015 BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
1016 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
1017 #else /* HAVE_LCD_CHARCELLS */
1018 pgfx_drawpixel (BOARD_X + i, BOARD_Y + j);
1019 #endif
1023 for (i = 0; i < 4; i++) {
1024 x = getRelativeX (rockblox_status.cf, i, rockblox_status.co)
1025 + rockblox_status.cx;
1026 y = getRelativeY (rockblox_status.cf, i, rockblox_status.co)
1027 + rockblox_status.cy;
1028 #ifdef HAVE_LCD_BITMAP
1029 #if LCD_DEPTH >= 2
1030 /* middle drawing */
1031 rb->lcd_set_foreground (figures[rockblox_status.cf].color[1]);
1032 #endif
1033 rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH,
1034 BOARD_Y + y * BLOCK_HEIGHT,
1035 BLOCK_WIDTH, BLOCK_HEIGHT);
1036 #if LCD_DEPTH >= 2
1037 /* light drawing */
1038 rb->lcd_set_foreground (figures[rockblox_status.cf].color[0]);
1039 #endif
1040 rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT,
1041 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2);
1042 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH,
1043 BOARD_X + (x + 1) * BLOCK_WIDTH - 2,
1044 BOARD_Y + y * BLOCK_HEIGHT);
1045 #if LCD_DEPTH >= 2
1046 /* shadow drawing */
1047 rb->lcd_set_foreground (figures[rockblox_status.cf].color[2]);
1048 #endif
1049 rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
1050 BOARD_Y + y * BLOCK_HEIGHT + 1,
1051 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
1052 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1,
1053 BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
1054 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
1055 #else /* HAVE_LCD_CHARCELLS */
1056 pgfx_drawpixel (BOARD_X + x, BOARD_Y + y);
1057 #endif
1059 MYLCD(update) ();
1062 static bool canMoveTo (int x, int y, int newOrientation)
1064 int i, rx, ry;
1065 for (i = 0; i < 4; i++) {
1066 ry = getRelativeY (rockblox_status.cf, i, newOrientation) + y;
1067 rx = getRelativeX (rockblox_status.cf, i, newOrientation) + x;
1068 if ((rx < 0 || rx >= BOARD_WIDTH) ||
1069 (ry < 0 || ry >= BOARD_HEIGHT) ||
1070 (rockblox_status.board[ry][rx] != EMPTY_BLOCK))
1071 return false;
1073 return true;
1076 /* draws the preview of next block in the preview window */
1077 static void draw_next_block (void)
1079 int i, rx, ry;
1080 /* clear preview window first */
1081 #if LCD_DEPTH >= 2
1082 rb->lcd_set_foreground (LCD_BLACK);
1083 #elif LCD_DEPTH == 1
1084 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
1085 #endif
1087 /* 4x4 */
1088 MYLCD(fillrect) (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4);
1090 #if LCD_DEPTH == 1
1091 MYLCD(set_drawmode) (DRMODE_SOLID);
1092 #endif
1094 /* draw the lightgray rectangles */
1095 #if LCD_DEPTH >= 16
1096 rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
1097 #elif LCD_DEPTH == 2
1098 rb->lcd_set_foreground (LCD_DARKGRAY);
1099 #endif
1101 #if LCD_DEPTH >= 2
1102 for (rx = 0; rx < 4; rx++)
1103 for (ry = 0; ry < 4; ry++)
1104 rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH,
1105 PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH,
1106 BLOCK_HEIGHT);
1107 #endif
1109 /* draw the figure */
1110 for (i = 0; i < 4; i++) {
1111 rx = getRelativeX (rockblox_status.nf, i, 0) + 2;
1112 ry = getRelativeY (rockblox_status.nf, i, 0) + 2;
1113 #ifdef HAVE_LCD_BITMAP
1114 #if LCD_DEPTH >= 2
1115 rb->lcd_set_foreground (figures[rockblox_status.nf].color[1]); /* middle drawing */
1116 #endif
1117 rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH,
1118 PREVIEW_Y + ry * BLOCK_HEIGHT,
1119 BLOCK_WIDTH, BLOCK_HEIGHT);
1120 #if LCD_DEPTH >= 2
1121 rb->lcd_set_foreground (figures[rockblox_status.nf].color[0]); /* light drawing */
1122 #endif
1123 rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH,
1124 PREVIEW_Y + ry * BLOCK_HEIGHT,
1125 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2);
1126 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH,
1127 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2,
1128 PREVIEW_Y + ry * BLOCK_HEIGHT);
1129 #if LCD_DEPTH >= 2
1130 rb->lcd_set_foreground (figures[rockblox_status.nf].color[2]); /* shadow drawing */
1131 #endif
1132 rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
1133 PREVIEW_Y + ry * BLOCK_HEIGHT + 1,
1134 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
1135 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1,
1136 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
1137 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
1138 #else /* HAVE_LCD_CHARCELLS */
1139 pgfx_drawpixel (PREVIEW_X + rx, PREVIEW_Y + ry);
1140 #endif
1145 /* move the block to a relative location */
1146 static void move_block (int x, int y, int o)
1148 if (canMoveTo (rockblox_status.cx + x, rockblox_status.cy + y, o)) {
1149 rockblox_status.cy += y;
1150 rockblox_status.cx += x;
1151 rockblox_status.co = o;
1155 /* try to add a new block to play with (return true if gameover) */
1156 static void new_block (void)
1158 rockblox_status.cy = 1;
1159 rockblox_status.cx = 5;
1160 rockblox_status.cf = rockblox_status.nf;
1161 rockblox_status.co = 0; /* start at the same orientation all time */
1162 rockblox_status.nf = t_rand (BLOCKS_NUM);
1163 rockblox_status.gameover = !canMoveTo (rockblox_status.cx,
1164 rockblox_status.cy, rockblox_status.co);
1166 draw_next_block ();
1170 /* check for filled rockblox_status.lines and do what necessary */
1171 static int check_lines (void)
1174 int i, j, y;
1175 int rockblox = 0;
1177 for (j = 0; j < BOARD_HEIGHT; j++) {
1178 for (i = 0; ((i < BOARD_WIDTH) &&
1179 (rockblox_status.board[j][i] != EMPTY_BLOCK)); i++);
1180 if (i == BOARD_WIDTH) { /* woo hoo, we have a line */
1181 rockblox++;
1182 for (y = j; y > 0; y--)
1184 for (i = 0; i < BOARD_WIDTH; i++)
1185 { /* fall line */
1186 rockblox_status.board[y][i] = rockblox_status.board[y - 1][i];
1192 return rockblox;
1195 /* moves down the figure and returns true if gameover */
1196 static void move_down (void)
1198 int l, i, rx, ry;
1200 if (!canMoveTo (rockblox_status.cx, rockblox_status.cy + 1, rockblox_status.co)) {
1201 /* save figure to board */
1202 for (i = 0; i < 4; i++) {
1203 rx = getRelativeX (rockblox_status.cf, i, rockblox_status.co) + rockblox_status.cx;
1204 ry = getRelativeY (rockblox_status.cf, i, rockblox_status.co) + rockblox_status.cy;
1205 rockblox_status.board[ry][rx] = rockblox_status.cf;
1207 /* check if formed some lines */
1208 l = check_lines ();
1209 if (l) {
1210 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
1211 rockblox_status.score += scoring[l - 1] * rockblox_status.level;
1212 rockblox_status.lines += l;
1213 rockblox_status.level = (int) rockblox_status.lines / 10 + 1;
1216 /* show details */
1217 show_details ();
1219 /* generate a new figure */
1220 new_block ();
1221 } else
1222 move_block (0, 1, rockblox_status.co);
1225 static bool rockblox_help(void)
1227 static char *help_text[] = {
1228 "Rockblox", "", "Aim", "",
1229 "Make", "the", "falling", "blocks", "of",
1230 "different", "shapes", "form", "full", "rows.",
1231 "Whenever", "a", "row", "is", "completed,",
1232 "it", "will", "be", "cleared", "away",
1233 "and", "you", "gain", "points."
1235 static struct style_text formation[]={
1236 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1237 { 2, C_RED },
1238 LAST_STYLE_ITEM
1241 #ifdef HAVE_LCD_BITMAP
1242 rb->lcd_setfont(FONT_UI);
1243 #endif
1244 #ifdef HAVE_LCD_COLOR
1245 rb->lcd_set_background(LCD_BLACK);
1246 rb->lcd_set_foreground(LCD_WHITE);
1247 #endif
1248 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1249 return true;
1250 #ifdef HAVE_LCD_BITMAP
1251 rb->lcd_setfont(FONT_SYSFIXED);
1252 #endif
1254 return false;
1257 static int rockblox_menu_cb(int action, const struct menu_item_ex *this_item)
1259 int i = ((intptr_t)this_item);
1260 if(action == ACTION_REQUEST_MENUITEM
1261 && !resume && (i==0 || i==5))
1262 return ACTION_EXIT_MENUITEM;
1263 return action;
1266 static int rockblox_menu(void)
1268 int selected = 0;
1270 MENUITEM_STRINGLIST(main_menu, "Rockblox Menu", rockblox_menu_cb,
1271 "Resume Game", "Start New Game",
1272 "Help", "High Scores", "Playback Control",
1273 "Quit without Saving", "Quit");
1275 rb->button_clear_queue();
1276 while (true) {
1277 switch (rb->do_menu(&main_menu, &selected, NULL, false)) {
1278 case 0:
1279 if(resume_file)
1280 rb->remove(RESUME_FILE);
1281 init_rockblox(true);
1282 return 0;
1283 case 1:
1284 init_rockblox(false);
1285 return 0;
1286 case 2:
1287 if (rockblox_help())
1288 return 1;
1289 break;
1290 case 3:
1291 highscore_show(-1, highscores, NUM_SCORES, true);
1292 break;
1293 case 4:
1294 if (playback_control(NULL))
1295 return 1;
1296 break;
1297 case 5:
1298 return 1;
1299 case 6:
1300 if (resume) {
1301 rb->splash(HZ*1, "Saving game ...");
1302 dump_resume();
1304 return 1;
1305 case MENU_ATTACHED_USB:
1306 return 1;
1307 default:
1308 return 1;
1309 break;
1315 static int rockblox_loop (void)
1317 int button;
1318 int lastbutton = BUTTON_NONE;
1319 long next_down_tick = *rb->current_tick + level_speed(rockblox_status.level);
1321 if (rockblox_menu()) {
1322 return 1;
1324 resume = false;
1325 resume_file = false;
1327 while (1) {
1328 #ifdef HAS_BUTTON_HOLD
1329 if (rb->button_hold ()) {
1330 /* Turn on backlight timeout (revert to settings) */
1331 backlight_use_settings(); /* backlight control in lib/helper.c */
1332 rb->splash(0, "Paused");
1333 while (rb->button_hold ())
1334 rb->sleep(HZ/10);
1336 /* Turn off backlight timeout */
1337 backlight_force_on(); /* backlight control in lib/helper.c */
1339 /* get rid of the splash text */
1340 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
1341 show_details ();
1342 #ifdef HIGH_SCORE_Y
1343 show_highscores ();
1344 #endif
1345 draw_next_block ();
1346 refresh_board ();
1348 #endif
1350 button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1));
1351 switch (button) {
1352 #ifdef ROCKBLOX_RC_OFF
1353 case ROCKBLOX_RC_OFF:
1354 #endif
1355 case ROCKBLOX_OFF:
1356 #ifdef ROCKBLOX_OFF_PRE
1357 if (lastbutton != ROCKBLOX_OFF_PRE)
1358 break;
1359 #endif
1360 resume = true;
1361 return 0;
1362 break;
1364 #if defined(ROCKBLOX_ROTATE)
1365 case ROCKBLOX_ROTATE:
1366 #endif
1367 case ROCKBLOX_ROTATE_CCW:
1368 case ROCKBLOX_ROTATE_CCW | BUTTON_REPEAT:
1369 #ifdef HAVE_SCROLLWHEEL
1370 /* if the wheel is disabled, add an event to the stack. */
1371 if(wheel_enabled == false)
1372 wheel_events++;
1374 /* if it's enabled, go ahead and rotate.. */
1375 if(wheel_enabled)
1376 #endif
1377 #ifdef ROCKBLOX_ROTATE_CCW2
1378 /* fallback */
1379 case ROCKBLOX_ROTATE_CCW2:
1380 #endif
1381 move_block (0, 0, (rockblox_status.co + 1) % figures[rockblox_status.cf].max_or);
1382 break;
1384 case ROCKBLOX_ROTATE_CW:
1385 case ROCKBLOX_ROTATE_CW | BUTTON_REPEAT:
1386 #ifdef HAVE_SCROLLWHEEL
1387 if(wheel_enabled == false)
1388 wheel_events++;
1390 if(wheel_enabled)
1391 #endif
1392 #ifdef ROCKBLOX_ROTATE_CW2
1393 /* fallback */
1394 case ROCKBLOX_ROTATE_CW2:
1395 #endif
1396 move_block (0, 0,
1397 (rockblox_status.co + figures[rockblox_status.cf].max_or -
1398 1) % figures[rockblox_status.cf].max_or);
1399 break;
1401 case ROCKBLOX_DOWN:
1402 case ROCKBLOX_DOWN | BUTTON_REPEAT:
1403 move_block (0, 1, rockblox_status.co);
1404 break;
1406 case ROCKBLOX_RIGHT:
1407 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
1408 move_block (1, 0, rockblox_status.co);
1409 break;
1411 case ROCKBLOX_LEFT:
1412 case ROCKBLOX_LEFT | BUTTON_REPEAT:
1413 move_block (-1, 0, rockblox_status.co);
1414 break;
1416 case ROCKBLOX_DROP:
1417 #ifdef ROCKBLOX_DROP_PRE
1418 if (lastbutton != ROCKBLOX_DROP_PRE)
1419 break;
1420 #endif
1421 while (canMoveTo (rockblox_status.cx, rockblox_status.cy + 1, rockblox_status.co))
1422 move_block (0, 1, rockblox_status.co);
1423 break;
1424 #ifdef ROCKBLOX_RESTART
1425 case ROCKBLOX_RESTART:
1426 rb->splash (HZ * 1, "Restarting...");
1427 init_rockblox (false);
1428 break;
1429 #endif
1431 default:
1432 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
1433 return PLUGIN_USB_CONNECTED;
1434 break;
1436 if (button != BUTTON_NONE)
1437 lastbutton = button;
1439 #ifdef HAVE_SCROLLWHEEL
1440 /* check if we should enable the scroll wheel, if events
1441 * begin to stack up... */
1442 if(wheel_enabled == false)
1444 /* stopped rotating the wheel, reset the count */
1445 if(wheel_events == last_wheel_event)
1447 last_wheel_event = 0;
1448 wheel_events = 0;
1450 /* rotated the wheel a while constantly, enable it. */
1451 else if(wheel_events > 3)
1453 wheel_enabled = true;
1456 /* this evens out the last event and the "current" event.
1457 * if we get an event next time through button reading, it will
1458 * remain ahead of last_event. if we don't, they'll end up equaling
1459 * each other.. thus, the scroll count will be reset. */
1460 if(wheel_enabled == false && wheel_events > last_wheel_event)
1461 last_wheel_event++;
1463 #endif
1465 if (TIME_AFTER(*rb->current_tick, next_down_tick)) {
1466 move_down ();
1467 next_down_tick += level_speed(rockblox_status.level);
1468 if (TIME_AFTER(*rb->current_tick, next_down_tick))
1469 /* restart time "raster" when we had to wait longer than usual
1470 * (pause, game restart etc) */
1471 next_down_tick = *rb->current_tick + level_speed(rockblox_status.level);
1474 if (rockblox_status.gameover) {
1475 #if LCD_DEPTH >= 2
1476 rb->lcd_set_foreground (LCD_BLACK);
1477 #endif
1478 show_game_over();
1479 resume = false;
1480 return 0;
1483 refresh_board ();
1486 return 0;
1489 enum plugin_status plugin_start (const void *parameter)
1492 (void) parameter;
1494 rb->srand (*rb->current_tick);
1496 /* Load HighScore if any */
1497 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1499 #if LCD_DEPTH > 1
1500 rb->lcd_set_backdrop(NULL);
1501 #endif
1503 #ifdef HAVE_LCD_BITMAP
1504 rb->lcd_setfont (FONT_SYSFIXED);
1505 #else
1506 if (!pgfx_init(4, 2))
1508 rb->splash(HZ*2, "Old LCD :(");
1509 return PLUGIN_OK;
1511 #endif
1512 /* Turn off backlight timeout */
1513 backlight_force_on(); /* backlight control in lib/helper.c */
1514 load_game();
1515 resume_file = resume;
1516 while(!rockblox_loop()) {
1517 if(!resume) {
1518 int position = highscore_update(rockblox_status.score,
1519 rockblox_status.level, "",
1520 highscores, NUM_SCORES);
1521 if (position != -1) {
1522 if (position == 0)
1523 rb->splash(HZ*2, "New High Score");
1524 highscore_show(position, highscores, NUM_SCORES, true);
1529 #ifndef HAVE_LCD_BITMAP
1530 pgfx_release();
1531 #endif
1532 /* Save user's HighScore */
1533 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1534 backlight_use_settings(); /* backlight control in lib/helper.c */
1536 return PLUGIN_OK;