Extract config file saving code to a function; Do not write the NUL character to...
[kugel-rb.git] / apps / plugins / rockblox.c
blob717aedab1ff3c7e86f5aa90296dd0a43570de945
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"
29 #include "lib/mylcd.h"
33 #if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
34 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
35 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
37 #define ROCKBLOX_OFF (BUTTON_MENU | BUTTON_SELECT)
38 #define ROCKBLOX_ROTATE_CCW BUTTON_SCROLL_BACK
39 #define ROCKBLOX_ROTATE_CCW2 (BUTTON_MENU | BUTTON_REL)
40 #define ROCKBLOX_ROTATE_CW BUTTON_SCROLL_FWD
41 #define ROCKBLOX_LEFT BUTTON_LEFT
42 #define ROCKBLOX_RIGHT BUTTON_RIGHT
43 #define ROCKBLOX_DOWN BUTTON_PLAY
44 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_PLAY)
45 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
47 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
48 (CONFIG_KEYPAD == IRIVER_H300_PAD)
50 #define ROCKBLOX_OFF BUTTON_OFF
51 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
52 #define ROCKBLOX_ROTATE_CW BUTTON_SELECT
53 #define ROCKBLOX_DOWN BUTTON_DOWN
54 #define ROCKBLOX_LEFT BUTTON_LEFT
55 #define ROCKBLOX_RIGHT BUTTON_RIGHT
56 #define ROCKBLOX_DROP BUTTON_MODE
57 #define ROCKBLOX_RESTART BUTTON_ON
59 #define ROCKBLOX_RC_OFF BUTTON_RC_STOP
61 #elif CONFIG_KEYPAD == RECORDER_PAD
63 #define ROCKBLOX_OFF BUTTON_OFF
64 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
65 #define ROCKBLOX_ROTATE_CW BUTTON_PLAY
66 #define ROCKBLOX_DOWN BUTTON_DOWN
67 #define ROCKBLOX_LEFT BUTTON_LEFT
68 #define ROCKBLOX_RIGHT BUTTON_RIGHT
69 #define ROCKBLOX_DROP BUTTON_ON
70 #define ROCKBLOX_RESTART BUTTON_F1
72 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
74 #define ROCKBLOX_OFF BUTTON_OFF
75 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
76 #define ROCKBLOX_ROTATE_CW BUTTON_SELECT
77 #define ROCKBLOX_DOWN BUTTON_DOWN
78 #define ROCKBLOX_LEFT BUTTON_LEFT
79 #define ROCKBLOX_RIGHT BUTTON_RIGHT
80 #define ROCKBLOX_DROP BUTTON_ON
81 #define ROCKBLOX_RESTART BUTTON_F1
83 #elif CONFIG_KEYPAD == PLAYER_PAD
85 #define ROCKBLOX_OFF_PRE BUTTON_STOP
86 #define ROCKBLOX_OFF (BUTTON_STOP|BUTTON_REL)
87 #define ROCKBLOX_ROTATE_CCW BUTTON_PLAY
88 #define ROCKBLOX_ROTATE_CW (BUTTON_ON|BUTTON_PLAY)
89 #define ROCKBLOX_DOWN BUTTON_MENU
90 #define ROCKBLOX_LEFT BUTTON_LEFT
91 #define ROCKBLOX_RIGHT BUTTON_RIGHT
92 #define ROCKBLOX_DROP_PRE BUTTON_ON
93 #define ROCKBLOX_DROP (BUTTON_ON|BUTTON_REL)
94 #define ROCKBLOX_RESTART (BUTTON_STOP|BUTTON_MENU)
96 #elif CONFIG_KEYPAD == ONDIO_PAD
98 #define ROCKBLOX_OFF_PRE BUTTON_OFF
99 #define ROCKBLOX_OFF (BUTTON_OFF|BUTTON_REL)
100 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
101 #define ROCKBLOX_ROTATE_CW (BUTTON_MENU|BUTTON_UP)
102 #define ROCKBLOX_DOWN BUTTON_DOWN
103 #define ROCKBLOX_LEFT BUTTON_LEFT
104 #define ROCKBLOX_RIGHT BUTTON_RIGHT
105 #define ROCKBLOX_DROP_PRE BUTTON_MENU
106 #define ROCKBLOX_DROP (BUTTON_MENU|BUTTON_REL)
107 #define ROCKBLOX_RESTART (BUTTON_OFF|BUTTON_MENU)
109 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
111 #define ROCKBLOX_OFF BUTTON_POWER
112 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
113 #define ROCKBLOX_ROTATE_CW BUTTON_SELECT
114 #define ROCKBLOX_DOWN BUTTON_DOWN
115 #define ROCKBLOX_LEFT BUTTON_LEFT
116 #define ROCKBLOX_RIGHT BUTTON_RIGHT
117 #define ROCKBLOX_DROP BUTTON_REC
118 #define ROCKBLOX_RESTART BUTTON_PLAY
120 #elif CONFIG_KEYPAD == SANSA_E200_PAD
122 #define ROCKBLOX_OFF BUTTON_POWER
123 #define ROCKBLOX_ROTATE_CCW BUTTON_SCROLL_BACK
124 #define ROCKBLOX_ROTATE_CCW2 BUTTON_UP
125 #define ROCKBLOX_ROTATE_CW BUTTON_SCROLL_FWD
126 #define ROCKBLOX_DOWN BUTTON_DOWN
127 #define ROCKBLOX_LEFT BUTTON_LEFT
128 #define ROCKBLOX_RIGHT BUTTON_RIGHT
129 #define ROCKBLOX_DROP BUTTON_SELECT
130 #define ROCKBLOX_RESTART BUTTON_REC
132 #elif CONFIG_KEYPAD == SANSA_FUZE_PAD
134 #define ROCKBLOX_OFF (BUTTON_HOME|BUTTON_REPEAT)
135 #define ROCKBLOX_ROTATE_CCW BUTTON_SCROLL_BACK
136 #define ROCKBLOX_ROTATE_CCW2 BUTTON_UP
137 #define ROCKBLOX_ROTATE_CW BUTTON_SCROLL_FWD
138 #define ROCKBLOX_DOWN BUTTON_DOWN
139 #define ROCKBLOX_LEFT BUTTON_LEFT
140 #define ROCKBLOX_RIGHT BUTTON_RIGHT
141 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
142 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_UP)
145 #elif CONFIG_KEYPAD == SANSA_C200_PAD
147 #define ROCKBLOX_OFF BUTTON_POWER
148 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
149 #define ROCKBLOX_ROTATE_CCW2 BUTTON_VOL_DOWN
150 #define ROCKBLOX_ROTATE_CW BUTTON_VOL_UP
151 #define ROCKBLOX_DOWN BUTTON_DOWN
152 #define ROCKBLOX_LEFT BUTTON_LEFT
153 #define ROCKBLOX_RIGHT BUTTON_RIGHT
154 #define ROCKBLOX_DROP BUTTON_SELECT
155 #define ROCKBLOX_RESTART BUTTON_REC
157 #elif CONFIG_KEYPAD == SANSA_CLIP_PAD
159 #define ROCKBLOX_OFF BUTTON_POWER
160 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
161 #define ROCKBLOX_ROTATE_CCW2 BUTTON_VOL_DOWN
162 #define ROCKBLOX_ROTATE_CW BUTTON_VOL_UP
163 #define ROCKBLOX_DOWN BUTTON_DOWN
164 #define ROCKBLOX_LEFT BUTTON_LEFT
165 #define ROCKBLOX_RIGHT BUTTON_RIGHT
166 #define ROCKBLOX_DROP BUTTON_SELECT
167 #define ROCKBLOX_RESTART BUTTON_HOME
169 #elif CONFIG_KEYPAD == SANSA_M200_PAD
171 #define ROCKBLOX_OFF BUTTON_POWER
172 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
173 #define ROCKBLOX_ROTATE_CCW2 BUTTON_VOL_DOWN
174 #define ROCKBLOX_ROTATE_CW BUTTON_VOL_UP
175 #define ROCKBLOX_DOWN BUTTON_DOWN
176 #define ROCKBLOX_LEFT BUTTON_LEFT
177 #define ROCKBLOX_RIGHT BUTTON_RIGHT
178 #define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_UP)
179 #define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
181 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
183 #define ROCKBLOX_OFF BUTTON_POWER
184 #define ROCKBLOX_ROTATE_CCW BUTTON_SCROLL_UP
185 #define ROCKBLOX_ROTATE_CW BUTTON_REW
186 #define ROCKBLOX_DOWN BUTTON_SCROLL_DOWN
187 #define ROCKBLOX_LEFT BUTTON_LEFT
188 #define ROCKBLOX_RIGHT BUTTON_RIGHT
189 #define ROCKBLOX_DROP BUTTON_FF
190 #define ROCKBLOX_RESTART BUTTON_PLAY
192 #elif CONFIG_KEYPAD == GIGABEAT_PAD
194 #define ROCKBLOX_OFF BUTTON_POWER
195 #define ROCKBLOX_ROTATE_CCW BUTTON_VOL_DOWN
196 #define ROCKBLOX_ROTATE_CW BUTTON_VOL_UP
197 #define ROCKBLOX_ROTATE BUTTON_UP
198 #define ROCKBLOX_DOWN BUTTON_DOWN
199 #define ROCKBLOX_LEFT BUTTON_LEFT
200 #define ROCKBLOX_RIGHT BUTTON_RIGHT
201 #define ROCKBLOX_DROP BUTTON_SELECT
202 #define ROCKBLOX_RESTART BUTTON_A
204 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
206 #define ROCKBLOX_OFF BUTTON_PLAY
207 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
208 #define ROCKBLOX_ROTATE_CW BUTTON_SELECT
209 #define ROCKBLOX_DOWN BUTTON_DOWN
210 #define ROCKBLOX_LEFT BUTTON_LEFT
211 #define ROCKBLOX_RIGHT BUTTON_RIGHT
212 #define ROCKBLOX_DROP BUTTON_MODE
213 #define ROCKBLOX_RESTART BUTTON_EQ
215 #elif CONFIG_KEYPAD == MROBE500_PAD
216 #define ROCKBLOX_OFF BUTTON_POWER
218 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
219 #define ROCKBLOX_OFF BUTTON_BACK
220 #define ROCKBLOX_ROTATE_CCW BUTTON_VOL_DOWN
221 #define ROCKBLOX_ROTATE_CW BUTTON_VOL_UP
222 #define ROCKBLOX_ROTATE BUTTON_UP
223 #define ROCKBLOX_DOWN BUTTON_DOWN
224 #define ROCKBLOX_LEFT BUTTON_LEFT
225 #define ROCKBLOX_RIGHT BUTTON_RIGHT
226 #define ROCKBLOX_DROP BUTTON_SELECT
227 #define ROCKBLOX_RESTART BUTTON_PLAY
229 #elif CONFIG_KEYPAD == MROBE100_PAD
231 #define ROCKBLOX_OFF BUTTON_POWER
232 #define ROCKBLOX_ROTATE_CCW BUTTON_MENU
233 #define ROCKBLOX_ROTATE_CW BUTTON_PLAY
234 #define ROCKBLOX_ROTATE BUTTON_UP
235 #define ROCKBLOX_DOWN BUTTON_DOWN
236 #define ROCKBLOX_LEFT BUTTON_LEFT
237 #define ROCKBLOX_RIGHT BUTTON_RIGHT
238 #define ROCKBLOX_DROP BUTTON_SELECT
239 #define ROCKBLOX_RESTART BUTTON_DISPLAY
241 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
243 #define ROCKBLOX_OFF BUTTON_RC_REC
244 #define ROCKBLOX_ROTATE_CCW BUTTON_RC_VOL_DOWN
245 #define ROCKBLOX_ROTATE_CW BUTTON_RC_VOL_UP
246 #define ROCKBLOX_DOWN BUTTON_RC_MENU
247 #define ROCKBLOX_LEFT BUTTON_RC_REW
248 #define ROCKBLOX_RIGHT BUTTON_RC_FF
249 #define ROCKBLOX_DROP BUTTON_RC_PLAY
250 #define ROCKBLOX_RESTART BUTTON_RC_MODE
252 #elif CONFIG_KEYPAD == COWON_D2_PAD
254 #define ROCKBLOX_OFF BUTTON_POWER
255 #define ROCKBLOX_RESTART BUTTON_MENU
257 #elif CONFIG_KEYPAD == IAUDIO67_PAD
259 #define ROCKBLOX_OFF BUTTON_POWER
260 #define ROCKBLOX_ROTATE_CCW BUTTON_VOLDOWN
261 #define ROCKBLOX_ROTATE_CW BUTTON_VOLUP
262 #define ROCKBLOX_DOWN BUTTON_STOP
263 #define ROCKBLOX_LEFT BUTTON_LEFT
264 #define ROCKBLOX_RIGHT BUTTON_RIGHT
265 #define ROCKBLOX_DROP BUTTON_PLAY
266 #define ROCKBLOX_RESTART BUTTON_MENU
268 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
269 #define ROCKBLOX_OFF BUTTON_BACK
270 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
271 #define ROCKBLOX_ROTATE_CW BUTTON_PLAY
272 #define ROCKBLOX_DOWN BUTTON_DOWN
273 #define ROCKBLOX_LEFT BUTTON_LEFT
274 #define ROCKBLOX_RIGHT BUTTON_RIGHT
275 #define ROCKBLOX_DROP BUTTON_SELECT
276 #define ROCKBLOX_RESTART BUTTON_CUSTOM
278 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
280 #define ROCKBLOX_OFF BUTTON_POWER
281 #define ROCKBLOX_ROTATE_CCW BUTTON_VOL_DOWN
282 #define ROCKBLOX_ROTATE_CW BUTTON_VOL_UP
283 #define ROCKBLOX_ROTATE BUTTON_UP
284 #define ROCKBLOX_DOWN BUTTON_DOWN
285 #define ROCKBLOX_LEFT BUTTON_LEFT
286 #define ROCKBLOX_RIGHT BUTTON_RIGHT
287 #define ROCKBLOX_DROP BUTTON_SELECT
288 #define ROCKBLOX_RESTART BUTTON_MENU
290 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
292 #define ROCKBLOX_OFF BUTTON_POWER
293 #define ROCKBLOX_ROTATE_CCW BUTTON_PREV
294 #define ROCKBLOX_ROTATE_CW BUTTON_NEXT
295 #define ROCKBLOX_ROTATE BUTTON_UP
296 #define ROCKBLOX_DOWN BUTTON_DOWN
297 #define ROCKBLOX_LEFT BUTTON_LEFT
298 #define ROCKBLOX_RIGHT BUTTON_RIGHT
299 #define ROCKBLOX_DROP BUTTON_PLAY
300 #define ROCKBLOX_RESTART BUTTON_MENU
302 # elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
304 #define ROCKBLOX_OFF BUTTON_POWER
305 #define ROCKBLOX_ROTATE_CCW BUTTON_VOL_DOWN
306 #define ROCKBLOX_ROTATE_CW BUTTON_VOL_UP
307 #define ROCKBLOX_ROTATE BUTTON_UP
308 #define ROCKBLOX_DOWN BUTTON_DOWN
309 #define ROCKBLOX_LEFT BUTTON_PREV
310 #define ROCKBLOX_RIGHT BUTTON_NEXT
311 #define ROCKBLOX_DROP BUTTON_PLAY
312 #define ROCKBLOX_RESTART BUTTON_MENU
314 #elif CONFIG_KEYPAD == ONDAVX747_PAD
315 #define ROCKBLOX_OFF BUTTON_POWER
316 #define ROCKBLOX_RESTART BUTTON_MENU
317 #elif CONFIG_KEYPAD == ONDAVX777_PAD
318 #define ROCKBLOX_OFF BUTTON_POWER
320 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
322 #define ROCKBLOX_OFF (BUTTON_REC|BUTTON_PLAY)
323 #define ROCKBLOX_ROTATE_CCW BUTTON_UP
324 #define ROCKBLOX_ROTATE_CW BUTTON_DOWN
325 #define ROCKBLOX_DOWN BUTTON_REW
326 #define ROCKBLOX_LEFT BUTTON_LEFT
327 #define ROCKBLOX_RIGHT BUTTON_RIGHT
328 #define ROCKBLOX_DROP BUTTON_FFWD
329 #define ROCKBLOX_RESTART (BUTTON_REC|BUTTON_REW)
331 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
333 #define ROCKBLOX_OFF BUTTON_REC
334 #define ROCKBLOX_ROTATE_CCW BUTTON_PLAY
335 #define ROCKBLOX_ROTATE_CW BUTTON_MENU
336 #define ROCKBLOX_DOWN BUTTON_DOWN
337 #define ROCKBLOX_LEFT BUTTON_PREV
338 #define ROCKBLOX_RIGHT BUTTON_NEXT
339 #define ROCKBLOX_DROP BUTTON_OK
340 #define ROCKBLOX_RESTART BUTTON_CANCEL
342 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
343 #define ROCKBLOX_OFF (BUTTON_REC|BUTTON_PLAY)
344 #define ROCKBLOX_ROTATE_CCW BUTTON_REW
345 #define ROCKBLOX_ROTATE_CW BUTTON_FF
346 #define ROCKBLOX_DOWN BUTTON_FUNC
347 #define ROCKBLOX_LEFT BUTTON_VOL_DOWN
348 #define ROCKBLOX_RIGHT BUTTON_VOL_UP
349 #define ROCKBLOX_DROP BUTTON_PLAY
350 #define ROCKBLOX_RESTART BUTTON_REC
352 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
353 #define ROCKBLOX_OFF (BUTTON_REC|BUTTON_REPEAT)
354 #define ROCKBLOX_ROTATE_CCW BUTTON_REW
355 #define ROCKBLOX_ROTATE_CW BUTTON_FF
356 #define ROCKBLOX_DOWN BUTTON_DOWN
357 #define ROCKBLOX_LEFT BUTTON_MENU
358 #define ROCKBLOX_RIGHT BUTTON_ENTER
359 #define ROCKBLOX_DROP BUTTON_PLAY
360 #define ROCKBLOX_RESTART BUTTON_REC
362 #else
363 #error No keymap defined!
364 #endif
366 #ifdef HAVE_TOUCHSCREEN
367 #ifndef ROCKBLOX_OFF
368 #define ROCKBLOX_OFF BUTTON_TOPLEFT
369 #endif
370 #ifdef ROCKBLOX_ROTATE_CCW
371 #define ROCKBLOX_ROTATE_CCW2 BUTTON_BOTTOMLEFT
372 #else
373 #define ROCKBLOX_ROTATE_CCW BUTTON_BOTTOMLEFT
374 #endif
375 #ifdef ROCKBLOX_ROTATE_CW
376 #define ROCKBLOX_ROTATE_CW2 BUTTON_BOTTOMRIGHT
377 #else
378 #define ROCKBLOX_ROTATE_CW BUTTON_BOTTOMRIGHT
379 #define ROCKBLOX_ROTATE_CW2 BUTTON_TOPMIDDLE
380 #endif
381 #ifndef ROCKBLOX_DOWN
382 #define ROCKBLOX_DOWN BUTTON_BOTTOMMIDDLE
383 #endif
384 #ifndef ROCKBLOX_LEFT
385 #define ROCKBLOX_LEFT BUTTON_MIDLEFT
386 #endif
387 #ifndef ROCKBLOX_RIGHT
388 #define ROCKBLOX_RIGHT BUTTON_MIDRIGHT
389 #endif
390 #ifndef ROCKBLOX_DROP
391 #define ROCKBLOX_DROP BUTTON_CENTER
392 #endif
393 #ifndef ROCKBLOX_RESTART
394 #define ROCKBLOX_RESTART BUTTON_TOPRIGHT
395 #endif
396 #endif
398 #define BLOCKS_NUM 7
399 #define EMPTY_BLOCK 7
401 #define BOARD_WIDTH 10
403 #ifdef HAVE_LCD_BITMAP
405 #define BOARD_HEIGHT 20
407 #if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
409 #define BLOCK_WIDTH 24
410 #define BLOCK_HEIGHT 24
411 #define BOARD_X 172
412 #define BOARD_Y 0
413 #define PREVIEW_X 24
414 #define PREVIEW_Y 22
415 #define LABEL_X 482
416 #define SCORE_Y 50
417 #define LEVEL_Y 140
418 #define LINES_Y 210
420 #elif (LCD_WIDTH == 480) && (LCD_HEIGHT == 640)
422 #define BLOCK_WIDTH 30
423 #define BLOCK_HEIGHT 30
424 #define BOARD_X 14
425 #define BOARD_Y 2
426 #define PREVIEW_X 342
427 #define PREVIEW_Y 482
428 #define LABEL_X 344
429 #define SCORE_Y 58
430 #define LEVEL_Y 142
431 #define LINES_Y 218
433 #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
435 #define BLOCK_WIDTH 12
436 #define BLOCK_HEIGHT 12
437 #define BOARD_X 86
438 #define BOARD_Y 0
439 #define PREVIEW_X 12
440 #define PREVIEW_Y 11
441 #define LABEL_X 242
442 #define SCORE_Y 25
443 #define LEVEL_Y 70
444 #define LINES_Y 105
446 #elif (LCD_WIDTH == 240) && ((LCD_HEIGHT == 320) || (LCD_HEIGHT == 400))
448 #define BLOCK_WIDTH 15
449 #define BLOCK_HEIGHT 15
450 #define BOARD_X 7
451 #define BOARD_Y 1
452 #define PREVIEW_X 171
453 #define PREVIEW_Y 241
454 #define LABEL_X 172
455 #define SCORE_Y 29
456 #define LEVEL_Y 71
457 #define LINES_Y 109
458 #define HIGH_LABEL_X 172
459 #define HIGH_SCORE_Y 163
460 #define HIGH_LEVEL_Y 172
462 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
464 #define BLOCK_WIDTH 8
465 #define BLOCK_HEIGHT 8
466 #define BOARD_X 27
467 #define BOARD_Y 5
468 #define PREVIEW_X 158
469 #define PREVIEW_Y 130
470 #define LABEL_X 147
471 #define SCORE_Y 20
472 #define LEVEL_Y 65
473 #define LINES_Y 100
475 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
477 #define BLOCK_WIDTH 6
478 #define BLOCK_HEIGHT 6
479 #define BOARD_X 25
480 #define BOARD_Y 1
481 #define PREVIEW_X 126
482 #define PREVIEW_Y 102
483 #define LABEL_X 112
484 #define SCORE_Y 17
485 #define LEVEL_Y 49
486 #define LINES_Y 81
488 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
490 /* no room for the space in the highscore list */
491 #define _SPACE ""
493 #define BLOCK_WIDTH 10
494 #define BLOCK_HEIGHT 10
495 #define BOARD_X 6
496 #define BOARD_Y 10
497 #define PREVIEW_X 124
498 #define PREVIEW_Y 174
499 #define LABEL_X 117
500 #define SCORE_Y 18
501 #define LEVEL_Y 52
502 #define LINES_Y 85
503 #define HIGH_SCORE_Y 119
504 #define HIGH_LEVEL_Y 126
505 #define HIGH_LABEL_X 114
507 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
510 #define BLOCK_WIDTH 6
511 #define BLOCK_HEIGHT 6
512 #define BOARD_X 22
513 #define BOARD_Y 3
514 #define PREVIEW_X 114
515 #define PREVIEW_Y 100
516 #define LABEL_X 101
517 #define SCORE_Y 17
518 #define LEVEL_Y 49
519 #define LINES_Y 82
521 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
523 #define BLOCK_WIDTH 5
524 #define BLOCK_HEIGHT 5
525 #define BOARD_X 14
526 #define BOARD_Y 0
527 #define PREVIEW_X 98
528 #define PREVIEW_Y 88
529 #define LABEL_X 80
530 #define SCORE_Y 15
531 #define LEVEL_Y 45
532 #define LINES_Y 74
534 #elif (LCD_WIDTH == 132) && (LCD_HEIGHT == 80)
536 #define BLOCK_WIDTH 4
537 #define BLOCK_HEIGHT 4
538 #define BOARD_X 10
539 #define BOARD_Y 0
540 #define PREVIEW_X 89
541 #define PREVIEW_Y 61
542 #define LABEL_X 78
543 #define SCORE_Y 10
544 #define LEVEL_Y 30
545 #define LINES_Y 50
547 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
549 #define BLOCK_WIDTH 6
550 #define BLOCK_HEIGHT 6
551 #define BOARD_X 4
552 #define BOARD_Y 3
553 #define PREVIEW_X 84
554 #define PREVIEW_Y 100
555 #define LABEL_X 71
556 #define SCORE_Y 17
557 #define LEVEL_Y 49
558 #define LINES_Y 82
560 /* NOTE: This is for the GoGear SA9200 and is only
561 temporary until I can get better coordinates! */
562 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 160)
564 #define BLOCK_WIDTH 6
565 #define BLOCK_HEIGHT 6
566 #define BOARD_X 4
567 #define BOARD_Y 3
568 #define PREVIEW_X 84
569 #define PREVIEW_Y 100
570 #define LABEL_X 71
571 #define SCORE_Y 17
572 #define LEVEL_Y 49
573 #define LINES_Y 82
575 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 96)
577 #define BLOCK_WIDTH 4
578 #define BLOCK_HEIGHT 4
579 #define BOARD_X 14
580 #define BOARD_Y 2
581 #define PREVIEW_X 89
582 #define PREVIEW_Y 76
583 #define LABEL_X 70
584 #define SCORE_Y 14
585 #define LEVEL_Y 39
586 #define LINES_Y 64
588 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 64)
590 #define BLOCK_WIDTH 3
591 #define BLOCK_HEIGHT 3
592 #define BOARD_X 9
593 #define BOARD_Y 3
594 #define PREVIEW_X 53
595 #define PREVIEW_Y 5
596 #define LABEL_X 70
597 #define SCORE_Y 32
598 #define LEVEL_Y 13
599 #define LINES_Y 51
601 #elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
603 #define BLOCK_WIDTH 4
604 #define BLOCK_HEIGHT 3
605 #define BOARD_X 9
606 #define BOARD_Y 3
607 #define PREVIEW_X 59
608 #define PREVIEW_Y 5
609 #define LABEL_X 59
610 #define SCORE_Y 32
611 #define LEVEL_Y 13
612 #define LEVEL_X 78
613 #define LINES_Y 51
615 #endif
617 #ifndef LEVEL_X
618 #define LEVEL_X LABEL_X
619 #endif
621 #ifndef LINES_X
622 #define LINES_X LABEL_X
623 #endif
625 extern const fb_data rockblox_background[];
627 #else /* HAVE_LCD_CHARCELLS */
629 #define BOARD_HEIGHT 14
631 #define BLOCK_WIDTH 1
632 #define BLOCK_HEIGHT 1
633 #define BOARD_X 5
634 #define BOARD_Y 0
635 #define PREVIEW_X 15
636 #define PREVIEW_Y 1
638 #endif
640 #ifndef _SPACE
641 #define _SPACE " "
642 #endif
643 /* <<Explanation on Rockblox shapes>>
646 %% - O has 1 orientation
648 %% %
649 %% %% - Z has 2 orientations
652 %% %
653 %% %% - S has 2 orientations
657 % %%%% - I has 2 orientations
660 % %%
661 % % % %%% - L has 4 orientations
662 %% %%% % %
664 % %%
665 % % % %%% - J has 4 orientations
666 %% %%% % %
668 % % %%%
669 %% % %% % - T has 4 orientations
670 % %%% %
673 /* c=current f=figure o=orientation n=next */
674 static struct _rockblox_status
676 int gameover;
677 int lines;
678 int level;
679 int score;
680 int cx;
681 int cy;
682 int cf;
683 int co;
684 int nf;
685 short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */
686 } rockblox_status;
688 /* prototypes */
689 static void draw_next_block(void);
690 static void new_block(void);
692 #ifdef HAVE_SCROLLWHEEL
693 int wheel_events = 0, last_wheel_event = 0;
694 bool wheel_enabled = false;
695 #endif
697 static const short scoring[4] = { /* scoring for each number of lines */
698 #if BOARD_HEIGHT == 20
699 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
700 #elif BOARD_HEIGHT == 14 /* Player special values */
701 60 /* single */ , 150 /* double */ , 500 /* triple */ , 2000 /* rockblox */
702 #endif
705 struct figure
707 #if LCD_DEPTH >= 2
708 unsigned short color[3]; /* color of figure (light,middle,shadow) */
709 #endif
710 unsigned short max_or; /* max orientations */
711 signed short shapeX[4], shapeY[4]; /* implementation of figures */
714 /* array of figures */
715 figures[BLOCKS_NUM] = {
716 /* O */
718 #if LCD_DEPTH >= 16
719 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
720 LCD_RGBPACK(0,153,153)},
721 #elif LCD_DEPTH == 2
722 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
723 #endif
725 {-1, 0, -1, 0},
726 {0, 0, 1, 1}
728 /* I */
730 #if LCD_DEPTH >= 16
731 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
732 LCD_RGBPACK (153, 0, 0)},
733 #elif LCD_DEPTH == 2
734 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
735 #endif
737 {-2, -1, 0, 1},
738 {0, 0, 0, 0}
740 /* 'Z' */
742 #if LCD_DEPTH >= 16
743 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
744 LCD_RGBPACK (0, 153, 0)},
745 #elif LCD_DEPTH == 2
746 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
747 #endif
749 {0, 1, -1, 0},
750 {0, 0, 1, 1}
752 /* 'S' */
754 #if LCD_DEPTH >= 16
755 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
756 LCD_RGBPACK (0, 0, 153)},
757 #elif LCD_DEPTH == 2
758 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
759 #endif
761 {-1, 0, 0, 1},
762 {0, 0, 1, 1}
764 /* 'L' */
766 #if LCD_DEPTH >= 16
767 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
768 LCD_RGBPACK (153, 153, 0)},
769 #elif LCD_DEPTH == 2
770 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
771 #endif
773 {-1, 0, 1, 1},
774 {0, 0, 0, 1}
776 /* 'J' */
778 #if LCD_DEPTH >= 16
779 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
780 LCD_RGBPACK (153, 0, 153)},
781 #elif LCD_DEPTH == 2
782 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
783 #endif
785 {-1, 0, 1, -1},
786 {0, 0, 0, 1}
788 /* 'T' */
790 #if LCD_DEPTH >= 16
791 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
792 LCD_RGBPACK (85, 85, 85)},
793 #elif LCD_DEPTH == 2
794 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
795 #endif
797 {-1, 0, 1, 0},
798 {0, 0, 0, 1}
801 bool resume = false;
802 bool resume_file = false;
804 /* Rockbox File System only supports full filenames inc dir */
805 #define SCORE_FILE PLUGIN_GAMES_DIR "/rockblox.score"
806 #define RESUME_FILE PLUGIN_GAMES_DIR "/rockblox.resume"
807 #define NUM_SCORES 5
809 /* Default High Scores... */
810 struct highscore highscores[NUM_SCORES];
812 /* get random number from (0) to (range-1) */
813 static int t_rand (int range)
815 return rb->rand () % range;
818 static inline void show_game_over (void)
820 rb->splash(HZ,"Game over!");
823 /* init the board array to have no blocks */
824 static void init_board (void)
826 int i, j;
827 for (i = 0; i < BOARD_WIDTH; i++)
828 for (j = 0; j < BOARD_HEIGHT; j++)
829 rockblox_status.board[j][i] = EMPTY_BLOCK;
832 /* show the score, level and lines */
833 static void show_details (void)
835 #ifdef HAVE_LCD_BITMAP
836 #if LCD_DEPTH >= 2
837 rb->lcd_set_foreground (LCD_BLACK);
838 rb->lcd_set_background (LCD_WHITE);
839 #endif
840 rb->lcd_putsxyf (LABEL_X, SCORE_Y, "%d", rockblox_status.score);
841 rb->lcd_putsxyf (LEVEL_X, LEVEL_Y, "%d", rockblox_status.level);
842 rb->lcd_putsxyf (LINES_X, LINES_Y, "%d", rockblox_status.lines);
843 #else /* HAVE_LCD_CHARCELLS */
844 rb->lcd_putsf (5, 0, "L%d/%d", rockblox_status.level,
845 rockblox_status.lines);
846 rb->lcd_putsf (5, 1, "S%d", rockblox_status.score);
847 #endif
850 #ifdef HIGH_SCORE_Y
851 static void show_highscores (void)
853 int i;
855 for (i = 0; i<NUM_SCORES; i++)
856 rb->lcd_putsxyf (HIGH_LABEL_X, HIGH_SCORE_Y + (10 * i),
857 "%06d" _SPACE "L%1d", highscores[i].score, highscores[i].level);
859 #endif
861 static void load_game(void)
863 int fd;
865 resume = false;
867 fd = rb->open(RESUME_FILE, O_RDONLY);
868 if (fd < 0) return;
870 if (rb->read(fd, &rockblox_status, sizeof(struct _rockblox_status))
871 < (ssize_t)sizeof(struct _rockblox_status))
873 rb->splash(HZ/2, "Loading Rockblox resume info failed");
874 return;
875 } else {
876 resume = true;
879 rb->close(fd);
881 return;
884 static void dump_resume(void)
886 int fd;
888 fd = rb->open(RESUME_FILE, O_WRONLY|O_CREAT, 0666);
889 if (fd < 0)
890 goto fail;
892 if (rb->write(fd, &rockblox_status, sizeof(struct _rockblox_status))
893 <= 0)
895 rb->close(fd);
896 goto fail;
898 rb->close(fd);
899 return;
901 fail:
902 rb->splash(HZ/2, "Writing Rockblox resume info failed");
903 return;
906 static void init_rockblox (bool resume)
908 char score_name[50];
909 struct tm* tm;
911 tm = rb->get_time();
912 rb->snprintf(score_name, sizeof(score_name), "%04d%02d%02d %02d%02d%02d",
913 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
914 tm->tm_hour, tm->tm_min, tm->tm_sec);
916 #ifdef HAVE_LCD_BITMAP
917 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
918 #else /* HAVE_LCD_CHARCELLS */
919 pgfx_display (0, 0);
920 pgfx_display_block (3, 0, 3, 1);
921 pgfx_display_block (4, 0, 3, 0);
922 rb->lcd_puts(4, 1, " ");
923 pgfx_clear_display();
924 pgfx_fillrect (3, 0, 2, 14);
925 pgfx_fillrect (15, 7, 2, 7);
926 pgfx_update();
927 #endif
928 if (!resume)
930 rockblox_status.level = 1;
931 rockblox_status.lines = 0;
932 rockblox_status.score = 0;
933 rockblox_status.nf = t_rand(BLOCKS_NUM);
934 init_board ();
935 new_block ();
937 draw_next_block();
939 show_details ();
940 #ifdef HIGH_SCORE_Y
941 show_highscores ();
942 #endif
945 static inline int level_speed(int level)
947 #if BOARD_HEIGHT == 20
948 return (5*HZ) / (level + 9);
949 #elif BOARD_HEIGHT == 14
950 return (7*HZ) / (level + 9);
951 #endif
954 static int getRelativeX (int figure, int square, int orientation)
956 switch (orientation) {
957 case 0:
958 return figures[figure].shapeX[square];
959 case 1:
960 return figures[figure].shapeY[square];
961 case 2:
962 return -figures[figure].shapeX[square];
963 case 3:
964 return -figures[figure].shapeY[square];
965 default:
966 return 0;
970 static int getRelativeY (int figure, int square, int orientation)
972 switch (orientation) {
973 case 0:
974 return figures[figure].shapeY[square];
975 case 1:
976 return -figures[figure].shapeX[square];
977 case 2:
978 return -figures[figure].shapeY[square];
979 case 3:
980 return figures[figure].shapeX[square];
981 default:
982 return 0;
986 /* redraw the while board on the screen */
987 static void refresh_board (void)
989 int i, j, x, y, block;
991 #if LCD_DEPTH >= 2
992 rb->lcd_set_foreground (LCD_BLACK);
993 #elif LCD_DEPTH == 1
994 mylcd_set_drawmode (DRMODE_SOLID | DRMODE_INVERSEVID);
995 #endif
997 mylcd_fillrect (BOARD_X, BOARD_Y, BOARD_WIDTH * BLOCK_WIDTH,
998 BOARD_HEIGHT * BLOCK_HEIGHT);
1000 #if LCD_DEPTH == 1
1001 mylcd_set_drawmode (DRMODE_SOLID);
1002 #endif
1004 for (i = 0; i < BOARD_WIDTH; i++)
1005 for (j = 0; j < BOARD_HEIGHT; j++) {
1006 block = rockblox_status.board[j][i];
1007 if (block != EMPTY_BLOCK) {
1008 #ifdef HAVE_LCD_BITMAP
1009 #if LCD_DEPTH >= 2
1010 /* middle drawing */
1011 rb->lcd_set_foreground (figures[block].color[1]);
1012 #endif
1013 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
1014 BOARD_Y + j * BLOCK_HEIGHT,
1015 BLOCK_WIDTH, BLOCK_HEIGHT);
1016 #if LCD_DEPTH >= 2
1017 /* light drawing */
1018 rb->lcd_set_foreground (figures[block].color[0]);
1019 #endif
1020 rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH,
1021 BOARD_Y + j * BLOCK_HEIGHT,
1022 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2);
1023 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH,
1024 BOARD_X + (i + 1) * BLOCK_WIDTH - 2,
1025 BOARD_Y + j * BLOCK_HEIGHT);
1026 #if LCD_DEPTH >= 2
1027 /* shadow drawing */
1028 rb->lcd_set_foreground (figures[block].color[2]);
1029 #endif
1030 rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
1031 BOARD_Y + j * BLOCK_HEIGHT + 1,
1032 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
1033 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1,
1034 BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
1035 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
1036 #else /* HAVE_LCD_CHARCELLS */
1037 pgfx_drawpixel (BOARD_X + i, BOARD_Y + j);
1038 #endif
1042 for (i = 0; i < 4; i++) {
1043 x = getRelativeX (rockblox_status.cf, i, rockblox_status.co)
1044 + rockblox_status.cx;
1045 y = getRelativeY (rockblox_status.cf, i, rockblox_status.co)
1046 + rockblox_status.cy;
1047 #ifdef HAVE_LCD_BITMAP
1048 #if LCD_DEPTH >= 2
1049 /* middle drawing */
1050 rb->lcd_set_foreground (figures[rockblox_status.cf].color[1]);
1051 #endif
1052 rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH,
1053 BOARD_Y + y * BLOCK_HEIGHT,
1054 BLOCK_WIDTH, BLOCK_HEIGHT);
1055 #if LCD_DEPTH >= 2
1056 /* light drawing */
1057 rb->lcd_set_foreground (figures[rockblox_status.cf].color[0]);
1058 #endif
1059 rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT,
1060 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2);
1061 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH,
1062 BOARD_X + (x + 1) * BLOCK_WIDTH - 2,
1063 BOARD_Y + y * BLOCK_HEIGHT);
1064 #if LCD_DEPTH >= 2
1065 /* shadow drawing */
1066 rb->lcd_set_foreground (figures[rockblox_status.cf].color[2]);
1067 #endif
1068 rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
1069 BOARD_Y + y * BLOCK_HEIGHT + 1,
1070 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
1071 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1,
1072 BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
1073 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
1074 #else /* HAVE_LCD_CHARCELLS */
1075 pgfx_drawpixel (BOARD_X + x, BOARD_Y + y);
1076 #endif
1078 mylcd_update ();
1081 static bool canMoveTo (int x, int y, int newOrientation)
1083 int i, rx, ry;
1084 for (i = 0; i < 4; i++) {
1085 ry = getRelativeY (rockblox_status.cf, i, newOrientation) + y;
1086 rx = getRelativeX (rockblox_status.cf, i, newOrientation) + x;
1087 if ((rx < 0 || rx >= BOARD_WIDTH) ||
1088 (ry < 0 || ry >= BOARD_HEIGHT) ||
1089 (rockblox_status.board[ry][rx] != EMPTY_BLOCK))
1090 return false;
1092 return true;
1095 /* draws the preview of next block in the preview window */
1096 static void draw_next_block (void)
1098 int i, rx, ry;
1099 /* clear preview window first */
1100 #if LCD_DEPTH >= 2
1101 rb->lcd_set_foreground (LCD_BLACK);
1102 #elif LCD_DEPTH == 1
1103 mylcd_set_drawmode (DRMODE_SOLID | DRMODE_INVERSEVID);
1104 #endif
1106 /* 4x4 */
1107 mylcd_fillrect (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4);
1109 #if LCD_DEPTH == 1
1110 mylcd_set_drawmode (DRMODE_SOLID);
1111 #endif
1113 /* draw the lightgray rectangles */
1114 #if LCD_DEPTH >= 16
1115 rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
1116 #elif LCD_DEPTH == 2
1117 rb->lcd_set_foreground (LCD_DARKGRAY);
1118 #endif
1120 #if LCD_DEPTH >= 2
1121 for (rx = 0; rx < 4; rx++)
1122 for (ry = 0; ry < 4; ry++)
1123 rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH,
1124 PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH,
1125 BLOCK_HEIGHT);
1126 #endif
1128 /* draw the figure */
1129 for (i = 0; i < 4; i++) {
1130 rx = getRelativeX (rockblox_status.nf, i, 0) + 2;
1131 ry = getRelativeY (rockblox_status.nf, i, 0) + 2;
1132 #ifdef HAVE_LCD_BITMAP
1133 #if LCD_DEPTH >= 2
1134 rb->lcd_set_foreground (figures[rockblox_status.nf].color[1]); /* middle drawing */
1135 #endif
1136 rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH,
1137 PREVIEW_Y + ry * BLOCK_HEIGHT,
1138 BLOCK_WIDTH, BLOCK_HEIGHT);
1139 #if LCD_DEPTH >= 2
1140 rb->lcd_set_foreground (figures[rockblox_status.nf].color[0]); /* light drawing */
1141 #endif
1142 rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH,
1143 PREVIEW_Y + ry * BLOCK_HEIGHT,
1144 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2);
1145 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH,
1146 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2,
1147 PREVIEW_Y + ry * BLOCK_HEIGHT);
1148 #if LCD_DEPTH >= 2
1149 rb->lcd_set_foreground (figures[rockblox_status.nf].color[2]); /* shadow drawing */
1150 #endif
1151 rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
1152 PREVIEW_Y + ry * BLOCK_HEIGHT + 1,
1153 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
1154 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1,
1155 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
1156 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
1157 #else /* HAVE_LCD_CHARCELLS */
1158 pgfx_drawpixel (PREVIEW_X + rx, PREVIEW_Y + ry);
1159 #endif
1164 /* move the block to a relative location */
1165 static void move_block (int x, int y, int o)
1167 if (canMoveTo (rockblox_status.cx + x, rockblox_status.cy + y, o)) {
1168 rockblox_status.cy += y;
1169 rockblox_status.cx += x;
1170 rockblox_status.co = o;
1174 /* try to add a new block to play with (return true if gameover) */
1175 static void new_block (void)
1177 rockblox_status.cy = 1;
1178 rockblox_status.cx = 5;
1179 rockblox_status.cf = rockblox_status.nf;
1180 rockblox_status.co = 0; /* start at the same orientation all time */
1181 rockblox_status.nf = t_rand (BLOCKS_NUM);
1182 rockblox_status.gameover = !canMoveTo (rockblox_status.cx,
1183 rockblox_status.cy, rockblox_status.co);
1185 draw_next_block ();
1189 /* check for filled rockblox_status.lines and do what necessary */
1190 static int check_lines (void)
1193 int i, j, y;
1194 int rockblox = 0;
1196 for (j = 0; j < BOARD_HEIGHT; j++) {
1197 for (i = 0; ((i < BOARD_WIDTH) &&
1198 (rockblox_status.board[j][i] != EMPTY_BLOCK)); i++);
1199 if (i == BOARD_WIDTH) { /* woo hoo, we have a line */
1200 rockblox++;
1201 for (y = j; y > 0; y--)
1203 for (i = 0; i < BOARD_WIDTH; i++)
1204 { /* fall line */
1205 rockblox_status.board[y][i] = rockblox_status.board[y - 1][i];
1211 return rockblox;
1214 /* moves down the figure and returns true if gameover */
1215 static void move_down (void)
1217 int l, i, rx, ry;
1219 if (!canMoveTo (rockblox_status.cx, rockblox_status.cy + 1, rockblox_status.co)) {
1220 /* save figure to board */
1221 for (i = 0; i < 4; i++) {
1222 rx = getRelativeX (rockblox_status.cf, i, rockblox_status.co) + rockblox_status.cx;
1223 ry = getRelativeY (rockblox_status.cf, i, rockblox_status.co) + rockblox_status.cy;
1224 rockblox_status.board[ry][rx] = rockblox_status.cf;
1226 /* check if formed some lines */
1227 l = check_lines ();
1228 if (l) {
1229 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
1230 rockblox_status.score += scoring[l - 1] * rockblox_status.level;
1231 rockblox_status.lines += l;
1232 rockblox_status.level = (int) rockblox_status.lines / 10 + 1;
1235 /* show details */
1236 show_details ();
1238 /* generate a new figure */
1239 new_block ();
1240 } else
1241 move_block (0, 1, rockblox_status.co);
1244 static bool rockblox_help(void)
1246 static char *help_text[] = {
1247 "Rockblox", "", "Aim", "",
1248 "Make", "the", "falling", "blocks", "of",
1249 "different", "shapes", "form", "full", "rows.",
1250 "Whenever", "a", "row", "is", "completed,",
1251 "it", "will", "be", "cleared", "away",
1252 "and", "you", "gain", "points."
1254 static struct style_text formation[]={
1255 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1256 { 2, C_RED },
1257 LAST_STYLE_ITEM
1260 #ifdef HAVE_LCD_BITMAP
1261 rb->lcd_setfont(FONT_UI);
1262 #endif
1263 #ifdef HAVE_LCD_COLOR
1264 rb->lcd_set_background(LCD_BLACK);
1265 rb->lcd_set_foreground(LCD_WHITE);
1266 #endif
1267 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1268 return true;
1269 #ifdef HAVE_LCD_BITMAP
1270 rb->lcd_setfont(FONT_SYSFIXED);
1271 #endif
1273 return false;
1276 static int rockblox_menu_cb(int action, const struct menu_item_ex *this_item)
1278 int i = ((intptr_t)this_item);
1279 if(action == ACTION_REQUEST_MENUITEM
1280 && !resume && (i==0 || i==5))
1281 return ACTION_EXIT_MENUITEM;
1282 return action;
1285 static int rockblox_menu(void)
1287 int selected = 0;
1289 MENUITEM_STRINGLIST(main_menu, "Rockblox Menu", rockblox_menu_cb,
1290 "Resume Game", "Start New Game",
1291 "Help", "High Scores", "Playback Control",
1292 "Quit without Saving", "Quit");
1294 rb->button_clear_queue();
1295 while (true) {
1296 switch (rb->do_menu(&main_menu, &selected, NULL, false)) {
1297 case 0:
1298 if(resume_file)
1299 rb->remove(RESUME_FILE);
1300 init_rockblox(true);
1301 return 0;
1302 case 1:
1303 init_rockblox(false);
1304 return 0;
1305 case 2:
1306 if (rockblox_help())
1307 return 1;
1308 break;
1309 case 3:
1310 highscore_show(-1, highscores, NUM_SCORES, true);
1311 break;
1312 case 4:
1313 if (playback_control(NULL))
1314 return 1;
1315 break;
1316 case 5:
1317 return 1;
1318 case 6:
1319 if (resume) {
1320 rb->splash(HZ*1, "Saving game ...");
1321 dump_resume();
1323 return 1;
1324 case MENU_ATTACHED_USB:
1325 return 1;
1326 default:
1327 return 1;
1328 break;
1334 static int rockblox_loop (void)
1336 int button;
1337 int lastbutton = BUTTON_NONE;
1338 long next_down_tick = *rb->current_tick + level_speed(rockblox_status.level);
1340 if (rockblox_menu()) {
1341 return 1;
1343 resume = false;
1344 resume_file = false;
1346 while (1) {
1347 #ifdef HAS_BUTTON_HOLD
1348 if (rb->button_hold ()) {
1349 /* Turn on backlight timeout (revert to settings) */
1350 backlight_use_settings(); /* backlight control in lib/helper.c */
1351 rb->splash(0, "Paused");
1352 while (rb->button_hold ())
1353 rb->sleep(HZ/10);
1355 /* Turn off backlight timeout */
1356 backlight_force_on(); /* backlight control in lib/helper.c */
1358 /* get rid of the splash text */
1359 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
1360 show_details ();
1361 #ifdef HIGH_SCORE_Y
1362 show_highscores ();
1363 #endif
1364 draw_next_block ();
1365 refresh_board ();
1367 #endif
1369 button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1));
1370 switch (button) {
1371 #ifdef ROCKBLOX_RC_OFF
1372 case ROCKBLOX_RC_OFF:
1373 #endif
1374 case ROCKBLOX_OFF:
1375 #ifdef ROCKBLOX_OFF_PRE
1376 if (lastbutton != ROCKBLOX_OFF_PRE)
1377 break;
1378 #endif
1379 resume = true;
1380 return 0;
1381 break;
1383 #if defined(ROCKBLOX_ROTATE)
1384 case ROCKBLOX_ROTATE:
1385 #endif
1386 case ROCKBLOX_ROTATE_CCW:
1387 case ROCKBLOX_ROTATE_CCW | BUTTON_REPEAT:
1388 #ifdef HAVE_SCROLLWHEEL
1389 /* if the wheel is disabled, add an event to the stack. */
1390 if(wheel_enabled == false)
1391 wheel_events++;
1393 /* if it's enabled, go ahead and rotate.. */
1394 if(wheel_enabled)
1395 #endif
1396 #ifdef ROCKBLOX_ROTATE_CCW2
1397 /* fallback */
1398 case ROCKBLOX_ROTATE_CCW2:
1399 #endif
1400 move_block (0, 0, (rockblox_status.co + 1) % figures[rockblox_status.cf].max_or);
1401 break;
1403 case ROCKBLOX_ROTATE_CW:
1404 case ROCKBLOX_ROTATE_CW | BUTTON_REPEAT:
1405 #ifdef HAVE_SCROLLWHEEL
1406 if(wheel_enabled == false)
1407 wheel_events++;
1409 if(wheel_enabled)
1410 #endif
1411 #ifdef ROCKBLOX_ROTATE_CW2
1412 /* fallback */
1413 case ROCKBLOX_ROTATE_CW2:
1414 #endif
1415 move_block (0, 0,
1416 (rockblox_status.co + figures[rockblox_status.cf].max_or -
1417 1) % figures[rockblox_status.cf].max_or);
1418 break;
1420 case ROCKBLOX_DOWN:
1421 case ROCKBLOX_DOWN | BUTTON_REPEAT:
1422 move_block (0, 1, rockblox_status.co);
1423 break;
1425 case ROCKBLOX_RIGHT:
1426 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
1427 move_block (1, 0, rockblox_status.co);
1428 break;
1430 case ROCKBLOX_LEFT:
1431 case ROCKBLOX_LEFT | BUTTON_REPEAT:
1432 move_block (-1, 0, rockblox_status.co);
1433 break;
1435 case ROCKBLOX_DROP:
1436 #ifdef ROCKBLOX_DROP_PRE
1437 if (lastbutton != ROCKBLOX_DROP_PRE)
1438 break;
1439 #endif
1440 while (canMoveTo (rockblox_status.cx, rockblox_status.cy + 1, rockblox_status.co))
1441 move_block (0, 1, rockblox_status.co);
1442 break;
1443 #ifdef ROCKBLOX_RESTART
1444 case ROCKBLOX_RESTART:
1445 rb->splash (HZ * 1, "Restarting...");
1446 init_rockblox (false);
1447 break;
1448 #endif
1450 default:
1451 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
1452 return PLUGIN_USB_CONNECTED;
1453 break;
1455 if (button != BUTTON_NONE)
1456 lastbutton = button;
1458 #ifdef HAVE_SCROLLWHEEL
1459 /* check if we should enable the scroll wheel, if events
1460 * begin to stack up... */
1461 if(wheel_enabled == false)
1463 /* stopped rotating the wheel, reset the count */
1464 if(wheel_events == last_wheel_event)
1466 last_wheel_event = 0;
1467 wheel_events = 0;
1469 /* rotated the wheel a while constantly, enable it. */
1470 else if(wheel_events > 3)
1472 wheel_enabled = true;
1475 /* this evens out the last event and the "current" event.
1476 * if we get an event next time through button reading, it will
1477 * remain ahead of last_event. if we don't, they'll end up equaling
1478 * each other.. thus, the scroll count will be reset. */
1479 if(wheel_enabled == false && wheel_events > last_wheel_event)
1480 last_wheel_event++;
1482 #endif
1484 if (TIME_AFTER(*rb->current_tick, next_down_tick)) {
1485 move_down ();
1486 next_down_tick += level_speed(rockblox_status.level);
1487 if (TIME_AFTER(*rb->current_tick, next_down_tick))
1488 /* restart time "raster" when we had to wait longer than usual
1489 * (pause, game restart etc) */
1490 next_down_tick = *rb->current_tick + level_speed(rockblox_status.level);
1493 if (rockblox_status.gameover) {
1494 #if LCD_DEPTH >= 2
1495 rb->lcd_set_foreground (LCD_BLACK);
1496 #endif
1497 show_game_over();
1498 resume = false;
1499 return 0;
1502 refresh_board ();
1505 return 0;
1508 enum plugin_status plugin_start (const void *parameter)
1511 (void) parameter;
1513 rb->srand (*rb->current_tick);
1515 /* Load HighScore if any */
1516 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1518 #if LCD_DEPTH > 1
1519 rb->lcd_set_backdrop(NULL);
1520 #endif
1522 #ifdef HAVE_LCD_BITMAP
1523 rb->lcd_setfont (FONT_SYSFIXED);
1524 #else
1525 if (!pgfx_init(4, 2))
1527 rb->splash(HZ*2, "Old LCD :(");
1528 return PLUGIN_OK;
1530 #endif
1531 /* Turn off backlight timeout */
1532 backlight_force_on(); /* backlight control in lib/helper.c */
1533 load_game();
1534 resume_file = resume;
1535 while(!rockblox_loop()) {
1536 if(!resume) {
1537 int position = highscore_update(rockblox_status.score,
1538 rockblox_status.level, "",
1539 highscores, NUM_SCORES);
1540 if (position != -1) {
1541 if (position == 0)
1542 rb->splash(HZ*2, "New High Score");
1543 highscore_show(position, highscores, NUM_SCORES, true);
1548 #ifndef HAVE_LCD_BITMAP
1549 pgfx_release();
1550 #endif
1551 /* Save user's HighScore */
1552 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1553 backlight_use_settings(); /* backlight control in lib/helper.c */
1555 return PLUGIN_OK;