summaryrefslogtreecommitdiff
path: root/apps/plugins/rockblox.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/rockblox.c')
-rw-r--r--apps/plugins/rockblox.c870
1 files changed, 870 insertions, 0 deletions
diff --git a/apps/plugins/rockblox.c b/apps/plugins/rockblox.c
new file mode 100644
index 0000000000..1277b328c2
--- /dev/null
+++ b/apps/plugins/rockblox.c
@@ -0,0 +1,870 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2005 Eli Sherer
11 *
12 * Heavily modified for embedded use by Björn Stenberg (bjorn@haxx.se)
13 *
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "plugin.h"
22#include "highscore.h"
23
24#ifdef HAVE_LCD_BITMAP
25
26PLUGIN_HEADER
27
28extern const fb_data rockblox_background[];
29
30#if (CONFIG_KEYPAD == IPOD_3G_PAD) || \
31 (CONFIG_KEYPAD == IPOD_4G_PAD)
32
33#define ROCKBLOX_OFF (BUTTON_MENU | BUTTON_SELECT)
34#define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_BACK
35#define ROCKBLOX_ROTATE_RIGHT2 (BUTTON_MENU | BUTTON_REL)
36#define ROCKBLOX_ROTATE_LEFT BUTTON_SCROLL_FWD
37#define ROCKBLOX_LEFT BUTTON_LEFT
38#define ROCKBLOX_RIGHT BUTTON_RIGHT
39#define ROCKBLOX_DOWN BUTTON_PLAY
40#define ROCKBLOX_RESTART (BUTTON_SELECT | BUTTON_PLAY)
41#define ROCKBLOX_DROP (BUTTON_SELECT | BUTTON_REL)
42
43#define SCROLL_WHEEL
44
45#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
46 (CONFIG_KEYPAD == IRIVER_H300_PAD)
47
48#define ROCKBLOX_OFF BUTTON_OFF
49#define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
50#define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
51#define ROCKBLOX_DOWN BUTTON_DOWN
52#define ROCKBLOX_LEFT BUTTON_LEFT
53#define ROCKBLOX_RIGHT BUTTON_RIGHT
54#define ROCKBLOX_DROP BUTTON_MODE
55#define ROCKBLOX_RESTART BUTTON_ON
56
57#define ROCKBLOX_RC_OFF BUTTON_RC_STOP
58#elif CONFIG_KEYPAD == RECORDER_PAD
59
60#define ROCKBLOX_OFF BUTTON_OFF
61#define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
62#define ROCKBLOX_ROTATE_LEFT BUTTON_PLAY
63#define ROCKBLOX_DOWN BUTTON_DOWN
64#define ROCKBLOX_LEFT BUTTON_LEFT
65#define ROCKBLOX_RIGHT BUTTON_RIGHT
66#define ROCKBLOX_DROP BUTTON_ON
67#define ROCKBLOX_RESTART BUTTON_F1
68
69#elif CONFIG_KEYPAD == ONDIO_PAD
70
71#define ROCKBLOX_OFF BUTTON_OFF
72#define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
73#define ROCKBLOX_ROTATE_LEFT (BUTTON_MENU|BUTTON_UP)
74#define ROCKBLOX_DOWN BUTTON_DOWN
75#define ROCKBLOX_LEFT BUTTON_LEFT
76#define ROCKBLOX_RIGHT BUTTON_RIGHT
77#define ROCKBLOX_DROP_PRE BUTTON_MENU
78#define ROCKBLOX_DROP (BUTTON_MENU|BUTTON_REL)
79
80#elif CONFIG_KEYPAD == IAUDIO_X5_PAD
81
82#define ROCKBLOX_OFF BUTTON_POWER
83#define ROCKBLOX_ROTATE_RIGHT BUTTON_UP
84#define ROCKBLOX_ROTATE_LEFT BUTTON_SELECT
85#define ROCKBLOX_DOWN BUTTON_DOWN
86#define ROCKBLOX_LEFT BUTTON_LEFT
87#define ROCKBLOX_RIGHT BUTTON_RIGHT
88#define ROCKBLOX_DROP BUTTON_REC
89#define ROCKBLOX_RESTART BUTTON_PLAY
90
91#elif CONFIG_KEYPAD == IRIVER_H10_PAD
92
93#define ROCKBLOX_OFF BUTTON_POWER
94#define ROCKBLOX_ROTATE_RIGHT BUTTON_SCROLL_UP
95#define ROCKBLOX_ROTATE_LEFT BUTTON_REW
96#define ROCKBLOX_DOWN BUTTON_SCROLL_DOWN
97#define ROCKBLOX_LEFT BUTTON_LEFT
98#define ROCKBLOX_RIGHT BUTTON_RIGHT
99#define ROCKBLOX_DROP BUTTON_FF
100#define ROCKBLOX_RESTART BUTTON_PLAY
101
102#endif
103
104#define BLOCKS_NUM 7
105#define EMPTY_BLOCK 7
106
107#define BOARD_WIDTH 10
108#define BOARD_HEIGHT 20
109
110#if (LCD_WIDTH == 320) && (LCD_HEIGHT == 240)
111
112#define BLOCK_WIDTH 12
113#define BLOCK_HEIGHT 12
114#define BOARD_X 86
115#define BOARD_Y 0
116#define PREVIEW_X 12
117#define PREVIEW_Y 11
118#define LABEL_X 242
119#define SCORE_Y 25
120#define LEVEL_Y 70
121#define LINES_Y 105
122
123#elif (LCD_WIDTH == 220) && (LCD_HEIGHT == 176)
124
125#define BLOCK_WIDTH 8
126#define BLOCK_HEIGHT 8
127#define BOARD_X 27
128#define BOARD_Y 5
129#define PREVIEW_X 158
130#define PREVIEW_Y 130
131#define LABEL_X 147
132#define SCORE_Y 20
133#define LEVEL_Y 65
134#define LINES_Y 100
135
136#elif (LCD_WIDTH == 176) && (LCD_HEIGHT == 132)
137
138#define BLOCK_WIDTH 6
139#define BLOCK_HEIGHT 6
140#define BOARD_X 25
141#define BOARD_Y 1
142#define PREVIEW_X 126
143#define PREVIEW_Y 102
144#define LABEL_X 112
145#define SCORE_Y 17
146#define LEVEL_Y 49
147#define LINES_Y 81
148
149#elif (LCD_WIDTH == 160) && (LCD_HEIGHT == 128)
150
151#define BLOCK_WIDTH 6
152#define BLOCK_HEIGHT 6
153#define BOARD_X 22
154#define BOARD_Y 3
155#define PREVIEW_X 114
156#define PREVIEW_Y 100
157#define LABEL_X 101
158#define SCORE_Y 17
159#define LEVEL_Y 49
160#define LINES_Y 82
161
162#elif (LCD_WIDTH == 128) && (LCD_HEIGHT == 128)
163
164#define BLOCK_WIDTH 6
165#define BLOCK_HEIGHT 6
166#define BOARD_X 4
167#define BOARD_Y 3
168#define PREVIEW_X 84
169#define PREVIEW_Y 100
170#define LABEL_X 71
171#define SCORE_Y 17
172#define LEVEL_Y 49
173#define LINES_Y 82
174
175#elif (LCD_WIDTH == 112) && (LCD_HEIGHT == 64)
176
177#define BLOCK_WIDTH 4
178#define BLOCK_HEIGHT 3
179#define BOARD_X 9
180#define BOARD_Y 3
181#define PREVIEW_X 59
182#define PREVIEW_Y 5
183#define LABEL_X 59
184#define SCORE_Y 32
185#define LEVEL_Y 13
186#define LEVEL_X 78
187#define LINES_Y 51
188
189#elif (LCD_WIDTH == 138) && (LCD_HEIGHT == 110)
190
191#define BLOCK_WIDTH 5
192#define BLOCK_HEIGHT 5
193#define BOARD_X 14
194#define BOARD_Y 0
195#define PREVIEW_X 98
196#define PREVIEW_Y 88
197#define LABEL_X 80
198#define SCORE_Y 15
199#define LEVEL_Y 45
200#define LINES_Y 74
201
202#endif
203
204/* Pictures */
205#ifdef HAVE_LCD_COLOR
206#define SPLASH_SCREEN PLUGIN_DIR "/rockblox/splash.bmp"
207#define PIC_SCREEN PLUGIN_DIR "/rockblox/screen.bmp"
208#endif
209
210/* <<Explanation on Rockblox shapes>>
211
212 %%
213 %% - O has 1 orientation
214
215 %% %
216 %% %% - Z has 2 orientations
217 %
218
219 %% %
220 %% %% - S has 2 orientations
221 %
222 %
223 %
224 % %%%% - I has 2 orientations
225 %
226
227 % %%
228 % % % %%% - L has 4 orientations
229 %% %%% % %
230
231 % %%s
232 % % % %%% - J has 4 orientations
233 %% %%% % %
234
235 % % %%%
236 %% % %% % - T has 4 orientations
237 % %%% %
238 */
239
240
241/* must have variable */
242static struct plugin_api *rb;
243
244static bool gameover = false;
245/* c=current f=figure o=orientation n=next */
246static int lines, level, score, cx, cy, cf, co, nf;
247static short board[BOARD_HEIGHT][BOARD_WIDTH]; /* 20 rows of 10 blocks */
248
249#ifdef SCROLL_WHEEL
250int wheel_events = 0, last_wheel_event = 0;
251bool wheel_enabled = false;
252#endif
253
254static const short scoring[4] = { /* scoring for each number of lines */
255 40 /* single */ , 100 /* double */ , 300 /* triple */ , 1200 /* rockblox */
256};
257
258struct figure
259{
260#if LCD_DEPTH >= 2
261 unsigned short color[3]; /* color of figure (light,middle,shadow) */
262#endif
263 unsigned short max_or; /* max orientations */
264 signed short shapeX[4], shapeY[4]; /* implementation of figures */
265}
266
267/* array of figures */
268figures[BLOCKS_NUM] = {
269 /* O */
270 {
271#if LCD_DEPTH >= 16
272 {LCD_RGBPACK (153, 255, 255), LCD_RGBPACK(0, 255, 255),
273 LCD_RGBPACK(0,153,153)},
274#elif LCD_DEPTH == 2
275 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
276#endif
277 1,
278 {-1, 0, -1, 0},
279 {0, 0, 1, 1}
280 },
281 /* I */
282 {
283#if LCD_DEPTH >= 16
284 {LCD_RGBPACK (255, 153, 128), LCD_RGBPACK (255, 0, 0),
285 LCD_RGBPACK (153, 0, 0)},
286#elif LCD_DEPTH == 2
287 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
288#endif
289 2,
290 {-2, -1, 0, 1},
291 {0, 0, 0, 0}
292 },
293 /* 'Z' */
294 {
295#if LCD_DEPTH >= 16
296 {LCD_RGBPACK (153, 255, 153), LCD_RGBPACK (0, 255, 0),
297 LCD_RGBPACK (0, 153, 0)},
298#elif LCD_DEPTH == 2
299 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
300#endif
301 2,
302 {0, 1, -1, 0},
303 {0, 0, 1, 1}
304 },
305 /* 'S' */
306 {
307#if LCD_DEPTH >= 16
308 {LCD_RGBPACK (153, 153, 255), LCD_RGBPACK (0, 0, 255),
309 LCD_RGBPACK (0, 0, 153)},
310#elif LCD_DEPTH == 2
311 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
312#endif
313 2,
314 {-1, 0, 0, 1},
315 {0, 0, 1, 1}
316 },
317 /* 'L' */
318 {
319#if LCD_DEPTH >= 16
320 {LCD_RGBPACK (255, 255, 153), LCD_RGBPACK (255, 255, 0),
321 LCD_RGBPACK (153, 153, 0)},
322#elif LCD_DEPTH == 2
323 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
324#endif
325 4,
326 {-1, 0, 1, 1},
327 {0, 0, 0, 1}
328 },
329 /* 'J' */
330 {
331#if LCD_DEPTH >= 16
332 {LCD_RGBPACK (255, 153, 255), LCD_RGBPACK (255, 0, 255),
333 LCD_RGBPACK (153, 0, 153)},
334#elif LCD_DEPTH == 2
335 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
336#endif
337 4,
338 {-1, 0, 1, -1},
339 {0, 0, 0, 1}
340 },
341 /* 'T' */
342 {
343#if LCD_DEPTH >= 16
344 {LCD_RGBPACK (204, 204, 204), LCD_RGBPACK (153, 153, 153),
345 LCD_RGBPACK (85, 85, 85)},
346#elif LCD_DEPTH == 2
347 {LCD_WHITE, LCD_LIGHTGRAY, LCD_DARKGRAY},
348#endif
349 4,
350 {-1, 0, 1, 0},
351 {0, 0, 0, 1}
352 }
353};
354
355/* get random number from (0) to (range-1) */
356static int t_rand (int range)
357{
358 return rb->rand () % range;
359}
360
361/* init the board array to have no blocks */
362static void init_board (void)
363{
364 int i, j;
365 for (i = 0; i < BOARD_WIDTH; i++)
366 for (j = 0; j < BOARD_HEIGHT; j++)
367 board[j][i] = EMPTY_BLOCK;
368}
369
370/* show the score, level and lines */
371static void show_details (void)
372{
373 char str[25]; /* for strings */
374#if LCD_DEPTH >= 2
375 rb->lcd_set_foreground (LCD_BLACK);
376 rb->lcd_set_background (LCD_WHITE);
377#endif
378 rb->snprintf (str, sizeof (str), "%d", score);
379 rb->lcd_putsxy (LABEL_X, SCORE_Y, str);
380 rb->snprintf (str, sizeof (str), "%d", level);
381#ifdef LEVEL_X
382 rb->lcd_putsxy (LEVEL_X, LEVEL_Y, str);
383#else
384 rb->lcd_putsxy (LABEL_X, LEVEL_Y, str);
385#endif
386 rb->snprintf (str, sizeof (str), "%d", lines);
387 rb->lcd_putsxy (LABEL_X, LINES_Y, str);
388}
389
390static void init_rockblox (void)
391{
392 level = 1;
393 lines = 0;
394 score = 0;
395 gameover = false;
396 nf = t_rand (BLOCKS_NUM);
397 init_board ();
398 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
399 show_details ();
400}
401
402static inline int level_speed(int level)
403{
404 return (5*HZ) / (level + 9);
405}
406
407static int getRelativeX (int figure, int square, int orientation)
408{
409 switch (orientation) {
410 case 0:
411 return figures[figure].shapeX[square];
412 case 1:
413 return figures[figure].shapeY[square];
414 case 2:
415 return -figures[figure].shapeX[square];
416 case 3:
417 return -figures[figure].shapeY[square];
418 default:
419 return 0;
420 }
421}
422
423static int getRelativeY (int figure, int square, int orientation)
424{
425 switch (orientation) {
426 case 0:
427 return figures[figure].shapeY[square];
428 case 1:
429 return -figures[figure].shapeX[square];
430 case 2:
431 return -figures[figure].shapeY[square];
432 case 3:
433 return figures[figure].shapeX[square];
434 default:
435 return 0;
436 }
437}
438
439/* redraw the while board on the screen */
440static void refresh_board (void)
441{
442 int i, j, x, y, block;
443
444#if LCD_DEPTH >= 2
445 rb->lcd_set_foreground (LCD_BLACK);
446#elif LCD_DEPTH == 1
447 rb->lcd_set_drawmode (DRMODE_SOLID | DRMODE_INVERSEVID);
448#endif
449
450 rb->lcd_fillrect (BOARD_X, 1, BOARD_WIDTH * BLOCK_WIDTH, BOARD_Y);
451
452#if LCD_DEPTH == 1
453 rb->lcd_set_drawmode (DRMODE_SOLID);
454#endif
455
456 for (i = 0; i < BOARD_WIDTH; i++)
457 for (j = 0; j < BOARD_HEIGHT; j++) {
458 block = board[j][i];
459 if (block == EMPTY_BLOCK) {
460#if LCD_DEPTH >= 2
461 rb->lcd_set_foreground (LCD_BLACK);
462#elif LCD_DEPTH == 1
463 rb->lcd_set_drawmode (DRMODE_SOLID | DRMODE_INVERSEVID);
464#endif
465
466 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
467 BOARD_Y + j * BLOCK_HEIGHT, BLOCK_WIDTH,
468 BLOCK_HEIGHT);
469
470#if LCD_DEPTH == 1
471 rb->lcd_set_drawmode (DRMODE_SOLID);
472#endif
473 } else {
474#if LCD_DEPTH >= 2
475 /* middle drawing */
476 rb->lcd_set_foreground (figures[block].color[1]);
477#endif
478 rb->lcd_fillrect (BOARD_X + i * BLOCK_WIDTH,
479 BOARD_Y + j * BLOCK_HEIGHT,
480 BLOCK_WIDTH, BLOCK_HEIGHT);
481#if LCD_DEPTH >= 2
482 /* light drawing */
483 rb->lcd_set_foreground (figures[block].color[0]);
484#endif
485 rb->lcd_vline (BOARD_X + i * BLOCK_WIDTH,
486 BOARD_Y + j * BLOCK_HEIGHT,
487 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 2);
488 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH,
489 BOARD_X + (i + 1) * BLOCK_WIDTH - 2,
490 BOARD_Y + j * BLOCK_HEIGHT);
491#if LCD_DEPTH >= 2
492 /* shadow drawing */
493 rb->lcd_set_foreground (figures[block].color[2]);
494#endif
495 rb->lcd_vline (BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
496 BOARD_Y + j * BLOCK_HEIGHT + 1,
497 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
498 rb->lcd_hline (BOARD_X + i * BLOCK_WIDTH + 1,
499 BOARD_X + (i + 1) * BLOCK_WIDTH - 1,
500 BOARD_Y + (j + 1) * BLOCK_HEIGHT - 1);
501 }
502 }
503
504 for (i = 0; i < 4; i++) {
505 x = getRelativeX (cf, i, co) + cx;
506 y = getRelativeY (cf, i, co) + cy;
507#if LCD_DEPTH >= 2
508 rb->lcd_set_foreground (figures[cf].color[1]); /* middle drawing */
509#endif
510 rb->lcd_fillrect (BOARD_X + x * BLOCK_WIDTH,
511 BOARD_Y + y * BLOCK_HEIGHT,
512 BLOCK_WIDTH, BLOCK_HEIGHT);
513#if LCD_DEPTH >= 2
514 rb->lcd_set_foreground (figures[cf].color[0]); /* light drawing */
515#endif
516 rb->lcd_vline (BOARD_X + x * BLOCK_WIDTH, BOARD_Y + y * BLOCK_HEIGHT,
517 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 2);
518 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH,
519 BOARD_X + (x + 1) * BLOCK_WIDTH - 2,
520 BOARD_Y + y * BLOCK_HEIGHT);
521#if LCD_DEPTH >= 2
522 rb->lcd_set_foreground (figures[cf].color[2]); /* shadow drawing */
523#endif
524 rb->lcd_vline (BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
525 BOARD_Y + y * BLOCK_HEIGHT + 1,
526 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
527 rb->lcd_hline (BOARD_X + x * BLOCK_WIDTH + 1,
528 BOARD_X + (x + 1) * BLOCK_WIDTH - 1,
529 BOARD_Y + (y + 1) * BLOCK_HEIGHT - 1);
530 }
531 rb->lcd_update ();
532}
533
534static bool canMoveTo (int x, int y, int newOrientation)
535{
536 int i, rx, ry;
537 for (i = 0; i < 4; i++) {
538 ry = getRelativeY (cf, i, newOrientation) + y;
539 rx = getRelativeX (cf, i, newOrientation) + x;
540 if ((rx < 0 || rx >= BOARD_WIDTH) ||
541 (ry < 0 || ry >= BOARD_HEIGHT) || (board[ry][rx] != EMPTY_BLOCK))
542 return false;
543 }
544 return true;
545}
546
547/* draws the preview of next block in the preview window */
548static void draw_next_block (void)
549{
550 int i, rx, ry;
551 /* clear preview window first */
552#if LCD_DEPTH >= 2
553 rb->lcd_set_foreground (LCD_BLACK);
554#elif LCD_DEPTH == 1
555 rb->lcd_set_drawmode (DRMODE_SOLID | DRMODE_INVERSEVID);
556#endif
557
558 /* 4x4 */
559 rb->lcd_fillrect (PREVIEW_X, PREVIEW_Y, BLOCK_WIDTH * 4, BLOCK_HEIGHT * 4);
560
561#if LCD_DEPTH == 1
562 rb->lcd_set_drawmode (DRMODE_SOLID);
563#endif
564
565 /* draw the lightgray rectangles */
566#if LCD_DEPTH >= 16
567 rb->lcd_set_foreground (LCD_RGBPACK (40, 40, 40));
568#elif LCD_DEPTH == 2
569 rb->lcd_set_foreground (LCD_DARKGRAY);
570#endif
571
572#if LCD_DEPTH >= 2
573 for (rx = 0; rx < 4; rx++)
574 for (ry = 0; ry < 4; ry++)
575 rb->lcd_drawrect (PREVIEW_X + rx * BLOCK_WIDTH,
576 PREVIEW_Y + ry * BLOCK_HEIGHT, BLOCK_WIDTH,
577 BLOCK_HEIGHT);
578#endif
579
580 /* draw the figure */
581 for (i = 0; i < 4; i++) {
582 rx = getRelativeX (nf, i, 0) + 2;
583 ry = getRelativeY (nf, i, 0) + 2;
584#if LCD_DEPTH >= 2
585 rb->lcd_set_foreground (figures[nf].color[1]); /* middle drawing */
586#endif
587 rb->lcd_fillrect (PREVIEW_X + rx * BLOCK_WIDTH,
588 PREVIEW_Y + ry * BLOCK_HEIGHT,
589 BLOCK_WIDTH, BLOCK_HEIGHT);
590#if LCD_DEPTH >= 2
591 rb->lcd_set_foreground (figures[nf].color[0]); /* light drawing */
592#endif
593 rb->lcd_vline (PREVIEW_X + rx * BLOCK_WIDTH,
594 PREVIEW_Y + ry * BLOCK_HEIGHT,
595 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 2);
596 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH,
597 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 2,
598 PREVIEW_Y + ry * BLOCK_HEIGHT);
599#if LCD_DEPTH >= 2
600 rb->lcd_set_foreground (figures[nf].color[2]); /* shadow drawing */
601#endif
602 rb->lcd_vline (PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
603 PREVIEW_Y + ry * BLOCK_HEIGHT + 1,
604 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
605 rb->lcd_hline (PREVIEW_X + rx * BLOCK_WIDTH + 1,
606 PREVIEW_X + (rx + 1) * BLOCK_WIDTH - 1,
607 PREVIEW_Y + (ry + 1) * BLOCK_HEIGHT - 1);
608 }
609
610}
611
612/* move the block to a relative location */
613static void move_block (int x, int y, int o)
614{
615 if (canMoveTo (cx + x, cy + y, o)) {
616 cy += y;
617 cx += x;
618 co = o;
619 }
620}
621
622/* try to add a new block to play with (return true if gameover) */
623static void new_block (void)
624{
625 cy = 1;
626 cx = 5;
627 cf = nf;
628 co = 0; /* start at the same orientation all time */
629 nf = t_rand (BLOCKS_NUM);
630 gameover = !canMoveTo (cx, cy, co);
631
632 draw_next_block ();
633}
634
635
636/* check for filled lines and do what necessary */
637static int check_lines (void)
638{
639 int i, j, y;
640 int rockblox = 0;
641
642 for (j = 0; j < BOARD_HEIGHT; j++) {
643 for (i = 0; ((i < BOARD_WIDTH) && (board[j][i] != EMPTY_BLOCK)); i++);
644 if (i == BOARD_WIDTH) { /* woo hoo, we have a line */
645 rockblox++;
646 for (y = j; y > 0; y--)
647 for (i = 0; i < BOARD_WIDTH; i++)
648 board[y][i] = board[y - 1][i]; /* fall line */
649 }
650 }
651
652 return rockblox;
653}
654
655/* moves down the figure and returns true if gameover */
656static void move_down (void)
657{
658 int l, i, rx, ry;
659
660 if (!canMoveTo (cx, cy + 1, co)) {
661 /* save figure to board */
662 for (i = 0; i < 4; i++) {
663 rx = getRelativeX (cf, i, co) + cx;
664 ry = getRelativeY (cf, i, co) + cy;
665 board[ry][rx] = cf;
666 }
667 /* check if formed some lines */
668 l = check_lines ();
669 if (l) {
670 /* the original scoring from "http://en.wikipedia.org/wiki/Rockblox" */
671 score += scoring[l - 1] * level;
672 lines += l;
673 level = (int) lines / 10 + 1;
674 }
675
676 /* show details */
677 show_details ();
678
679 /* generate a new figure */
680 new_block ();
681 } else
682 move_block (0, 1, co);
683}
684
685static int rockblox_loop (void)
686{
687 int button;
688 int lastbutton = BUTTON_NONE;
689 long next_down_tick = *rb->current_tick + level_speed(level);
690
691 new_block ();
692
693 while (1) {
694#ifdef HAS_BUTTON_HOLD
695 if (rb->button_hold ()) {
696 /* Restore user's original backlight setting */
697 rb->backlight_set_timeout (rb->global_settings->backlight_timeout);
698
699 rb->splash(0, true, "Paused");
700 while (rb->button_hold ())
701 rb->sleep(HZ/10);
702
703 /* Permanently enable the backlight (unless the user has
704 turned it off) */
705 if (rb->global_settings->backlight_timeout > 0)
706 rb->backlight_set_timeout (1);
707
708 /* get rid of the splash text */
709 rb->lcd_bitmap (rockblox_background, 0, 0, LCD_WIDTH, LCD_HEIGHT);
710 show_details ();
711 draw_next_block ();
712 refresh_board ();
713 }
714#endif
715
716 button = rb->button_get_w_tmo (MAX(next_down_tick - *rb->current_tick, 1));
717 switch (button) {
718#ifdef ROCKBLOX_RC_OFF
719 case ROCKBLOX_RC_OFF:
720#endif
721 case ROCKBLOX_OFF:
722 return PLUGIN_OK;
723
724 case ROCKBLOX_ROTATE_RIGHT:
725 case ROCKBLOX_ROTATE_RIGHT | BUTTON_REPEAT:
726#ifdef SCROLL_WHEEL
727 /* if the wheel is disabled, add an event to the stack. */
728 if(wheel_enabled == false)
729 wheel_events++;
730
731 /* if it's enabled, go ahead and rotate.. */
732 if(wheel_enabled)
733#endif
734 move_block (0, 0, (co + 1) % figures[cf].max_or);
735 break;
736
737 case ROCKBLOX_ROTATE_LEFT:
738 case ROCKBLOX_ROTATE_LEFT | BUTTON_REPEAT:
739#ifdef SCROLL_WHEEL
740 if(wheel_enabled == false)
741 wheel_events++;
742
743 if(wheel_enabled)
744#endif
745 move_block (0, 0,
746 (co + figures[cf].max_or -
747 1) % figures[cf].max_or);
748 break;
749
750#ifdef ROCKBLOX_ROTATE_RIGHT2
751 case ROCKBLOX_ROTATE_RIGHT2:
752 move_block (0, 0, (co + 1) % figures[cf].max_or);
753 break;
754#endif
755
756 case ROCKBLOX_DOWN:
757 case ROCKBLOX_DOWN | BUTTON_REPEAT:
758 move_block (0, 1, co);
759 break;
760
761 case ROCKBLOX_RIGHT:
762 case ROCKBLOX_RIGHT | BUTTON_REPEAT:
763 move_block (1, 0, co);
764 break;
765
766 case ROCKBLOX_LEFT:
767 case ROCKBLOX_LEFT | BUTTON_REPEAT:
768 move_block (-1, 0, co);
769 break;
770
771 case ROCKBLOX_DROP:
772#ifdef ROCKBLOX_DROP_PRE
773 if (lastbutton != ROCKBLOX_DROP_PRE)
774 break;
775#endif
776 while (canMoveTo (cx, cy + 1, co))
777 move_block (0, 1, co);
778 break;
779#ifdef ROCKBLOX_RESTART
780 case ROCKBLOX_RESTART:
781 rb->splash (HZ * 1, true, "Restarting...");
782 init_rockblox ();
783 new_block ();
784 break;
785#endif
786
787 default:
788 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
789 return PLUGIN_USB_CONNECTED;
790 break;
791 }
792 if (button != BUTTON_NONE)
793 lastbutton = button;
794
795#ifdef SCROLL_WHEEL
796 /* check if we should enable the scroll wheel, if events
797 * begin to stack up... */
798 if(wheel_enabled == false)
799 {
800 /* stopped rotating the wheel, reset the count */
801 if(wheel_events == last_wheel_event)
802 {
803 last_wheel_event = 0;
804 wheel_events = 0;
805 }
806 /* rotated the wheel a while constantly, enable it. */
807 else if(wheel_events > 3)
808 {
809 wheel_enabled = true;
810 }
811
812 /* this evens out the last event and the "current" event.
813 * if we get an event next time through button reading, it will
814 * remain ahead of last_event. if we don't, they'll end up equaling
815 * each other.. thus, the scroll count will be reset. */
816 if(wheel_enabled == false && wheel_events > last_wheel_event)
817 last_wheel_event++;
818 }
819#endif
820
821 if (TIME_AFTER(*rb->current_tick, next_down_tick)) {
822 move_down ();
823 next_down_tick += level_speed(level);
824 if (TIME_AFTER(*rb->current_tick, next_down_tick))
825 /* restart time "raster" when we had to wait longer than usual
826 * (pause, game restart etc) */
827 next_down_tick = *rb->current_tick + level_speed(level);
828 }
829
830 if (gameover) {
831#if LCD_DEPTH >= 2
832 rb->lcd_set_foreground (LCD_BLACK);
833#endif
834 rb->splash (HZ * 2, true, "Game Over");
835 init_rockblox ();
836 new_block ();
837 }
838
839 refresh_board ();
840 }
841
842 return PLUGIN_OK;
843}
844
845enum plugin_status plugin_start (struct plugin_api *api, void *parameter)
846{
847 int ret;
848
849 (void) parameter;
850 rb = api;
851
852 rb->srand (*rb->current_tick);
853
854 rb->lcd_setfont (FONT_SYSFIXED);
855 /* Permanently enable the backlight (unless the user has turned it off) */
856 if (rb->global_settings->backlight_timeout > 0)
857 rb->backlight_set_timeout (1);
858
859 init_rockblox ();
860 ret = rockblox_loop ();
861
862 /* Lets use the default font */
863 rb->lcd_setfont (FONT_UI);
864 /* Restore user's original backlight setting */
865 rb->backlight_set_timeout (rb->global_settings->backlight_timeout);
866
867 return ret;
868}
869
870#endif