1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2005 Adam Boot
12 * Color graphics from Gweled (http://sebdelestaing.free.fr/gweled/)
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 ****************************************************************************/
25 #include "playback_control.h"
27 #ifdef HAVE_LCD_BITMAP
31 /* button definitions */
32 #if CONFIG_KEYPAD == RECORDER_PAD
33 #define JEWELS_UP BUTTON_UP
34 #define JEWELS_DOWN BUTTON_DOWN
35 #define JEWELS_LEFT BUTTON_LEFT
36 #define JEWELS_RIGHT BUTTON_RIGHT
37 #define JEWELS_SELECT BUTTON_PLAY
38 #define JEWELS_CANCEL BUTTON_OFF
40 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
41 #define JEWELS_UP BUTTON_UP
42 #define JEWELS_DOWN BUTTON_DOWN
43 #define JEWELS_LEFT BUTTON_LEFT
44 #define JEWELS_RIGHT BUTTON_RIGHT
45 #define JEWELS_SELECT BUTTON_SELECT
46 #define JEWELS_CANCEL BUTTON_OFF
48 #elif CONFIG_KEYPAD == ONDIO_PAD
49 #define JEWELS_UP BUTTON_UP
50 #define JEWELS_DOWN BUTTON_DOWN
51 #define JEWELS_LEFT BUTTON_LEFT
52 #define JEWELS_RIGHT BUTTON_RIGHT
53 #define JEWELS_SELECT BUTTON_MENU
54 #define JEWELS_CANCEL BUTTON_OFF
56 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
57 #define JEWELS_UP BUTTON_UP
58 #define JEWELS_DOWN BUTTON_DOWN
59 #define JEWELS_LEFT BUTTON_LEFT
60 #define JEWELS_RIGHT BUTTON_RIGHT
61 #define JEWELS_SELECT BUTTON_SELECT
62 #define JEWELS_CANCEL BUTTON_OFF
63 #define JEWELS_RC_CANCEL BUTTON_RC_STOP
65 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
66 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
67 #define JEWELS_SCROLLWHEEL
68 #define JEWELS_UP BUTTON_MENU
69 #define JEWELS_DOWN BUTTON_PLAY
70 #define JEWELS_LEFT BUTTON_LEFT
71 #define JEWELS_RIGHT BUTTON_RIGHT
72 #define JEWELS_PREV BUTTON_SCROLL_BACK
73 #define JEWELS_NEXT BUTTON_SCROLL_FWD
74 #define JEWELS_SELECT BUTTON_SELECT
76 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
77 #define JEWELS_UP BUTTON_UP
78 #define JEWELS_DOWN BUTTON_DOWN
79 #define JEWELS_LEFT BUTTON_LEFT
80 #define JEWELS_RIGHT BUTTON_RIGHT
81 #define JEWELS_SELECT BUTTON_SELECT
82 #define JEWELS_CANCEL BUTTON_PLAY
84 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
85 #define JEWELS_UP BUTTON_UP
86 #define JEWELS_DOWN BUTTON_DOWN
87 #define JEWELS_LEFT BUTTON_LEFT
88 #define JEWELS_RIGHT BUTTON_RIGHT
89 #define JEWELS_SELECT BUTTON_SELECT
90 #define JEWELS_CANCEL BUTTON_POWER
92 #elif CONFIG_KEYPAD == GIGABEAT_PAD
93 #define JEWELS_UP BUTTON_UP
94 #define JEWELS_DOWN BUTTON_DOWN
95 #define JEWELS_LEFT BUTTON_LEFT
96 #define JEWELS_RIGHT BUTTON_RIGHT
97 #define JEWELS_SELECT BUTTON_SELECT
98 #define JEWELS_CANCEL BUTTON_POWER
100 #elif CONFIG_KEYPAD == SANSA_E200_PAD
101 #define JEWELS_SCROLLWHEEL
102 #define JEWELS_UP BUTTON_UP
103 #define JEWELS_DOWN BUTTON_DOWN
104 #define JEWELS_LEFT BUTTON_LEFT
105 #define JEWELS_RIGHT BUTTON_RIGHT
106 #define JEWELS_PREV BUTTON_SCROLL_BACK
107 #define JEWELS_NEXT BUTTON_SCROLL_FWD
108 #define JEWELS_SELECT BUTTON_SELECT
109 #define JEWELS_CANCEL BUTTON_POWER
111 #elif CONFIG_KEYPAD == SANSA_C200_PAD
112 #define JEWELS_UP BUTTON_UP
113 #define JEWELS_DOWN BUTTON_DOWN
114 #define JEWELS_LEFT BUTTON_LEFT
115 #define JEWELS_RIGHT BUTTON_RIGHT
116 #define JEWELS_SELECT BUTTON_SELECT
117 #define JEWELS_CANCEL BUTTON_POWER
119 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
120 #define JEWELS_UP BUTTON_SCROLL_UP
121 #define JEWELS_DOWN BUTTON_SCROLL_DOWN
122 #define JEWELS_LEFT BUTTON_LEFT
123 #define JEWELS_RIGHT BUTTON_RIGHT
124 #define JEWELS_SELECT BUTTON_PLAY
125 #define JEWELS_CANCEL BUTTON_POWER
127 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
128 #define JEWELS_UP BUTTON_UP
129 #define JEWELS_DOWN BUTTON_DOWN
130 #define JEWELS_LEFT BUTTON_LEFT
131 #define JEWELS_RIGHT BUTTON_RIGHT
132 #define JEWELS_SELECT BUTTON_SELECT
133 #define JEWELS_CANCEL BUTTON_BACK
135 #elif CONFIG_KEYPAD == MROBE100_PAD
136 #define JEWELS_UP BUTTON_UP
137 #define JEWELS_DOWN BUTTON_DOWN
138 #define JEWELS_LEFT BUTTON_LEFT
139 #define JEWELS_RIGHT BUTTON_RIGHT
140 #define JEWELS_SELECT BUTTON_SELECT
141 #define JEWELS_CANCEL BUTTON_POWER
143 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
144 #define JEWELS_UP BUTTON_RC_VOL_UP
145 #define JEWELS_DOWN BUTTON_RC_VOL_DOWN
146 #define JEWELS_LEFT BUTTON_RC_REW
147 #define JEWELS_RIGHT BUTTON_RC_FF
148 #define JEWELS_SELECT BUTTON_RC_PLAY
149 #define JEWELS_CANCEL BUTTON_RC_REC
151 #define JEWELS_RC_CANCEL BUTTON_REC
153 #elif CONFIG_KEYPAD == COWOND2_PAD
154 #define JEWELS_CANCEL BUTTON_POWER
156 #elif CONFIG_KEYPAD == IAUDIO67_PAD
157 #define JEWELS_UP BUTTON_STOP
158 #define JEWELS_DOWN BUTTON_PLAY
159 #define JEWELS_LEFT BUTTON_LEFT
160 #define JEWELS_RIGHT BUTTON_RIGHT
161 #define JEWELS_SELECT BUTTON_MENU
162 #define JEWELS_CANCEL BUTTON_POWER
165 #error No keymap defined!
168 #ifdef HAVE_TOUCHSCREEN
170 #define JEWELS_UP BUTTON_TOPMIDDLE
173 #define JEWELS_DOWN BUTTON_BOTTOMMIDDLE
176 #define JEWELS_LEFT BUTTON_MIDLEFT
179 #define JEWELS_RIGHT BUTTON_MIDRIGHT
181 #ifndef JEWELS_SELECT
182 #define JEWELS_SELECT BUTTON_CENTER
184 #ifndef JEWELS_CANCEL
185 #define JEWELS_CANCEL BUTTON_TOPLEFT
189 /* use 30x30 tiles (iPod Video, Gigabeat) */
190 #if (LCD_HEIGHT == 240) && (LCD_WIDTH == 320) || \
191 ((LCD_HEIGHT == 320) && (LCD_WIDTH == 240))
192 #define TILE_WIDTH 30
193 #define TILE_HEIGHT 30
195 #define NUM_SCORES 10
197 /* use 22x22 tiles (H300, iPod Color) */
198 #elif ((LCD_HEIGHT == 176) && (LCD_WIDTH == 220)) || \
199 ((LCD_HEIGHT == 220) && (LCD_WIDTH == 176))
200 #define TILE_WIDTH 22
201 #define TILE_HEIGHT 22
203 #define NUM_SCORES 10
205 /* use 16x16 tiles (iPod Nano) */
206 #elif (LCD_HEIGHT == 132) && (LCD_WIDTH == 176)
207 #define TILE_WIDTH 16
208 #define TILE_HEIGHT 16
210 #define NUM_SCORES 10
212 /* use 16x16 tiles (H100, iAudio X5, iPod 3G, iPod 4G grayscale) */
213 #elif (LCD_HEIGHT == 128) && (LCD_WIDTH == 160)
214 #define TILE_WIDTH 16
215 #define TILE_HEIGHT 16
217 #define NUM_SCORES 10
219 /* use 14x14 tiles (H10 5/6 GB) */
220 #elif (LCD_HEIGHT == 128) && (LCD_WIDTH == 128)
221 #define TILE_WIDTH 14
222 #define TILE_HEIGHT 14
224 #define NUM_SCORES 10
226 /* use 13x13 tiles (iPod Mini) */
227 #elif (LCD_HEIGHT == 110) && (LCD_WIDTH == 138)
228 #define TILE_WIDTH 13
229 #define TILE_HEIGHT 13
231 #define NUM_SCORES 10
233 /* use 12x12 tiles (iAudio M3) */
234 #elif (LCD_HEIGHT == 96) && (LCD_WIDTH == 128)
235 #define TILE_WIDTH 12
236 #define TILE_HEIGHT 12
240 /* use 10x10 tiles (Sansa c200) */
241 #elif (LCD_HEIGHT == 80) && (LCD_WIDTH == 132)
242 #define TILE_WIDTH 10
243 #define TILE_HEIGHT 10
247 /* use 10x8 tiles (iFP 700) */
248 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 128)
249 #define TILE_WIDTH 10
250 #define TILE_HEIGHT 8
254 /* use 10x8 tiles (Recorder, Ondio) */
255 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 112)
256 #define TILE_WIDTH 10
257 #define TILE_HEIGHT 8
262 #error JEWELS: Unsupported LCD
266 #define SCORE_FILE PLUGIN_GAMES_DIR "/jewels.score"
267 #define SAVE_FILE PLUGIN_GAMES_DIR "/jewels.save"
269 /* final game return status */
270 #define BJ_QUIT_FROM_GAME 4
276 /* swap directions */
282 /* play board dimension */
286 /* next level threshold */
287 #define LEVEL_PTS 100
289 /* animation frame rate */
299 #define FONT_HEIGHT 8
301 #define MENU_WIDTH 100
331 struct jewels_menuitem
{
333 enum menu_result res
;
336 {"Jewels", false, 0, 6,
337 {{"New Game", MRES_NEW
},
338 {"Puzzle", MRES_PUZZLE
},
339 {"Resume Game", MRES_RESUME
},
340 {"High Scores", MRES_SCORES
},
342 {"Quit", MRES_QUIT
}}},
344 {{"Audio Playback", MRES_PLAYBACK
},
345 {"Resume Game", MRES_RESUME
},
346 {"Save Game", MRES_SAVE
},
347 {"End Game", MRES_QUIT
},
348 {"Exit Jewels", MRES_EXIT
}}}
351 /* global rockbox api */
352 static const struct plugin_api
* rb
;
354 /* external bitmaps */
355 extern const fb_data jewels
[];
357 /* tile background colors */
358 #ifdef HAVE_LCD_COLOR
359 static const unsigned jewels_bkgd
[2] = {
360 LCD_RGBPACK(104, 63, 63),
361 LCD_RGBPACK(83, 44, 44)
366 * type is the jewel number 0-7
367 * falling if the jewel is falling
368 * delete marks the jewel for deletion
376 /* the game context struct
377 * score is the current level score
378 * segments is the number of cleared segments in the current run
379 * level is the current level
380 * type is the game type (normal or puzzle)
381 * highscores is the list of high scores
382 * resume denotes whether to resume the currently loaded game
383 * dirty denotes whether the high scores are out of sync with the saved file
384 * playboard is the game playing board (first row is hidden)
385 * num_jewels is the number of different jewels to use
387 struct game_context
{
389 unsigned int segments
;
392 unsigned int highscores
[NUM_SCORES
];
395 struct tile playboard
[BJ_HEIGHT
][BJ_WIDTH
];
396 unsigned int num_jewels
;
399 #define MAX_NUM_JEWELS 7
401 #define MAX_PUZZLE_TILES 4
402 #define NUM_PUZZLE_LEVELS 10
410 struct puzzle_level
{
411 unsigned int num_jewels
;
412 unsigned int num_tiles
;
413 struct puzzle_tile tiles
[MAX_PUZZLE_TILES
];
416 #define PUZZLE_TILE_UP 1
417 #define PUZZLE_TILE_DOWN 2
418 #define PUZZLE_TILE_LEFT 4
419 #define PUZZLE_TILE_RIGHT 8
421 struct puzzle_level puzzle_levels
[NUM_PUZZLE_LEVELS
] = {
422 { 5, 2, { {3, 3, PUZZLE_TILE_RIGHT
},
423 {4, 2, PUZZLE_TILE_LEFT
} } },
424 { 5, 2, { {3, 2, PUZZLE_TILE_DOWN
},
425 {3, 4, PUZZLE_TILE_UP
} } },
426 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
427 {3, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
428 {3, 6, PUZZLE_TILE_UP
} } },
429 { 6, 3, { {3, 2, PUZZLE_TILE_RIGHT
},
430 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
431 {5, 4, PUZZLE_TILE_LEFT
} } },
432 { 6, 2, { {3, 4, PUZZLE_TILE_RIGHT
},
433 {4, 2, PUZZLE_TILE_LEFT
} } },
434 { 6, 2, { {3, 2, PUZZLE_TILE_DOWN
},
435 {4, 4, PUZZLE_TILE_UP
} } },
436 { 7, 4, { {3, 2, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
437 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
438 {3, 4, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
439 {4, 4, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
440 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
441 {4, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
442 {3, 6, PUZZLE_TILE_UP
} } },
443 { 7, 3, { {2, 2, PUZZLE_TILE_RIGHT
},
444 {4, 1, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
445 {5, 4, PUZZLE_TILE_LEFT
} } },
446 { 7, 4, { {3, 0, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
447 {5, 0, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
448 {2, 7, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
449 {4, 7, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
452 /*****************************************************************************
453 * jewels_init() initializes jewels data structures.
454 ******************************************************************************/
455 static void jewels_init(struct game_context
* bj
) {
456 /* seed the rand generator */
457 rb
->srand(*rb
->current_tick
);
459 /* check for resumed game */
470 /* clear playing board */
471 rb
->memset(bj
->playboard
, 0, sizeof(bj
->playboard
));
474 /*****************************************************************************
475 * jewels_setcolors() set the foreground and background colors.
476 ******************************************************************************/
477 static inline void jewels_setcolors(void) {
478 #ifdef HAVE_LCD_COLOR
479 rb
->lcd_set_background(LCD_RGBPACK(49, 26, 26));
480 rb
->lcd_set_foreground(LCD_RGBPACK(210, 181, 181));
484 /*****************************************************************************
485 * jewels_drawboard() redraws the entire game board.
486 ******************************************************************************/
487 static void jewels_drawboard(struct game_context
* bj
) {
490 unsigned int tempscore
;
491 char *title
= "Level";
494 tempscore
= (bj
->score
>LEVEL_PTS
? LEVEL_PTS
: bj
->score
);
497 rb
->lcd_clear_display();
499 /* dispay playing board */
500 for(i
=0; i
<BJ_HEIGHT
-1; i
++){
501 for(j
=0; j
<BJ_WIDTH
; j
++){
502 #ifdef HAVE_LCD_COLOR
503 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
504 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
505 TILE_WIDTH
, TILE_HEIGHT
);
506 rb
->lcd_bitmap_transparent_part(jewels
,
507 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
508 TILE_WIDTH
, j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
509 TILE_WIDTH
, TILE_HEIGHT
);
511 rb
->lcd_bitmap_part(jewels
,
512 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
513 TILE_WIDTH
, j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
514 TILE_WIDTH
, TILE_HEIGHT
);
519 #if LCD_WIDTH > LCD_HEIGHT /* horizontal layout */
521 /* draw separator lines */
523 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, LCD_HEIGHT
-1);
524 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, 18);
525 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, LCD_HEIGHT
-10);
527 /* draw progress bar */
528 #ifdef HAVE_LCD_COLOR
529 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
531 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
532 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
533 tempscore
/LEVEL_PTS
),
534 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
535 ((LCD_HEIGHT
-10)-18)*tempscore
/LEVEL_PTS
);
536 #ifdef HAVE_LCD_COLOR
537 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
538 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
539 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
540 tempscore
/LEVEL_PTS
)+1,
541 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
542 ((LCD_HEIGHT
-10)-18)*tempscore
/LEVEL_PTS
-1);
544 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
545 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
546 tempscore
/LEVEL_PTS
),
547 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
548 ((LCD_HEIGHT
-10)-18)*tempscore
/LEVEL_PTS
+1);
552 rb
->lcd_getstringsize(title
, &w
, &h
);
553 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 1, title
);
555 rb
->snprintf(str
, 4, "%d", bj
->level
);
556 rb
->lcd_getstringsize(str
, &w
, &h
);
557 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 10, str
);
559 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
560 rb
->lcd_getstringsize(str
, &w
, &h
);
561 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2,
564 #elif LCD_WIDTH < LCD_HEIGHT /* vertical layout */
566 /* draw separator lines */
568 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
569 rb
->lcd_hline(0, LCD_WIDTH
-1, LCD_HEIGHT
-14);
570 rb
->lcd_vline(LCD_WIDTH
/2, LCD_HEIGHT
-14, LCD_HEIGHT
-1);
572 /* draw progress bar */
573 #ifdef HAVE_LCD_COLOR
574 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
576 rb
->lcd_fillrect(0, (8*TILE_HEIGHT
+YOFS
)
577 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
578 LCD_WIDTH
*tempscore
/LEVEL_PTS
,
579 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
580 #ifdef HAVE_LCD_COLOR
581 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
582 rb
->lcd_drawrect(1, (8*TILE_HEIGHT
+YOFS
)
583 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4+1,
584 LCD_WIDTH
*tempscore
/LEVEL_PTS
-1,
585 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2-2);
587 rb
->lcd_drawrect(0, (8*TILE_HEIGHT
+YOFS
)
588 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
589 LCD_WIDTH
*tempscore
/LEVEL_PTS
+1,
590 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
594 rb
->snprintf(str
, 10, "%s %d", title
, bj
->level
);
595 rb
->lcd_putsxy(1, LCD_HEIGHT
-10, str
);
597 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
598 rb
->lcd_getstringsize(str
, &w
, &h
);
599 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
, LCD_HEIGHT
-10, str
);
601 #else /* square layout */
603 /* draw separator lines */
605 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
606 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, 8*TILE_HEIGHT
+YOFS
);
607 rb
->lcd_vline(LCD_WIDTH
/2, 8*TILE_HEIGHT
+YOFS
, LCD_HEIGHT
-1);
609 /* draw progress bar */
610 #ifdef HAVE_LCD_COLOR
611 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
613 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
614 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
615 *tempscore
/LEVEL_PTS
,
616 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
617 (8*TILE_HEIGHT
+YOFS
)*tempscore
/LEVEL_PTS
);
618 #ifdef HAVE_LCD_COLOR
619 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
620 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
621 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
622 *tempscore
/LEVEL_PTS
+1,
623 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
624 (8*TILE_HEIGHT
+YOFS
)*tempscore
/LEVEL_PTS
-1);
626 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
627 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
628 *tempscore
/LEVEL_PTS
,
629 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
630 (8*TILE_HEIGHT
+YOFS
)*tempscore
/LEVEL_PTS
+1);
634 rb
->snprintf(str
, 10, "%s %d", title
, bj
->level
);
635 rb
->lcd_putsxy(1, LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3, str
);
637 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
638 rb
->lcd_getstringsize(str
, &w
, &h
);
639 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
,
640 LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3, str
);
647 /*****************************************************************************
648 * jewels_showmenu() displays the chosen menu after performing the chosen
650 ******************************************************************************/
651 static enum menu_result
jewels_showmenu(struct jewels_menu
* menu
,
657 int extraline
= LCD_HEIGHT
<= ((menu
->itemcnt
+2)*FONT_HEIGHT
) ? 0 : 1;
659 /* handle menu command */
662 menu
->selected
= (menu
->selected
+1)%menu
->itemcnt
;
666 menu
->selected
= (menu
->selected
-1+menu
->itemcnt
)%menu
->itemcnt
;
670 return menu
->items
[menu
->selected
].res
;
676 /* clear menu area */
677 firstline
= (LCD_HEIGHT
/FONT_HEIGHT
-(menu
->itemcnt
+3))/2;
679 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
680 rb
->lcd_fillrect((LCD_WIDTH
-MENU_WIDTH
)/2, firstline
*FONT_HEIGHT
,
681 MENU_WIDTH
, (menu
->itemcnt
+3)*FONT_HEIGHT
);
682 rb
->lcd_set_drawmode(DRMODE_SOLID
);
685 rb
->lcd_drawrect((LCD_WIDTH
-MENU_WIDTH
)/2-1, firstline
*FONT_HEIGHT
-1,
686 MENU_WIDTH
+2, (menu
->itemcnt
+3)*FONT_HEIGHT
+2);
687 rb
->lcd_hline((LCD_WIDTH
-MENU_WIDTH
)/2-1,
688 (LCD_WIDTH
-MENU_WIDTH
)/2-1+MENU_WIDTH
+2,
689 (firstline
+1)*FONT_HEIGHT
);
692 /* draw menu items */
693 rb
->lcd_getstringsize(menu
->title
, &w
, &h
);
694 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, firstline
*FONT_HEIGHT
, menu
->title
);
696 for(i
=0; i
<menu
->itemcnt
; i
++) {
697 if(i
== menu
->selected
) {
698 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
700 rb
->lcd_putsxy((LCD_WIDTH
-MENU_WIDTH
)/2,
701 (firstline
+i
+1+extraline
)*FONT_HEIGHT
,
702 menu
->items
[i
].text
);
703 if(i
== menu
->selected
) {
704 rb
->lcd_set_drawmode(DRMODE_SOLID
);
708 adj
= (firstline
== 0 ? 0 : 1);
709 rb
->lcd_update_rect((LCD_WIDTH
-MENU_WIDTH
)/2-1, firstline
*FONT_HEIGHT
-adj
,
710 MENU_WIDTH
+2, (menu
->itemcnt
+3)*FONT_HEIGHT
+2*adj
);
714 /*****************************************************************************
715 * jewels_putjewels() makes the jewels fall to fill empty spots and adds
716 * new random jewels at the empty spots at the top of each row.
717 ******************************************************************************/
718 static void jewels_putjewels(struct game_context
* bj
){
721 long lasttick
, currenttick
;
723 /* loop to make all the jewels fall */
725 /* mark falling jewels and add new jewels to hidden top row*/
728 for(j
=0; j
<BJ_WIDTH
; j
++) {
729 if(bj
->playboard
[1][j
].type
== 0) {
730 bj
->playboard
[0][j
].type
= rb
->rand()%bj
->num_jewels
+1;
732 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
733 if(!mark
&& bj
->playboard
[i
+1][j
].type
== 0) {
737 if(mark
) bj
->playboard
[i
][j
].falling
= true;
739 /*if(bj->playboard[1][j].falling) {
740 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
741 bj->playboard[0][j].falling = true;
746 /* break if there are no falling jewels */
749 /* animate falling jewels */
750 lasttick
= *rb
->current_tick
;
752 for(k
=1; k
<=8; k
++) {
753 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
754 for(j
=0; j
<BJ_WIDTH
; j
++) {
755 if(bj
->playboard
[i
][j
].falling
&&
756 bj
->playboard
[i
][j
].type
!= 0) {
757 /* clear old position */
758 #ifdef HAVE_LCD_COLOR
760 rb
->lcd_set_foreground(rb
->lcd_get_background());
762 rb
->lcd_set_foreground(jewels_bkgd
[(i
-1+j
)%2]);
764 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
765 TILE_WIDTH
, TILE_HEIGHT
);
766 if(bj
->playboard
[i
+1][j
].type
== 0) {
767 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
768 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
769 TILE_WIDTH
, TILE_HEIGHT
);
772 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
773 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
774 TILE_WIDTH
, TILE_HEIGHT
);
775 if(bj
->playboard
[i
+1][j
].type
== 0) {
776 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
777 TILE_WIDTH
, TILE_HEIGHT
);
779 rb
->lcd_set_drawmode(DRMODE_SOLID
);
782 /* draw new position */
783 #ifdef HAVE_LCD_COLOR
784 rb
->lcd_bitmap_transparent_part(jewels
, 0,
785 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
786 TILE_WIDTH
, j
*TILE_WIDTH
,
787 (i
-1)*TILE_HEIGHT
+YOFS
+
788 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
789 TILE_WIDTH
, TILE_HEIGHT
);
791 rb
->lcd_bitmap_part(jewels
, 0,
792 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
793 TILE_WIDTH
, j
*TILE_WIDTH
,
794 (i
-1)*TILE_HEIGHT
+YOFS
+
795 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
796 TILE_WIDTH
, TILE_HEIGHT
);
802 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
805 /* framerate limiting */
806 currenttick
= *rb
->current_tick
;
807 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
808 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
812 lasttick
= currenttick
;
815 /* shift jewels down */
816 for(j
=0; j
<BJ_WIDTH
; j
++) {
817 for(i
=BJ_HEIGHT
-1; i
>=1; i
--) {
818 if(bj
->playboard
[i
-1][j
].falling
) {
819 bj
->playboard
[i
][j
].type
= bj
->playboard
[i
-1][j
].type
;
824 /* clear out top row */
825 for(j
=0; j
<BJ_WIDTH
; j
++) {
826 bj
->playboard
[0][j
].type
= 0;
829 /* mark everything not falling */
830 for(i
=0; i
<BJ_HEIGHT
; i
++) {
831 for(j
=0; j
<BJ_WIDTH
; j
++) {
832 bj
->playboard
[i
][j
].falling
= false;
838 /*****************************************************************************
839 * jewels_clearjewels() finds all the connected rows and columns and
840 * calculates and returns the points earned.
841 ******************************************************************************/
842 static unsigned int jewels_clearjewels(struct game_context
* bj
) {
845 unsigned int points
= 0;
847 /* check for connected rows */
848 for(i
=1; i
<BJ_HEIGHT
; i
++) {
851 for(j
=0; j
<BJ_WIDTH
; j
++) {
852 if(bj
->playboard
[i
][j
].type
== last
&&
853 bj
->playboard
[i
][j
].type
!= 0 &&
854 bj
->playboard
[i
][j
].type
<= MAX_NUM_JEWELS
) {
859 points
+= bj
->segments
;
860 bj
->playboard
[i
][j
].delete = true;
861 bj
->playboard
[i
][j
-1].delete = true;
862 bj
->playboard
[i
][j
-2].delete = true;
865 bj
->playboard
[i
][j
].delete = true;
869 last
= bj
->playboard
[i
][j
].type
;
874 /* check for connected columns */
875 for(j
=0; j
<BJ_WIDTH
; j
++) {
878 for(i
=1; i
<BJ_HEIGHT
; i
++) {
879 if(bj
->playboard
[i
][j
].type
!= 0 &&
880 bj
->playboard
[i
][j
].type
== last
&&
881 bj
->playboard
[i
][j
].type
<= MAX_NUM_JEWELS
) {
886 points
+= bj
->segments
;
887 bj
->playboard
[i
][j
].delete = true;
888 bj
->playboard
[i
-1][j
].delete = true;
889 bj
->playboard
[i
-2][j
].delete = true;
892 bj
->playboard
[i
][j
].delete = true;
896 last
= bj
->playboard
[i
][j
].type
;
901 /* clear deleted jewels */
902 for(i
=1; i
<BJ_HEIGHT
; i
++) {
903 for(j
=0; j
<BJ_WIDTH
; j
++) {
904 if(bj
->playboard
[i
][j
].delete) {
905 bj
->playboard
[i
][j
].delete = false;
906 bj
->playboard
[i
][j
].type
= 0;
914 /*****************************************************************************
915 * jewels_runboard() runs the board until it settles in a fixed state and
916 * returns points earned.
917 ******************************************************************************/
918 static unsigned int jewels_runboard(struct game_context
* bj
) {
919 unsigned int points
= 0;
924 while((ret
= jewels_clearjewels(bj
)) > 0) {
926 jewels_drawboard(bj
);
927 jewels_putjewels(bj
);
933 /*****************************************************************************
934 * jewels_swapjewels() swaps two jewels as long as it results in points and
935 * returns points earned.
936 ******************************************************************************/
937 static unsigned int jewels_swapjewels(struct game_context
* bj
,
938 int x
, int y
, int direc
) {
940 int horzmod
, vertmod
;
943 unsigned int points
= 0;
944 long lasttick
, currenttick
;
946 /* check for invalid parameters */
947 if(x
< 0 || x
>= BJ_WIDTH
|| y
< 0 || y
>= BJ_HEIGHT
-1 ||
948 direc
< SWAP_UP
|| direc
> SWAP_LEFT
) {
952 /* check for invalid directions */
953 if((x
== 0 && direc
== SWAP_LEFT
) ||
954 (x
== BJ_WIDTH
-1 && direc
== SWAP_RIGHT
) ||
955 (y
== 0 && direc
== SWAP_UP
) ||
956 (y
== BJ_HEIGHT
-2 && direc
== SWAP_DOWN
)) {
960 /* set direction variables */
966 movelen
= TILE_HEIGHT
;
970 movelen
= TILE_WIDTH
;
974 movelen
= TILE_HEIGHT
;
978 movelen
= TILE_WIDTH
;
983 lasttick
= *rb
->current_tick
;
985 /* animate swapping jewels */
986 for(k
=0; k
<=8; k
++) {
987 /* clear old position */
988 #ifdef HAVE_LCD_COLOR
989 rb
->lcd_set_foreground(jewels_bkgd
[(x
+y
)%2]);
990 rb
->lcd_fillrect(x
*TILE_WIDTH
,
992 TILE_WIDTH
, TILE_HEIGHT
);
993 rb
->lcd_set_foreground(jewels_bkgd
[(x
+horzmod
+y
+vertmod
)%2]);
994 rb
->lcd_fillrect((x
+horzmod
)*TILE_WIDTH
,
995 (y
+vertmod
)*TILE_HEIGHT
+YOFS
,
996 TILE_WIDTH
, TILE_HEIGHT
);
998 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
999 rb
->lcd_fillrect(x
*TILE_WIDTH
,
1001 TILE_WIDTH
, TILE_HEIGHT
);
1002 rb
->lcd_fillrect((x
+horzmod
)*TILE_WIDTH
,
1003 (y
+vertmod
)*TILE_HEIGHT
+YOFS
,
1004 TILE_WIDTH
, TILE_HEIGHT
);
1005 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1007 /* draw new position */
1008 #ifdef HAVE_LCD_COLOR
1009 rb
->lcd_bitmap_transparent_part(jewels
,
1010 0, TILE_HEIGHT
*(bj
->playboard
1011 [y
+1+vertmod
][x
+horzmod
].type
), TILE_WIDTH
,
1012 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
1013 ((((movelen
<<10)*k
)/8)>>10),
1014 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
1015 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1016 TILE_WIDTH
, TILE_HEIGHT
);
1017 rb
->lcd_bitmap_transparent_part(jewels
,
1018 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
1019 TILE_WIDTH
, x
*TILE_WIDTH
+horzmod
*
1020 ((((movelen
<<10)*k
)/8)>>10),
1021 y
*TILE_HEIGHT
+vertmod
*
1022 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1023 TILE_WIDTH
, TILE_HEIGHT
);
1025 rb
->lcd_bitmap_part(jewels
,
1026 0, TILE_HEIGHT
*(bj
->playboard
1027 [y
+1+vertmod
][x
+horzmod
].type
), TILE_WIDTH
,
1028 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
1029 ((((movelen
<<10)*k
)/8)>>10),
1030 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
1031 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1032 TILE_WIDTH
, TILE_HEIGHT
);
1033 rb
->lcd_set_drawmode(DRMODE_FG
);
1034 rb
->lcd_bitmap_part(jewels
,
1035 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
1036 TILE_WIDTH
, x
*TILE_WIDTH
+horzmod
*
1037 ((((movelen
<<10)*k
)/8)>>10),
1038 y
*TILE_HEIGHT
+vertmod
*
1039 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1040 TILE_WIDTH
, TILE_HEIGHT
);
1041 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1044 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
1047 /* framerate limiting */
1048 currenttick
= *rb
->current_tick
;
1049 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
1050 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
1054 lasttick
= currenttick
;
1058 int temp
= bj
->playboard
[y
+1][x
].type
;
1059 bj
->playboard
[y
+1][x
].type
=
1060 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
;
1061 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
= temp
;
1065 points
= jewels_runboard(bj
);
1076 /*****************************************************************************
1077 * jewels_movesavail() uses pattern matching to see if there are any
1078 * available move left.
1079 ******************************************************************************/
1080 static bool jewels_movesavail(struct game_context
* bj
) {
1085 for(i
=1; i
<BJ_HEIGHT
; i
++) {
1086 for(j
=0; j
<BJ_WIDTH
; j
++) {
1087 mytype
= bj
->playboard
[i
][j
].type
;
1088 if(mytype
== 0 || mytype
> MAX_NUM_JEWELS
) continue;
1090 /* check horizontal patterns */
1091 if(j
<= BJ_WIDTH
-3) {
1093 if(bj
->playboard
[i
-1][j
+1].type
== mytype
) {
1094 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1095 {moves
= true; break;}
1096 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1097 {moves
= true; break;}
1099 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1100 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1101 {moves
= true; break;}
1105 if(j
<= BJ_WIDTH
-4) {
1106 if(bj
->playboard
[i
][j
+3].type
== mytype
) {
1107 if(bj
->playboard
[i
][j
+1].type
== mytype
)
1108 {moves
= true; break;}
1109 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1110 {moves
= true; break;}
1114 if(i
< BJ_HEIGHT
-1) {
1115 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1116 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1117 {moves
= true; break;}
1119 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1120 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1121 {moves
= true; break;}
1122 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1123 {moves
= true; break;}
1128 /* check vertical patterns */
1129 if(i
<= BJ_HEIGHT
-3) {
1131 if(bj
->playboard
[i
+1][j
-1].type
== mytype
) {
1132 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1133 {moves
= true; break;}
1134 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1135 {moves
= true; break;}
1137 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1138 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1139 {moves
= true; break;}
1143 if(i
<= BJ_HEIGHT
-4) {
1144 if(bj
->playboard
[i
+3][j
].type
== mytype
) {
1145 if(bj
->playboard
[i
+1][j
].type
== mytype
)
1146 {moves
= true; break;}
1147 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1148 {moves
= true; break;}
1152 if(j
< BJ_WIDTH
-1) {
1153 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1154 if(bj
->playboard
[i
+2][j
+1].type
== mytype
)
1155 {moves
= true; break;}
1157 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1158 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1159 {moves
= true; break;}
1160 if (bj
->playboard
[i
+2][j
+1].type
== mytype
)
1161 {moves
= true; break;}
1173 /*****************************************************************************
1174 * jewels_puzzle_is_finished(bj) checks if the puzzle is finished.
1175 ******************************************************************************/
1176 static int jewels_puzzle_is_finished(struct game_context
* bj
) {
1178 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1179 for(j
=0; j
<BJ_WIDTH
; j
++) {
1180 int mytype
= bj
->playboard
[i
][j
].type
;
1181 if(mytype
>MAX_NUM_JEWELS
) {
1182 mytype
-= MAX_NUM_JEWELS
;
1183 if(mytype
&PUZZLE_TILE_UP
) {
1184 if(i
==0 || bj
->playboard
[i
-1][j
].type
<=MAX_NUM_JEWELS
||
1185 !((bj
->playboard
[i
-1][j
].type
-MAX_NUM_JEWELS
)
1189 if(mytype
&PUZZLE_TILE_DOWN
) {
1190 if(i
==BJ_HEIGHT
-1 ||
1191 bj
->playboard
[i
+1][j
].type
<=MAX_NUM_JEWELS
||
1192 !((bj
->playboard
[i
+1][j
].type
-MAX_NUM_JEWELS
)
1196 if(mytype
&PUZZLE_TILE_LEFT
) {
1197 if(j
==0 || bj
->playboard
[i
][j
-1].type
<=MAX_NUM_JEWELS
||
1198 !((bj
->playboard
[i
][j
-1].type
-MAX_NUM_JEWELS
)
1199 &PUZZLE_TILE_RIGHT
))
1202 if(mytype
&PUZZLE_TILE_RIGHT
) {
1204 bj
->playboard
[i
][j
+1].type
<=MAX_NUM_JEWELS
||
1205 !((bj
->playboard
[i
][j
+1].type
-MAX_NUM_JEWELS
)
1215 /*****************************************************************************
1216 * jewels_initlevel() initialises a level.
1217 ******************************************************************************/
1218 static unsigned int jewels_initlevel(struct game_context
* bj
) {
1219 unsigned int points
= 0;
1222 case GAME_TYPE_NORMAL
:
1223 bj
->num_jewels
= MAX_NUM_JEWELS
;
1226 case GAME_TYPE_PUZZLE
:
1229 struct puzzle_tile
*tile
;
1231 bj
->num_jewels
= puzzle_levels
[bj
->level
-1].num_jewels
;
1233 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1234 for(j
=0; j
<BJ_WIDTH
; j
++) {
1235 bj
->playboard
[i
][j
].type
= (rb
->rand()%bj
->num_jewels
)+1;
1236 bj
->playboard
[i
][j
].falling
= false;
1237 bj
->playboard
[i
][j
].delete = false;
1240 jewels_runboard(bj
);
1241 tile
= puzzle_levels
[bj
->level
-1].tiles
;
1242 for(i
=0; i
<puzzle_levels
[bj
->level
-1].num_tiles
; i
++, tile
++) {
1243 bj
->playboard
[tile
->y
+1][tile
->x
].type
= MAX_NUM_JEWELS
1250 jewels_drawboard(bj
);
1252 /* run the play board */
1253 jewels_putjewels(bj
);
1254 points
+= jewels_runboard(bj
);
1258 /*****************************************************************************
1259 * jewels_nextlevel() advances the game to the next level and returns
1261 ******************************************************************************/
1262 static void jewels_nextlevel(struct game_context
* bj
) {
1264 unsigned int points
= 0;
1267 case GAME_TYPE_NORMAL
:
1268 /* roll over score, change and display level */
1269 while(bj
->score
>= LEVEL_PTS
) {
1270 bj
->score
-= LEVEL_PTS
;
1272 rb
->splashf(HZ
*2, "Level %d", bj
->level
);
1273 jewels_drawboard(bj
);
1276 /* randomly clear some jewels */
1277 for(i
=0; i
<16; i
++) {
1281 if(bj
->playboard
[y
][x
].type
!= 0) {
1283 bj
->playboard
[y
][x
].type
= 0;
1288 case GAME_TYPE_PUZZLE
:
1290 if(bj
->level
>NUM_PUZZLE_LEVELS
) {
1291 rb
->splash(HZ
*2, "You win!");
1294 rb
->splashf(HZ
*2, "Level %d", bj
->level
);
1299 points
+= jewels_initlevel(bj
);
1300 bj
->score
+= points
;
1303 /*****************************************************************************
1304 * jewels_recordscore() inserts a high score into the high scores list and
1305 * returns the high score position.
1306 ******************************************************************************/
1307 static int jewels_recordscore(struct game_context
* bj
) {
1310 unsigned int current
, temp
;
1312 /* calculate total score */
1313 current
= (bj
->level
-1)*LEVEL_PTS
+bj
->score
;
1314 if(current
<= 0) return 0;
1316 /* insert the current score into the high scores */
1317 for(i
=0; i
<NUM_SCORES
; i
++) {
1318 if(current
>= bj
->highscores
[i
]) {
1323 temp
= bj
->highscores
[i
];
1324 bj
->highscores
[i
] = current
;
1332 /*****************************************************************************
1333 * jewels_loadscores() loads the high scores saved file.
1334 ******************************************************************************/
1335 static void jewels_loadscores(struct game_context
* bj
) {
1340 /* clear high scores */
1341 rb
->memset(bj
->highscores
, 0, sizeof(bj
->highscores
));
1343 /* open scores file */
1344 fd
= rb
->open(SCORE_FILE
, O_RDONLY
);
1347 /* read in high scores */
1348 if(rb
->read(fd
, bj
->highscores
, sizeof(bj
->highscores
)) <= 0) {
1349 /* scores are bad, reset */
1350 rb
->memset(bj
->highscores
, 0, sizeof(bj
->highscores
));
1356 /*****************************************************************************
1357 * jewels_savescores() saves the high scores saved file.
1358 ******************************************************************************/
1359 static void jewels_savescores(struct game_context
* bj
) {
1362 /* write out the high scores to the save file */
1363 fd
= rb
->open(SCORE_FILE
, O_WRONLY
|O_CREAT
);
1364 rb
->write(fd
, bj
->highscores
, sizeof(bj
->highscores
));
1369 /*****************************************************************************
1370 * jewels_loadgame() loads the saved game and returns load success.
1371 ******************************************************************************/
1372 static bool jewels_loadgame(struct game_context
* bj
) {
1374 bool loaded
= false;
1376 /* open game file */
1377 fd
= rb
->open(SAVE_FILE
, O_RDONLY
);
1378 if(fd
< 0) return loaded
;
1380 /* read in saved game */
1382 if(rb
->read(fd
, &bj
->score
, sizeof(bj
->score
)) <= 0) break;
1383 if(rb
->read(fd
, &bj
->level
, sizeof(bj
->level
)) <= 0) break;
1384 if(rb
->read(fd
, &bj
->type
, sizeof(bj
->type
)) <= 0) break;
1385 if(rb
->read(fd
, bj
->playboard
, sizeof(bj
->playboard
)) <= 0) break;
1393 /* delete saved file */
1394 rb
->remove(SAVE_FILE
);
1398 /*****************************************************************************
1399 * jewels_savegame() saves the current game state.
1400 ******************************************************************************/
1401 static void jewels_savegame(struct game_context
* bj
) {
1404 /* write out the game state to the save file */
1405 fd
= rb
->open(SAVE_FILE
, O_WRONLY
|O_CREAT
);
1406 rb
->write(fd
, &bj
->score
, sizeof(bj
->score
));
1407 rb
->write(fd
, &bj
->level
, sizeof(bj
->level
));
1408 rb
->write(fd
, &bj
->type
, sizeof(bj
->type
));
1409 rb
->write(fd
, bj
->playboard
, sizeof(bj
->playboard
));
1415 /*****************************************************************************
1416 * jewels_callback() is the default event handler callback which is called
1417 * on usb connect and shutdown.
1418 ******************************************************************************/
1419 static void jewels_callback(void* param
) {
1420 struct game_context
* bj
= (struct game_context
*) param
;
1422 rb
->splash(HZ
, "Saving high scores...");
1423 jewels_savescores(bj
);
1427 /*****************************************************************************
1428 * jewels_main() is the main game subroutine, it returns the final game status.
1429 ******************************************************************************/
1430 static int jewels_main(struct game_context
* bj
) {
1435 bool startgame
= false;
1436 bool inmenu
= false;
1437 bool selected
= false;
1438 enum menu_cmd cmd
= MCMD_NONE
;
1439 enum menu_result res
;
1441 /* the cursor coordinates */
1444 /* don't resume by default */
1447 /********************
1449 ********************/
1450 rb
->lcd_clear_display();
1453 res
= jewels_showmenu(&bjmenu
[0], cmd
);
1456 rb
->snprintf(str
, 18, "High Score: %d", bj
->highscores
[0]);
1457 rb
->lcd_getstringsize(str
, &w
, &h
);
1458 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, LCD_HEIGHT
-8, str
);
1464 bj
->type
= GAME_TYPE_NORMAL
;
1469 bj
->type
= GAME_TYPE_PUZZLE
;
1473 if(!jewels_loadgame(bj
)) {
1474 rb
->splash(HZ
*2, "Nothing to resume");
1475 rb
->lcd_clear_display();
1482 rb
->lcd_clear_display();
1484 /* room for a title? */
1486 if(LCD_HEIGHT
-NUM_SCORES
*8 >= 8) {
1487 rb
->snprintf(str
, 12, "%s", "High Scores");
1488 rb
->lcd_getstringsize(str
, &w
, &h
);
1489 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, 0, str
);
1493 /* print high scores */
1494 for(i
=0; i
<NUM_SCORES
; i
++) {
1495 rb
->snprintf(str
, 11, "#%02d: %d", i
+1, bj
->highscores
[i
]);
1496 rb
->lcd_puts(0, i
+j
, str
);
1501 button
= rb
->button_get(true);
1502 if(button
!= BUTTON_NONE
&& !(button
&BUTTON_REL
)) break;
1504 rb
->lcd_clear_display();
1508 /* welcome screen to display key bindings */
1509 rb
->lcd_clear_display();
1510 rb
->snprintf(str
, 5, "%s", "Help");
1511 rb
->lcd_getstringsize(str
, &w
, &h
);
1512 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, 0, str
);
1513 #if CONFIG_KEYPAD == RECORDER_PAD
1514 rb
->lcd_puts(0, 2, "Controls:");
1515 rb
->lcd_puts(0, 3, "Directions = move");
1516 rb
->lcd_puts(0, 4, "PLAY = select");
1517 rb
->lcd_puts(0, 5, "Long PLAY = menu");
1518 rb
->lcd_puts(0, 6, "OFF = cancel");
1519 #elif CONFIG_KEYPAD == ONDIO_PAD
1520 rb
->lcd_puts(0, 2, "Controls:");
1521 rb
->lcd_puts(0, 3, "Directions = move");
1522 rb
->lcd_puts(0, 4, "MENU = select");
1523 rb
->lcd_puts(0, 5, "Long MENU = menu");
1524 rb
->lcd_puts(0, 6, "OFF = cancel");
1525 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
1526 rb
->lcd_puts(0, 2, "Controls:");
1527 rb
->lcd_puts(0, 3, "Directions = move");
1528 rb
->lcd_puts(0, 4, "SELECT = select");
1529 rb
->lcd_puts(0, 5, "Long SELECT = menu");
1530 rb
->lcd_puts(0, 6, "PLAY = cancel");
1531 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
1532 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1533 rb
->lcd_puts(0, 3, "form connected segments");
1534 rb
->lcd_puts(0, 4, "of three or more of the");
1535 rb
->lcd_puts(0, 5, "same type.");
1536 rb
->lcd_puts(0, 7, "Controls:");
1537 rb
->lcd_puts(0, 8, "Directions to move");
1538 rb
->lcd_puts(0, 9, "SELECT to select");
1539 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1540 rb
->lcd_puts(0, 11, "OFF to cancel");
1541 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1542 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1543 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1544 rb
->lcd_puts(0, 3, "form connected segments");
1545 rb
->lcd_puts(0, 4, "of three or more of the");
1546 rb
->lcd_puts(0, 5, "same type.");
1547 rb
->lcd_puts(0, 7, "Controls:");
1548 rb
->lcd_puts(0, 8, "Directions or scroll to move");
1549 rb
->lcd_puts(0, 9, "SELECT to select");
1550 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1551 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
1552 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1553 rb
->lcd_puts(0, 3, "form connected segments");
1554 rb
->lcd_puts(0, 4, "of three or more of the");
1555 rb
->lcd_puts(0, 5, "same type.");
1556 rb
->lcd_puts(0, 7, "Controls:");
1557 rb
->lcd_puts(0, 8, "Directions to move");
1558 rb
->lcd_puts(0, 9, "SELECT to select");
1559 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1560 rb
->lcd_puts(0, 11, "PLAY to cancel");
1561 #elif CONFIG_KEYPAD == GIGABEAT_PAD \
1562 || CONFIG_KEYPAD == MROBE100_PAD
1563 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1564 rb
->lcd_puts(0, 3, "form connected segments");
1565 rb
->lcd_puts(0, 4, "of three or more of the");
1566 rb
->lcd_puts(0, 5, "same type.");
1567 rb
->lcd_puts(0, 7, "Controls:");
1568 rb
->lcd_puts(0, 8, "Directions to move");
1569 rb
->lcd_puts(0, 9, "SELECT to select");
1570 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1571 rb
->lcd_puts(0, 11, "POWER to cancel");
1572 #elif CONFIG_KEYPAD == SANSA_E200_PAD \
1573 || CONFIG_KEYPAD == SANSA_C200_PAD
1574 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1575 rb
->lcd_puts(0, 3, "form connected segments");
1576 rb
->lcd_puts(0, 4, "of three or more of the");
1577 rb
->lcd_puts(0, 5, "same type.");
1578 rb
->lcd_puts(0, 7, "Controls:");
1579 rb
->lcd_puts(0, 8, "Directions to move");
1580 rb
->lcd_puts(0, 9, "SELECT to select");
1581 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1582 rb
->lcd_puts(0, 11, "POWER to cancel");
1583 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1584 rb
->lcd_puts(0, 2, "Swap pairs of jewels");
1585 rb
->lcd_puts(0, 3, "to form connected");
1586 rb
->lcd_puts(0, 4, "segments of three or ");
1587 rb
->lcd_puts(0, 5, "more of the");
1588 rb
->lcd_puts(0, 6, "same type.");
1589 rb
->lcd_puts(0, 8, "Controls:");
1590 rb
->lcd_puts(0, 9, "Directions or scroll to move");
1591 rb
->lcd_puts(0, 10, "PLAY to select");
1592 rb
->lcd_puts(0, 11, "Long PLAY for menu");
1593 rb
->lcd_puts(0, 12, "POWER to cancel");
1594 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1595 rb
->lcd_puts(0, 2, "Swap pairs of jewels");
1596 rb
->lcd_puts(0, 3, "to form connected");
1597 rb
->lcd_puts(0, 4, "segments of three or ");
1598 rb
->lcd_puts(0, 5, "more of the");
1599 rb
->lcd_puts(0, 6, "same type.");
1600 rb
->lcd_puts(0, 8, "Controls:");
1601 rb
->lcd_puts(0, 9, "Directions or scroll to move");
1602 rb
->lcd_puts(0, 10, "PLAY to select");
1603 rb
->lcd_puts(0, 11, "Long PLAY for menu");
1604 rb
->lcd_puts(0, 12, "REC to cancel");
1605 #elif CONFIG_KEYPAD == COWOND2_PAD
1606 rb
->lcd_puts(0, 11, "POWER to cancel");
1607 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
1608 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1609 rb
->lcd_puts(0, 3, "form connected segments");
1610 rb
->lcd_puts(0, 4, "of three or more of the");
1611 rb
->lcd_puts(0, 5, "same type.");
1612 rb
->lcd_puts(0, 7, "Controls:");
1613 rb
->lcd_puts(0, 8, "Directions to move");
1614 rb
->lcd_puts(0, 9, "SELECT to select");
1615 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1616 rb
->lcd_puts(0, 11, "BACK to cancel");
1618 #warning: missing help text.
1621 #ifdef HAVE_TOUCHSCREEN
1622 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1623 rb
->lcd_puts(0, 3, "form connected segments");
1624 rb
->lcd_puts(0, 4, "of three or more of the");
1625 rb
->lcd_puts(0, 5, "same type.");
1626 rb
->lcd_puts(0, 7, "Controls:");
1627 rb
->lcd_puts(0, 8, "Directions to move");
1628 rb
->lcd_puts(0, 9, "CENTER to select");
1629 rb
->lcd_puts(0, 10, "Long CENTER to show menu");
1633 button
= rb
->button_get(true);
1634 if(button
!= BUTTON_NONE
&& !(button
&BUTTON_REL
)) break;
1636 rb
->lcd_clear_display();
1646 /* handle menu button presses */
1647 button
= rb
->button_get(true);
1649 #ifdef JEWELS_SCROLLWHEEL
1651 case (JEWELS_PREV
|BUTTON_REPEAT
):
1654 case (JEWELS_UP
|BUTTON_REPEAT
):
1658 #ifdef JEWELS_SCROLLWHEEL
1660 case (JEWELS_NEXT
|BUTTON_REPEAT
):
1663 case (JEWELS_DOWN
|BUTTON_REPEAT
):
1672 #ifdef JEWELS_CANCEL
1673 #ifdef JEWELS_RC_CANCEL
1674 case JEWELS_RC_CANCEL
:
1681 if(rb
->default_event_handler_ex(button
, jewels_callback
,
1682 (void*) bj
) == SYS_USB_CONNECTED
)
1688 /********************
1690 ********************/
1693 /********************
1695 ********************/
1696 bj
->score
+= jewels_initlevel(bj
);
1697 if (!jewels_movesavail(bj
)) {
1699 case GAME_TYPE_NORMAL
:
1702 case GAME_TYPE_PUZZLE
:
1704 rb
->splash(2*HZ
, "No more moves!");
1705 bj
->score
+= jewels_initlevel(bj
);
1706 } while(!jewels_movesavail(bj
));
1711 /**********************
1713 **********************/
1715 int no_movesavail
= false;
1718 /* refresh the board */
1719 jewels_drawboard(bj
);
1721 /* display the cursor */
1723 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
1724 rb
->lcd_fillrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1725 TILE_WIDTH
, TILE_HEIGHT
);
1726 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1728 rb
->lcd_drawrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1729 TILE_WIDTH
, TILE_HEIGHT
);
1731 rb
->lcd_update_rect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1732 TILE_WIDTH
, TILE_HEIGHT
);
1734 res
= jewels_showmenu(&bjmenu
[1], cmd
);
1743 playback_control(rb
, NULL
);
1744 rb
->lcd_setfont(FONT_SYSFIXED
);
1750 rb
->splash(HZ
, "Saving game...");
1751 jewels_savegame(bj
);
1758 return BJ_QUIT_FROM_GAME
;
1765 /* handle game button presses */
1766 button
= rb
->button_get(true);
1768 case JEWELS_LEFT
: /* move cursor left */
1769 case (JEWELS_LEFT
|BUTTON_REPEAT
):
1772 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_LEFT
);
1774 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1776 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1781 case JEWELS_RIGHT
: /* move cursor right */
1782 case (JEWELS_RIGHT
|BUTTON_REPEAT
):
1785 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_RIGHT
);
1787 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1796 case JEWELS_DOWN
: /* move cursor down */
1797 case (JEWELS_DOWN
|BUTTON_REPEAT
):
1800 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_DOWN
);
1802 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1804 y
= (y
+1)%(BJ_HEIGHT
-1);
1811 case JEWELS_UP
: /* move cursor up */
1812 case (JEWELS_UP
|BUTTON_REPEAT
):
1815 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_UP
);
1817 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1819 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1826 #ifdef JEWELS_SCROLLWHEEL
1827 case JEWELS_PREV
: /* scroll backwards */
1828 case (JEWELS_PREV
|BUTTON_REPEAT
):
1832 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1834 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1841 case JEWELS_NEXT
: /* scroll forwards */
1842 case (JEWELS_NEXT
|BUTTON_REPEAT
):
1845 if(x
== BJ_WIDTH
-1) {
1846 y
= (y
+1)%(BJ_HEIGHT
-1);
1856 case JEWELS_SELECT
: /* toggle selected */
1858 selected
= !selected
;
1864 case (JEWELS_SELECT
|BUTTON_REPEAT
): /* show menu */
1865 if(!inmenu
) inmenu
= true;
1868 #ifdef JEWELS_CANCEL
1869 #ifdef JEWELS_RC_CANCEL
1870 case JEWELS_RC_CANCEL
:
1872 case JEWELS_CANCEL
: /* end game */
1878 if(rb
->default_event_handler_ex(button
, jewels_callback
,
1879 (void*) bj
) == SYS_USB_CONNECTED
)
1884 if (no_movesavail
) {
1886 case GAME_TYPE_NORMAL
:
1889 case GAME_TYPE_PUZZLE
:
1891 rb
->splash(2*HZ
, "No more moves!");
1892 bj
->score
+= jewels_initlevel(bj
);
1893 } while(!jewels_movesavail(bj
));
1899 case GAME_TYPE_NORMAL
:
1900 if(bj
->score
>= LEVEL_PTS
)
1901 jewels_nextlevel(bj
);
1904 case GAME_TYPE_PUZZLE
:
1905 if(jewels_puzzle_is_finished(bj
))
1906 jewels_nextlevel(bj
);
1912 /*****************************************************************************
1913 * plugin entry point.
1914 ******************************************************************************/
1915 enum plugin_status
plugin_start(const struct plugin_api
* api
, const void* parameter
) {
1916 struct game_context bj
;
1924 /* end of plugin init */
1926 /* load high scores */
1927 jewels_loadscores(&bj
);
1929 rb
->lcd_setfont(FONT_SYSFIXED
);
1931 rb
->lcd_set_backdrop(NULL
);
1936 switch(jewels_main(&bj
)){
1938 rb
->splash(HZ
*2, "No more moves!");
1939 /* fall through to BJ_END */
1943 if((position
= jewels_recordscore(&bj
))) {
1944 rb
->snprintf(str
, 19, "New high score #%d!", position
);
1945 rb
->splash(HZ
*2, str
);
1951 rb
->lcd_setfont(FONT_UI
);
1952 return PLUGIN_USB_CONNECTED
;
1956 rb
->splash(HZ
, "Saving high scores...");
1957 jewels_savescores(&bj
);
1962 case BJ_QUIT_FROM_GAME
:
1964 if((position
= jewels_recordscore(&bj
))) {
1965 rb
->snprintf(str
, 19, "New high score #%d!", position
);
1966 rb
->splash(HZ
*2, str
);
1970 rb
->splash(HZ
, "Saving high scores...");
1971 jewels_savescores(&bj
);
1981 rb
->lcd_setfont(FONT_UI
);
1985 #endif /* HAVE_LCD_BITMAP */