Make open() posix compliant api-wise. A few calls (those with O_CREAT) need the addit...
[kugel-rb.git] / apps / plugins / rockblox.c
blob4e261e454761708b5ee4e8d9298f7958ca2d9d0f
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 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
330 #define ROCKBLOX_OFF (BUTTON_REC|BUTTON_PLAY)
331 #define ROCKBLOX_ROTATE_CCW BUTTON_PREV
332 #define ROCKBLOX_ROTATE_CW BUTTON_NEXT
333 #define ROCKBLOX_DOWN BUTTON_SELECT
334 #define ROCKBLOX_LEFT BUTTON_VOL_DOWN
335 #define ROCKBLOX_RIGHT BUTTON_VOL_UP
336 #define ROCKBLOX_DROP BUTTON_PLAY
337 #define ROCKBLOX_RESTART BUTTON_REC
339 #else
340 #error No keymap defined!
341 #endif
343 #ifdef HAVE_TOUCHSCREEN
344 #ifndef ROCKBLOX_OFF
345 #define ROCKBLOX_OFF BUTTON_TOPLEFT
346 #endif
347 #ifdef ROCKBLOX_ROTATE_CCW
348 #define ROCKBLOX_ROTATE_CCW2 BUTTON_BOTTOMLEFT
349 #else
350 #define ROCKBLOX_ROTATE_CCW BUTTON_BOTTOMLEFT
351 #endif
352 #ifdef ROCKBLOX_ROTATE_CW
353 #define ROCKBLOX_ROTATE_CW2 BUTTON_BOTTOMRIGHT
354 #else
355 #define ROCKBLOX_ROTATE_CW BUTTON_BOTTOMRIGHT
356 #define ROCKBLOX_ROTATE_CW2 BUTTON_TOPMIDDLE
357 #endif
358 #ifndef ROCKBLOX_DOWN
359 #define ROCKBLOX_DOWN BUTTON_BOTTOMMIDDLE
360 #endif
361 #ifndef ROCKBLOX_LEFT
362 #define ROCKBLOX_LEFT BUTTON_MIDLEFT
363 #endif
364 #ifndef ROCKBLOX_RIGHT
365 #define ROCKBLOX_RIGHT BUTTON_MIDRIGHT
366 #endif
367 #ifndef ROCKBLOX_DROP
368 #define ROCKBLOX_DROP BUTTON_CENTER
369 #endif
370 #ifndef ROCKBLOX_RESTART
371 #define ROCKBLOX_RESTART BUTTON_TOPRIGHT
372 #endif
373 #endif
375 #define BLOCKS_NUM 7
376 #define EMPTY_BLOCK 7
378 #define BOARD_WIDTH 10
380 #ifdef HAVE_LCD_BITMAP
382 #define BOARD_HEIGHT 20
384 #if (LCD_WIDTH == 640) && (LCD_HEIGHT == 480)
386 #define BLOCK_WIDTH 24
387 #define BLOCK_HEIGHT 24
388 #define BOARD_X 172
389 #define BOARD_Y 0
390 #define PREVIEW_X 24
391 #define PREVIEW_Y 22
392 #define LABEL_X 482
393 #define SCORE_Y 50
394 #define LEVEL_Y 140
395 #define LINES_Y 210
397 #elif (LCD_WIDTH == 480) && (LCD_HEIGHT == 640)
399 #define BLOCK_WIDTH 30
400 #define BLOCK_HEIGHT 30
401 #define BOARD_X 14
402 #define BOARD_Y 2
403 #define PREVIEW_X 342
404 #define PREVIEW_Y 482
405 #define LABEL_X 344
406 #define SCORE_Y 58
407 #define LEVEL_Y 142
408 #define LINES_Y 218
410 #elif (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
412 #define BLOCK_WIDTH 12
413 #define BLOCK_HEIGHT 12
414 #define BOARD_X 86
415 #define BOARD_Y 0
416 #define PREVIEW_X 12
417 #define PREVIEW_Y 11
418 #define LABEL_X 242
419 #define SCORE_Y 25
420 #define LEVEL_Y 70
421 #define LINES_Y 105
423 #elif (LCD_WIDTH == 240) && ((LCD_HEIGHT == 320) || (LCD_HEIGHT == 400))
425 #define BLOCK_WIDTH 15
426 #define BLOCK_HEIGHT 15
427 #define BOARD_X 7
428 #define BOARD_Y 1
429 #define PREVIEW_X 171
430 #define PREVIEW_Y 241
431 #define LABEL_X 172
432 #define SCORE_Y 29
433 #define LEVEL_Y 71
434 #define LINES_Y 109
435 #define HIGH_LABEL_X 172
436 #define HIGH_SCORE_Y 163
437 #define HIGH_LEVEL_Y 172
439 #elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
441 #define BLOCK_WIDTH 8
442 #define BLOCK_HEIGHT 8
443 #define BOARD_X 27
444 #define BOARD_Y 5
445 #define PREVIEW_X 158
446 #define PREVIEW_Y 130
447 #define LABEL_X 147
448 #define SCORE_Y 20
449 #define LEVEL_Y 65
450 #define LINES_Y 100
452 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
454 #define BLOCK_WIDTH 6
455 #define BLOCK_HEIGHT 6
456 #define BOARD_X 25
457 #define BOARD_Y 1
458 #define PREVIEW_X 126
459 #define PREVIEW_Y 102
460 #define LABEL_X 112
461 #define SCORE_Y 17
462 #define LEVEL_Y 49
463 #define LINES_Y 81
465 #elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 220)
467 /* no room for the space in the highscore list */
468 #define _SPACE ""
470 #define BLOCK_WIDTH 10
471 #define BLOCK_HEIGHT 10
472 #define BOARD_X 6
473 #define BOARD_Y 10
474 #define PREVIEW_X 124
475 #define PREVIEW_Y 174
476 #define LABEL_X 117
477 #define SCORE_Y 18
478 #define LEVEL_Y 52
479 #define LINES_Y 85
480 #define HIGH_SCORE_Y 119
481 #define HIGH_LEVEL_Y 126
482 #define HIGH_LABEL_X 114
484 #elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
487 #define BLOCK_WIDTH 6
488 #define BLOCK_HEIGHT 6
489 #define BOARD_X 22
490 #define BOARD_Y 3
491 #define PREVIEW_X 114
492 #define PREVIEW_Y 100
493 #define LABEL_X 101
494 #define SCORE_Y 17
495 #define LEVEL_Y 49
496 #define LINES_Y 82
498 #elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
500 #define BLOCK_WIDTH 5
501 #define BLOCK_HEIGHT 5
502 #define BOARD_X 14
503 #define BOARD_Y 0
504 #define PREVIEW_X 98
505 #define PREVIEW_Y 88
506 #define LABEL_X 80
507 #define SCORE_Y 15
508 #define LEVEL_Y 45
509 #define LINES_Y 74
511 #elif (LCD_WIDTH == 132) && (LCD_HEIGHT == 80)
513 #define BLOCK_WIDTH 4
514 #define BLOCK_HEIGHT 4
515 #define BOARD_X 10
516 #define BOARD_Y 0
517 #define PREVIEW_X 89
518 #define PREVIEW_Y 61
519 #define LABEL_X 78
520 #define SCORE_Y 10
521 #define LEVEL_Y 30
522 #define LINES_Y 50
524 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
526 #define BLOCK_WIDTH 6
527 #define BLOCK_HEIGHT 6
528 #define BOARD_X 4
529 #define BOARD_Y 3
530 #define PREVIEW_X 84
531 #define PREVIEW_Y 100
532 #define LABEL_X 71
533 #define SCORE_Y 17
534 #define LEVEL_Y 49
535 #define LINES_Y 82
537 /* NOTE: This is for the GoGear SA9200 and is only
538 temporary until I can get better coordinates! */
539 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 160)
541 #define BLOCK_WIDTH 6
542 #define BLOCK_HEIGHT 6
543 #define BOARD_X 4
544 #define BOARD_Y 3
545 #define PREVIEW_X 84
546 #define PREVIEW_Y 100
547 #define LABEL_X 71
548 #define SCORE_Y 17
549 #define LEVEL_Y 49
550 #define LINES_Y 82
552 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 96)
554 #define BLOCK_WIDTH 4
555 #define BLOCK_HEIGHT 4
556 #define BOARD_X 14
557 #define BOARD_Y 2
558 #define PREVIEW_X 89
559 #define PREVIEW_Y 76
560 #define LABEL_X 70
561 #define SCORE_Y 14
562 #define LEVEL_Y 39
563 #define LINES_Y 64
565 #elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 64)
567 #define BLOCK_WIDTH 3
568 #define BLOCK_HEIGHT 3
569 #define BOARD_X 9
570 #define BOARD_Y 3
571 #define PREVIEW_X 53
572 #define PREVIEW_Y 5
573 #define LABEL_X 70
574 #define SCORE_Y 32
575 #define LEVEL_Y 13
576 #define LINES_Y 51
578 #elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
580 #define BLOCK_WIDTH 4
581 #define BLOCK_HEIGHT 3
582 #define BOARD_X 9
583 #define BOARD_Y 3
584 #define PREVIEW_X 59
585 #define PREVIEW_Y 5
586 #define LABEL_X 59
587 #define SCORE_Y 32
588 #define LEVEL_Y 13
589 #define LEVEL_X 78
590 #define LINES_Y 51
592 #endif
594 #ifndef LEVEL_X
595 #define LEVEL_X LABEL_X
596 #endif
598 #ifndef LINES_X
599 #define LINES_X LABEL_X
600 #endif
602 #define MYLCD(fn) rb->lcd_ ## fn
604 extern const fb_data rockblox_background[];
606 #else /* HAVE_LCD_CHARCELLS */
608 #define BOARD_HEIGHT 14
610 #define BLOCK_WIDTH 1
611 #define BLOCK_HEIGHT 1
612 #define BOARD_X 5
613 #define BOARD_Y 0
614 #define PREVIEW_X 15
615 #define PREVIEW_Y 1
617 #define MYLCD(fn) pgfx_ ## fn
619 #endif
621 #ifndef _SPACE
622 #define _SPACE " "
623 #endif
624 /* <<Explanation on Rockblox shapes>>
627 %% - O has 1 orientation
629 %% %
630 %% %% - Z has 2 orientations
633 %% %
634 %% %% - S has 2 orientations
638 % %%%% - I has 2 orientations
641 % %%
642 % % % %%% - L has 4 orientations
643 %% %%% % %
645 % %%
646 % % % %%% - J has 4 orientations
647 %% %%% % %
649 % % %%%
650 %% % %% % - T has 4 orientations
651 % %%% %
654 /* c=current f=figure o=orientation n=next */
655 static struct _rockblox_status
657 int gameover;
658 int lines;
659 int level;
660 int score;
661 int cx;
662 int cy;
663 int cf;
664 int co;
665 int nf;
666 short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */
667 } rockblox_status;
669 /* prototypes */
670 static void draw_next_block(void);
671 static void new_block(void);
673 #ifdef HAVE_SCROLLWHEEL
674 int wheel_events = 0, last_wheel_event = 0;
675 bool wheel_enabled = false;
676 #endif
678 static const short scoring[4] = { /* scoring for each number of lines */
679 #if BOARD_HEIGHT == 20
680 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
681 #elif BOARD_HEIGHT == 14 /* Player special values */
682 60 /* single */ , 150 /* double */ , 500 /* triple */ , 2000 /* rockblox */
683 #endif
686 struct figure
688 #if LCD_DEPTH >= 2
689 unsigned short color[3]; /* color of figure (light,middle,shadow) */
690 #endif
691 unsigned short max_or; /* max orientations */
692 signed short shapeX[4], shapeY[4]; /* implementation of figures */
695 /* array of figures */
696 figures[BLOCKS_NUM] = {
697 /* O */
699 #if LCD_DEPTH >= 16
700 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
701 LCD_RGBPACK(0,153,153)},
702 #elif LCD_DEPTH == 2
703 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
704 #endif
706 {-1, 0, -1, 0},
707 {0, 0, 1, 1}
709 /* I */
711 #if LCD_DEPTH >= 16
712 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
713 LCD_RGBPACK (153, 0, 0)},
714 #elif LCD_DEPTH == 2
715 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
716 #endif
718 {-2, -1, 0, 1},
719 {0, 0, 0, 0}
721 /* 'Z' */
723 #if LCD_DEPTH >= 16
724 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
725 LCD_RGBPACK (0, 153, 0)},
726 #elif LCD_DEPTH == 2
727 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
728 #endif
730 {0, 1, -1, 0},
731 {0, 0, 1, 1}
733 /* 'S' */
735 #if LCD_DEPTH >= 16
736 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
737 LCD_RGBPACK (0, 0, 153)},
738 #elif LCD_DEPTH == 2
739 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
740 #endif
742 {-1, 0, 0, 1},
743 {0, 0, 1, 1}
745 /* 'L' */
747 #if LCD_DEPTH >= 16
748 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
749 LCD_RGBPACK (153, 153, 0)},
750 #elif LCD_DEPTH == 2
751 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
752 #endif
754 {-1, 0, 1, 1},
755 {0, 0, 0, 1}
757 /* 'J' */
759 #if LCD_DEPTH >= 16
760 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
761 LCD_RGBPACK (153, 0, 153)},
762 #elif LCD_DEPTH == 2
763 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
764 #endif
766 {-1, 0, 1, -1},
767 {0, 0, 0, 1}
769 /* 'T' */
771 #if LCD_DEPTH >= 16
772 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
773 LCD_RGBPACK (85, 85, 85)},
774 #elif LCD_DEPTH == 2
775 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
776 #endif
778 {-1, 0, 1, 0},
779 {0, 0, 0, 1}
782 bool resume = false;
783 bool resume_file = false;
785 /* Rockbox File System only supports full filenames inc dir */
786 #define SCORE_FILE PLUGIN_GAMES_DIR "/rockblox.score"
787 #define RESUME_FILE PLUGIN_GAMES_DIR "/rockblox.resume"
788 #define NUM_SCORES 5
790 /* Default High Scores... */
791 struct highscore highscores[NUM_SCORES];
793 /* get random number from (0) to (range-1) */
794 static int t_rand (int range)
796 return rb->rand () % range;
799 static inline void show_game_over (void)
801 rb->splash(HZ,"Game over!");
804 /* init the board array to have no blocks */
805 static void init_board (void)
807 int i, j;
808 for (i = 0; i < BOARD_WIDTH; i++)
809 for (j = 0; j < BOARD_HEIGHT; j++)
810 rockblox_status.board[j][i] = EMPTY_BLOCK;
813 /* show the score, level and lines */
814 static void show_details (void)
816 char str[25]; /* for strings */
818 #ifdef HAVE_LCD_BITMAP
819 #if LCD_DEPTH >= 2
820 rb->lcd_set_foreground (LCD_BLACK);
821 rb->lcd_set_background (LCD_WHITE);
822 #endif
823 rb->snprintf (str, sizeof (str), "%d", rockblox_status.score);
824 rb->lcd_putsxy (LABEL_X, SCORE_Y, str);
825 rb->snprintf (str, sizeof (str), "%d", rockblox_status.level);
826 rb->lcd_putsxy (LEVEL_X, LEVEL_Y, str);
827 rb->snprintf (str, sizeof (str), "%d", rockblox_status.lines);
828 rb->lcd_putsxy (LINES_X, LINES_Y, str);
829 #else /* HAVE_LCD_CHARCELLS */
830 rb->snprintf (str, sizeof (str), "L%d/%d", rockblox_status.level,
831 rockblox_status.lines);
832 rb->lcd_puts (5, 0, str);
833 rb->snprintf (str, sizeof (str), "S%d", rockblox_status.score);
834 rb->lcd_puts (5, 1, str);
835 #endif
838 #ifdef HIGH_SCORE_Y
839 static void show_highscores (void)
841 int i;
842 char str[25]; /* for strings */
844 for (i = 0; i<NUM_SCORES; i++)
846 rb->snprintf (str, sizeof (str), "%06d" _SPACE "L%1d",
847 highscores[i].score, highscores[i].level);
848 rb->lcd_putsxy (HIGH_LABEL_X, HIGH_SCORE_Y + (10 * i), str);
851 #endif
853 static void load_game(void)
855 int fd;
857 resume = false;
859 fd = rb->open(RESUME_FILE, O_RDONLY);
860 if (fd < 0) return;
862 if (rb->read(fd, &rockblox_status, sizeof(struct _rockblox_status))
863 < (ssize_t)sizeof(struct _rockblox_status))
865 rb->splash(HZ/2, "Loading Rockblox resume info failed");
866 return;
867 } else {
868 resume = true;
871 rb->close(fd);
873 return;
876 static void dump_resume(void)
878 int fd;
880 fd = rb->open(RESUME_FILE, O_WRONLY|O_CREAT, 0666);
881 if (fd < 0)
882 goto fail;
884 if (rb->write(fd, &rockblox_status, sizeof(struct _rockblox_status))
885 <= 0)
887 rb->close(fd);
888 goto fail;
890 rb->close(fd);
891 return;
893 fail:
894 rb->splash(HZ/2, "Writing Rockblox resume info failed");
895 return;
898 static void init_rockblox (bool resume)
900 char score_name[50];
901 struct tm* tm;
903 tm = rb->get_time();
904 rb->snprintf(score_name, sizeof(score_name), "%04d%02d%02d %02d%02d%02d",
905 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
906 tm->tm_hour, tm->tm_min, tm->tm_sec);
908 #ifdef HAVE_LCD_BITMAP
909 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
910 #else /* HAVE_LCD_CHARCELLS */
911 pgfx_display (0, 0);
912 pgfx_display_block (3, 0, 3, 1);
913 pgfx_display_block (4, 0, 3, 0);
914 rb->lcd_puts(4, 1, " ");
915 pgfx_clear_display();
916 pgfx_fillrect (3, 0, 2, 14);
917 pgfx_fillrect (15, 7, 2, 7);
918 pgfx_update();
919 #endif
920 if (!resume)
922 rockblox_status.level = 1;
923 rockblox_status.lines = 0;
924 rockblox_status.score = 0;
925 rockblox_status.nf = t_rand(BLOCKS_NUM);
926 init_board ();
927 new_block ();
929 draw_next_block();
931 show_details ();
932 #ifdef HIGH_SCORE_Y
933 show_highscores ();
934 #endif
937 static inline int level_speed(int level)
939 #if BOARD_HEIGHT == 20
940 return (5*HZ) / (level + 9);
941 #elif BOARD_HEIGHT == 14
942 return (7*HZ) / (level + 9);
943 #endif
946 static int getRelativeX (int figure, int square, int orientation)
948 switch (orientation) {
949 case 0:
950 return figures[figure].shapeX[square];
951 case 1:
952 return figures[figure].shapeY[square];
953 case 2:
954 return -figures[figure].shapeX[square];
955 case 3:
956 return -figures[figure].shapeY[square];
957 default:
958 return 0;
962 static int getRelativeY (int figure, int square, int orientation)
964 switch (orientation) {
965 case 0:
966 return figures[figure].shapeY[square];
967 case 1:
968 return -figures[figure].shapeX[square];
969 case 2:
970 return -figures[figure].shapeY[square];
971 case 3:
972 return figures[figure].shapeX[square];
973 default:
974 return 0;
978 /* redraw the while board on the screen */
979 static void refresh_board (void)
981 int i, j, x, y, block;
983 #if LCD_DEPTH >= 2
984 rb->lcd_set_foreground (LCD_BLACK);
985 #elif LCD_DEPTH == 1
986 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
987 #endif
989 MYLCD(fillrect) (BOARD_X, BOARD_Y, BOARD_WIDTH * BLOCK_WIDTH,
990 BOARD_HEIGHT * BLOCK_HEIGHT);
992 #if LCD_DEPTH == 1
993 MYLCD(set_drawmode) (DRMODE_SOLID);
994 #endif
996 for (i = 0; i < BOARD_WIDTH; i++)
997 for (j = 0; j < BOARD_HEIGHT; j++) {
998 block = rockblox_status.board[j][i];
999 if (block != EMPTY_BLOCK) {
1000 #ifdef HAVE_LCD_BITMAP
1001 #if LCD_DEPTH >= 2
1002 /* middle drawing */
1003 rb->lcd_set_foreground (figures[block].color[1]);
1004 #endif
1005 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
1006 BOARD_Y + j * BLOCK_HEIGHT,
1007 BLOCK_WIDTH, BLOCK_HEIGHT);
1008 #if LCD_DEPTH >= 2
1009 /* light drawing */
1010 rb->lcd_set_foreground (figures[block].color[0]);
1011 #endif
1012 rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH,
1013 BOARD_Y + j * BLOCK_HEIGHT,
1014 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2);
1015 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH,
1016 BOARD_X + (i + 1) * BLOCK_WIDTH - 2,
1017 BOARD_Y + j * BLOCK_HEIGHT);
1018 #if LCD_DEPTH >= 2
1019 /* shadow drawing */
1020 rb->lcd_set_foreground (figures[block].color[2]);
1021 #endif
1022 rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
1023 BOARD_Y + j * BLOCK_HEIGHT + 1,
1024 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
1025 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1,
1026 BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
1027 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
1028 #else /* HAVE_LCD_CHARCELLS */
1029 pgfx_drawpixel (BOARD_X + i, BOARD_Y + j);
1030 #endif
1034 for (i = 0; i < 4; i++) {
1035 x = getRelativeX (rockblox_status.cf, i, rockblox_status.co)
1036 + rockblox_status.cx;
1037 y = getRelativeY (rockblox_status.cf, i, rockblox_status.co)
1038 + rockblox_status.cy;
1039 #ifdef HAVE_LCD_BITMAP
1040 #if LCD_DEPTH >= 2
1041 /* middle drawing */
1042 rb->lcd_set_foreground (figures[rockblox_status.cf].color[1]);
1043 #endif
1044 rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH,
1045 BOARD_Y + y * BLOCK_HEIGHT,
1046 BLOCK_WIDTH, BLOCK_HEIGHT);
1047 #if LCD_DEPTH >= 2
1048 /* light drawing */
1049 rb->lcd_set_foreground (figures[rockblox_status.cf].color[0]);
1050 #endif
1051 rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT,
1052 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2);
1053 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH,
1054 BOARD_X + (x + 1) * BLOCK_WIDTH - 2,
1055 BOARD_Y + y * BLOCK_HEIGHT);
1056 #if LCD_DEPTH >= 2
1057 /* shadow drawing */
1058 rb->lcd_set_foreground (figures[rockblox_status.cf].color[2]);
1059 #endif
1060 rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
1061 BOARD_Y + y * BLOCK_HEIGHT + 1,
1062 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
1063 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1,
1064 BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
1065 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
1066 #else /* HAVE_LCD_CHARCELLS */
1067 pgfx_drawpixel (BOARD_X + x, BOARD_Y + y);
1068 #endif
1070 MYLCD(update) ();
1073 static bool canMoveTo (int x, int y, int newOrientation)
1075 int i, rx, ry;
1076 for (i = 0; i < 4; i++) {
1077 ry = getRelativeY (rockblox_status.cf, i, newOrientation) + y;
1078 rx = getRelativeX (rockblox_status.cf, i, newOrientation) + x;
1079 if ((rx < 0 || rx >= BOARD_WIDTH) ||
1080 (ry < 0 || ry >= BOARD_HEIGHT) ||
1081 (rockblox_status.board[ry][rx] != EMPTY_BLOCK))
1082 return false;
1084 return true;
1087 /* draws the preview of next block in the preview window */
1088 static void draw_next_block (void)
1090 int i, rx, ry;
1091 /* clear preview window first */
1092 #if LCD_DEPTH >= 2
1093 rb->lcd_set_foreground (LCD_BLACK);
1094 #elif LCD_DEPTH == 1
1095 MYLCD(set_drawmode) (DRMODE_SOLID | DRMODE_INVERSEVID);
1096 #endif
1098 /* 4x4 */
1099 MYLCD(fillrect) (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4);
1101 #if LCD_DEPTH == 1
1102 MYLCD(set_drawmode) (DRMODE_SOLID);
1103 #endif
1105 /* draw the lightgray rectangles */
1106 #if LCD_DEPTH >= 16
1107 rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
1108 #elif LCD_DEPTH == 2
1109 rb->lcd_set_foreground (LCD_DARKGRAY);
1110 #endif
1112 #if LCD_DEPTH >= 2
1113 for (rx = 0; rx < 4; rx++)
1114 for (ry = 0; ry < 4; ry++)
1115 rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH,
1116 PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH,
1117 BLOCK_HEIGHT);
1118 #endif
1120 /* draw the figure */
1121 for (i = 0; i < 4; i++) {
1122 rx = getRelativeX (rockblox_status.nf, i, 0) + 2;
1123 ry = getRelativeY (rockblox_status.nf, i, 0) + 2;
1124 #ifdef HAVE_LCD_BITMAP
1125 #if LCD_DEPTH >= 2
1126 rb->lcd_set_foreground (figures[rockblox_status.nf].color[1]); /* middle drawing */
1127 #endif
1128 rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH,
1129 PREVIEW_Y + ry * BLOCK_HEIGHT,
1130 BLOCK_WIDTH, BLOCK_HEIGHT);
1131 #if LCD_DEPTH >= 2
1132 rb->lcd_set_foreground (figures[rockblox_status.nf].color[0]); /* light drawing */
1133 #endif
1134 rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH,
1135 PREVIEW_Y + ry * BLOCK_HEIGHT,
1136 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2);
1137 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH,
1138 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2,
1139 PREVIEW_Y + ry * BLOCK_HEIGHT);
1140 #if LCD_DEPTH >= 2
1141 rb->lcd_set_foreground (figures[rockblox_status.nf].color[2]); /* shadow drawing */
1142 #endif
1143 rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
1144 PREVIEW_Y + ry * BLOCK_HEIGHT + 1,
1145 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
1146 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1,
1147 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
1148 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
1149 #else /* HAVE_LCD_CHARCELLS */
1150 pgfx_drawpixel (PREVIEW_X + rx, PREVIEW_Y + ry);
1151 #endif
1156 /* move the block to a relative location */
1157 static void move_block (int x, int y, int o)
1159 if (canMoveTo (rockblox_status.cx + x, rockblox_status.cy + y, o)) {
1160 rockblox_status.cy += y;
1161 rockblox_status.cx += x;
1162 rockblox_status.co = o;
1166 /* try to add a new block to play with (return true if gameover) */
1167 static void new_block (void)
1169 rockblox_status.cy = 1;
1170 rockblox_status.cx = 5;
1171 rockblox_status.cf = rockblox_status.nf;
1172 rockblox_status.co = 0; /* start at the same orientation all time */
1173 rockblox_status.nf = t_rand (BLOCKS_NUM);
1174 rockblox_status.gameover = !canMoveTo (rockblox_status.cx,
1175 rockblox_status.cy, rockblox_status.co);
1177 draw_next_block ();
1181 /* check for filled rockblox_status.lines and do what necessary */
1182 static int check_lines (void)
1185 int i, j, y;
1186 int rockblox = 0;
1188 for (j = 0; j < BOARD_HEIGHT; j++) {
1189 for (i = 0; ((i < BOARD_WIDTH) &&
1190 (rockblox_status.board[j][i] != EMPTY_BLOCK)); i++);
1191 if (i == BOARD_WIDTH) { /* woo hoo, we have a line */
1192 rockblox++;
1193 for (y = j; y > 0; y--)
1195 for (i = 0; i < BOARD_WIDTH; i++)
1196 { /* fall line */
1197 rockblox_status.board[y][i] = rockblox_status.board[y - 1][i];
1203 return rockblox;
1206 /* moves down the figure and returns true if gameover */
1207 static void move_down (void)
1209 int l, i, rx, ry;
1211 if (!canMoveTo (rockblox_status.cx, rockblox_status.cy + 1, rockblox_status.co)) {
1212 /* save figure to board */
1213 for (i = 0; i < 4; i++) {
1214 rx = getRelativeX (rockblox_status.cf, i, rockblox_status.co) + rockblox_status.cx;
1215 ry = getRelativeY (rockblox_status.cf, i, rockblox_status.co) + rockblox_status.cy;
1216 rockblox_status.board[ry][rx] = rockblox_status.cf;
1218 /* check if formed some lines */
1219 l = check_lines ();
1220 if (l) {
1221 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
1222 rockblox_status.score += scoring[l - 1] * rockblox_status.level;
1223 rockblox_status.lines += l;
1224 rockblox_status.level = (int) rockblox_status.lines / 10 + 1;
1227 /* show details */
1228 show_details ();
1230 /* generate a new figure */
1231 new_block ();
1232 } else
1233 move_block (0, 1, rockblox_status.co);
1236 static bool rockblox_help(void)
1238 static char *help_text[] = {
1239 "Rockblox", "", "Aim", "",
1240 "Make", "the", "falling", "blocks", "of",
1241 "different", "shapes", "form", "full", "rows.",
1242 "Whenever", "a", "row", "is", "completed,",
1243 "it", "will", "be", "cleared", "away",
1244 "and", "you", "gain", "points."
1246 static struct style_text formation[]={
1247 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1248 { 2, C_RED },
1249 LAST_STYLE_ITEM
1252 #ifdef HAVE_LCD_BITMAP
1253 rb->lcd_setfont(FONT_UI);
1254 #endif
1255 #ifdef HAVE_LCD_COLOR
1256 rb->lcd_set_background(LCD_BLACK);
1257 rb->lcd_set_foreground(LCD_WHITE);
1258 #endif
1259 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1260 return true;
1261 #ifdef HAVE_LCD_BITMAP
1262 rb->lcd_setfont(FONT_SYSFIXED);
1263 #endif
1265 return false;
1268 static int rockblox_menu_cb(int action, const struct menu_item_ex *this_item)
1270 int i = ((intptr_t)this_item);
1271 if(action == ACTION_REQUEST_MENUITEM
1272 && !resume && (i==0 || i==5))
1273 return ACTION_EXIT_MENUITEM;
1274 return action;
1277 static int rockblox_menu(void)
1279 int selected = 0;
1281 MENUITEM_STRINGLIST(main_menu, "Rockblox Menu", rockblox_menu_cb,
1282 "Resume Game", "Start New Game",
1283 "Help", "High Scores", "Playback Control",
1284 "Quit without Saving", "Quit");
1286 rb->button_clear_queue();
1287 while (true) {
1288 switch (rb->do_menu(&main_menu, &selected, NULL, false)) {
1289 case 0:
1290 if(resume_file)
1291 rb->remove(RESUME_FILE);
1292 init_rockblox(true);
1293 return 0;
1294 case 1:
1295 init_rockblox(false);
1296 return 0;
1297 case 2:
1298 if (rockblox_help())
1299 return 1;
1300 break;
1301 case 3:
1302 highscore_show(-1, highscores, NUM_SCORES, true);
1303 break;
1304 case 4:
1305 if (playback_control(NULL))
1306 return 1;
1307 break;
1308 case 5:
1309 return 1;
1310 case 6:
1311 if (resume) {
1312 rb->splash(HZ*1, "Saving game ...");
1313 dump_resume();
1315 return 1;
1316 case MENU_ATTACHED_USB:
1317 return 1;
1318 default:
1319 return 1;
1320 break;
1326 static int rockblox_loop (void)
1328 int button;
1329 int lastbutton = BUTTON_NONE;
1330 long next_down_tick = *rb->current_tick + level_speed(rockblox_status.level);
1332 if (rockblox_menu()) {
1333 return 1;
1335 resume = false;
1336 resume_file = false;
1338 while (1) {
1339 #ifdef HAS_BUTTON_HOLD
1340 if (rb->button_hold ()) {
1341 /* Turn on backlight timeout (revert to settings) */
1342 backlight_use_settings(); /* backlight control in lib/helper.c */
1343 rb->splash(0, "Paused");
1344 while (rb->button_hold ())
1345 rb->sleep(HZ/10);
1347 /* Turn off backlight timeout */
1348 backlight_force_on(); /* backlight control in lib/helper.c */
1350 /* get rid of the splash text */
1351 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
1352 show_details ();
1353 #ifdef HIGH_SCORE_Y
1354 show_highscores ();
1355 #endif
1356 draw_next_block ();
1357 refresh_board ();
1359 #endif
1361 button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1));
1362 switch (button) {
1363 #ifdef ROCKBLOX_RC_OFF
1364 case ROCKBLOX_RC_OFF:
1365 #endif
1366 case ROCKBLOX_OFF:
1367 #ifdef ROCKBLOX_OFF_PRE
1368 if (lastbutton != ROCKBLOX_OFF_PRE)
1369 break;
1370 #endif
1371 resume = true;
1372 return 0;
1373 break;
1375 #if defined(ROCKBLOX_ROTATE)
1376 case ROCKBLOX_ROTATE:
1377 #endif
1378 case ROCKBLOX_ROTATE_CCW:
1379 case ROCKBLOX_ROTATE_CCW | BUTTON_REPEAT:
1380 #ifdef HAVE_SCROLLWHEEL
1381 /* if the wheel is disabled, add an event to the stack. */
1382 if(wheel_enabled == false)
1383 wheel_events++;
1385 /* if it's enabled, go ahead and rotate.. */
1386 if(wheel_enabled)
1387 #endif
1388 #ifdef ROCKBLOX_ROTATE_CCW2
1389 /* fallback */
1390 case ROCKBLOX_ROTATE_CCW2:
1391 #endif
1392 move_block (0, 0, (rockblox_status.co + 1) % figures[rockblox_status.cf].max_or);
1393 break;
1395 case ROCKBLOX_ROTATE_CW:
1396 case ROCKBLOX_ROTATE_CW | BUTTON_REPEAT:
1397 #ifdef HAVE_SCROLLWHEEL
1398 if(wheel_enabled == false)
1399 wheel_events++;
1401 if(wheel_enabled)
1402 #endif
1403 #ifdef ROCKBLOX_ROTATE_CW2
1404 /* fallback */
1405 case ROCKBLOX_ROTATE_CW2:
1406 #endif
1407 move_block (0, 0,
1408 (rockblox_status.co + figures[rockblox_status.cf].max_or -
1409 1) % figures[rockblox_status.cf].max_or);
1410 break;
1412 case ROCKBLOX_DOWN:
1413 case ROCKBLOX_DOWN | BUTTON_REPEAT:
1414 move_block (0, 1, rockblox_status.co);
1415 break;
1417 case ROCKBLOX_RIGHT:
1418 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
1419 move_block (1, 0, rockblox_status.co);
1420 break;
1422 case ROCKBLOX_LEFT:
1423 case ROCKBLOX_LEFT | BUTTON_REPEAT:
1424 move_block (-1, 0, rockblox_status.co);
1425 break;
1427 case ROCKBLOX_DROP:
1428 #ifdef ROCKBLOX_DROP_PRE
1429 if (lastbutton != ROCKBLOX_DROP_PRE)
1430 break;
1431 #endif
1432 while (canMoveTo (rockblox_status.cx, rockblox_status.cy + 1, rockblox_status.co))
1433 move_block (0, 1, rockblox_status.co);
1434 break;
1435 #ifdef ROCKBLOX_RESTART
1436 case ROCKBLOX_RESTART:
1437 rb->splash (HZ * 1, "Restarting...");
1438 init_rockblox (false);
1439 break;
1440 #endif
1442 default:
1443 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
1444 return PLUGIN_USB_CONNECTED;
1445 break;
1447 if (button != BUTTON_NONE)
1448 lastbutton = button;
1450 #ifdef HAVE_SCROLLWHEEL
1451 /* check if we should enable the scroll wheel, if events
1452 * begin to stack up... */
1453 if(wheel_enabled == false)
1455 /* stopped rotating the wheel, reset the count */
1456 if(wheel_events == last_wheel_event)
1458 last_wheel_event = 0;
1459 wheel_events = 0;
1461 /* rotated the wheel a while constantly, enable it. */
1462 else if(wheel_events > 3)
1464 wheel_enabled = true;
1467 /* this evens out the last event and the "current" event.
1468 * if we get an event next time through button reading, it will
1469 * remain ahead of last_event. if we don't, they'll end up equaling
1470 * each other.. thus, the scroll count will be reset. */
1471 if(wheel_enabled == false && wheel_events > last_wheel_event)
1472 last_wheel_event++;
1474 #endif
1476 if (TIME_AFTER(*rb->current_tick, next_down_tick)) {
1477 move_down ();
1478 next_down_tick += level_speed(rockblox_status.level);
1479 if (TIME_AFTER(*rb->current_tick, next_down_tick))
1480 /* restart time "raster" when we had to wait longer than usual
1481 * (pause, game restart etc) */
1482 next_down_tick = *rb->current_tick + level_speed(rockblox_status.level);
1485 if (rockblox_status.gameover) {
1486 #if LCD_DEPTH >= 2
1487 rb->lcd_set_foreground (LCD_BLACK);
1488 #endif
1489 show_game_over();
1490 resume = false;
1491 return 0;
1494 refresh_board ();
1497 return 0;
1500 enum plugin_status plugin_start (const void *parameter)
1503 (void) parameter;
1505 rb->srand (*rb->current_tick);
1507 /* Load HighScore if any */
1508 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1510 #if LCD_DEPTH > 1
1511 rb->lcd_set_backdrop(NULL);
1512 #endif
1514 #ifdef HAVE_LCD_BITMAP
1515 rb->lcd_setfont (FONT_SYSFIXED);
1516 #else
1517 if (!pgfx_init(4, 2))
1519 rb->splash(HZ*2, "Old LCD :(");
1520 return PLUGIN_OK;
1522 #endif
1523 /* Turn off backlight timeout */
1524 backlight_force_on(); /* backlight control in lib/helper.c */
1525 load_game();
1526 resume_file = resume;
1527 while(!rockblox_loop()) {
1528 if(!resume) {
1529 int position = highscore_update(rockblox_status.score,
1530 rockblox_status.level, "",
1531 highscores, NUM_SCORES);
1532 if (position != -1) {
1533 if (position == 0)
1534 rb->splash(HZ*2, "New High Score");
1535 highscore_show(position, highscores, NUM_SCORES, true);
1540 #ifndef HAVE_LCD_BITMAP
1541 pgfx_release();
1542 #endif
1543 /* Save user's HighScore */
1544 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1545 backlight_use_settings(); /* backlight control in lib/helper.c */
1547 return PLUGIN_OK;