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 "lib/display_text.h"
26 #include "lib/highscore.h"
27 #include "lib/playback_control.h"
28 #include "pluginbitmaps/jewels.h"
30 /* button definitions */
31 #if CONFIG_KEYPAD == RECORDER_PAD
32 #define JEWELS_UP BUTTON_UP
33 #define JEWELS_DOWN BUTTON_DOWN
34 #define JEWELS_LEFT BUTTON_LEFT
35 #define JEWELS_RIGHT BUTTON_RIGHT
36 #define JEWELS_SELECT BUTTON_PLAY
37 #define JEWELS_CANCEL BUTTON_OFF
38 #define HK_SELECT "PLAY"
39 #define HK_CANCEL "OFF"
41 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
42 #define JEWELS_UP BUTTON_UP
43 #define JEWELS_DOWN BUTTON_DOWN
44 #define JEWELS_LEFT BUTTON_LEFT
45 #define JEWELS_RIGHT BUTTON_RIGHT
46 #define JEWELS_SELECT BUTTON_SELECT
47 #define JEWELS_CANCEL BUTTON_OFF
48 #define HK_SELECT "SELECT"
49 #define HK_CANCEL "OFF"
51 #elif CONFIG_KEYPAD == ONDIO_PAD
52 #define JEWELS_UP BUTTON_UP
53 #define JEWELS_DOWN BUTTON_DOWN
54 #define JEWELS_LEFT BUTTON_LEFT
55 #define JEWELS_RIGHT BUTTON_RIGHT
56 #define JEWELS_SELECT BUTTON_MENU
57 #define JEWELS_CANCEL BUTTON_OFF
58 #define HK_SELECT "MENU"
59 #define HK_CANCEL "OFF"
61 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
62 #define JEWELS_UP BUTTON_UP
63 #define JEWELS_DOWN BUTTON_DOWN
64 #define JEWELS_LEFT BUTTON_LEFT
65 #define JEWELS_RIGHT BUTTON_RIGHT
66 #define JEWELS_SELECT BUTTON_SELECT
67 #define JEWELS_CANCEL BUTTON_OFF
68 #define JEWELS_RC_CANCEL BUTTON_RC_STOP
69 #define HK_SELECT "SELECT"
70 #define HK_CANCEL "OFF"
72 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
73 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
74 #define JEWELS_SCROLLWHEEL
75 #define JEWELS_UP BUTTON_MENU
76 #define JEWELS_DOWN BUTTON_PLAY
77 #define JEWELS_LEFT BUTTON_LEFT
78 #define JEWELS_RIGHT BUTTON_RIGHT
79 #define JEWELS_PREV BUTTON_SCROLL_BACK
80 #define JEWELS_NEXT BUTTON_SCROLL_FWD
81 #define JEWELS_SELECT BUTTON_SELECT
82 #define JEWELS_CANCEL (BUTTON_SELECT | BUTTON_MENU)
83 #define HK_SELECT "SELECT"
84 #define HK_CANCEL "SEL + MENU"
86 #elif (CONFIG_KEYPAD == IPOD_3G_PAD)
87 #define JEWELS_LEFT BUTTON_LEFT
88 #define JEWELS_RIGHT BUTTON_RIGHT
89 #define JEWELS_UP BUTTON_SCROLL_BACK
90 #define JEWELS_DOWN BUTTON_SCROLL_FWD
91 #define JEWELS_SELECT BUTTON_SELECT
92 #define JEWELS_CANCEL BUTTON_MENU
93 #define HK_SELECT "SELECT"
94 #define HK_CANCEL "MENU"
96 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
97 #define JEWELS_UP BUTTON_UP
98 #define JEWELS_DOWN BUTTON_DOWN
99 #define JEWELS_LEFT BUTTON_LEFT
100 #define JEWELS_RIGHT BUTTON_RIGHT
101 #define JEWELS_SELECT BUTTON_SELECT
102 #define JEWELS_CANCEL BUTTON_PLAY
103 #define HK_SELECT "SELECT"
104 #define HK_CANCEL "PLAY"
106 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
107 #define JEWELS_UP BUTTON_UP
108 #define JEWELS_DOWN BUTTON_DOWN
109 #define JEWELS_LEFT BUTTON_LEFT
110 #define JEWELS_RIGHT BUTTON_RIGHT
111 #define JEWELS_SELECT BUTTON_SELECT
112 #define JEWELS_CANCEL BUTTON_POWER
113 #define HK_SELECT "SELECT"
114 #define HK_CANCEL "POWER"
116 #elif CONFIG_KEYPAD == GIGABEAT_PAD
117 #define JEWELS_UP BUTTON_UP
118 #define JEWELS_DOWN BUTTON_DOWN
119 #define JEWELS_LEFT BUTTON_LEFT
120 #define JEWELS_RIGHT BUTTON_RIGHT
121 #define JEWELS_SELECT BUTTON_SELECT
122 #define JEWELS_CANCEL BUTTON_POWER
123 #define HK_SELECT "SELECT"
124 #define HK_CANCEL "POWER"
126 #elif CONFIG_KEYPAD == SANSA_E200_PAD
127 #define JEWELS_SCROLLWHEEL
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_PREV BUTTON_SCROLL_BACK
133 #define JEWELS_NEXT BUTTON_SCROLL_FWD
134 #define JEWELS_SELECT BUTTON_SELECT
135 #define JEWELS_CANCEL BUTTON_POWER
136 #define HK_SELECT "SELECT"
137 #define HK_CANCEL "POWER"
139 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
140 #define JEWELS_SCROLLWHEEL
141 #define JEWELS_UP BUTTON_UP
142 #define JEWELS_DOWN BUTTON_DOWN
143 #define JEWELS_LEFT BUTTON_LEFT
144 #define JEWELS_RIGHT BUTTON_RIGHT
145 #define JEWELS_PREV BUTTON_SCROLL_BACK
146 #define JEWELS_NEXT BUTTON_SCROLL_FWD
147 #define JEWELS_SELECT BUTTON_SELECT
148 #define JEWELS_CANCEL (BUTTON_HOME|BUTTON_REPEAT)
149 #define HK_SELECT "SELECT"
150 #define HK_CANCEL "HOME"
152 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
153 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
154 CONFIG_KEYPAD == SANSA_M200_PAD
155 #define JEWELS_UP BUTTON_UP
156 #define JEWELS_DOWN BUTTON_DOWN
157 #define JEWELS_LEFT BUTTON_LEFT
158 #define JEWELS_RIGHT BUTTON_RIGHT
159 #define JEWELS_SELECT BUTTON_SELECT
160 #define JEWELS_CANCEL BUTTON_POWER
161 #define HK_SELECT "SELECT"
162 #define HK_CANCEL "POWER"
164 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
165 #define JEWELS_UP BUTTON_SCROLL_UP
166 #define JEWELS_DOWN BUTTON_SCROLL_DOWN
167 #define JEWELS_LEFT BUTTON_LEFT
168 #define JEWELS_RIGHT BUTTON_RIGHT
169 #define JEWELS_SELECT BUTTON_PLAY
170 #define JEWELS_CANCEL BUTTON_POWER
171 #define HK_SELECT "PLAY"
172 #define HK_CANCEL "POWER"
174 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
175 #define JEWELS_UP BUTTON_UP
176 #define JEWELS_DOWN BUTTON_DOWN
177 #define JEWELS_LEFT BUTTON_LEFT
178 #define JEWELS_RIGHT BUTTON_RIGHT
179 #define JEWELS_SELECT BUTTON_SELECT
180 #define JEWELS_CANCEL BUTTON_BACK
181 #define HK_SELECT "SELECT"
182 #define HK_CANCEL "BACK"
184 #elif CONFIG_KEYPAD == MROBE100_PAD
185 #define JEWELS_UP BUTTON_UP
186 #define JEWELS_DOWN BUTTON_DOWN
187 #define JEWELS_LEFT BUTTON_LEFT
188 #define JEWELS_RIGHT BUTTON_RIGHT
189 #define JEWELS_SELECT BUTTON_SELECT
190 #define JEWELS_CANCEL BUTTON_POWER
191 #define HK_SELECT "SELECT"
192 #define HK_CANCEL "POWER"
194 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
195 #define JEWELS_UP BUTTON_RC_VOL_UP
196 #define JEWELS_DOWN BUTTON_RC_VOL_DOWN
197 #define JEWELS_LEFT BUTTON_RC_REW
198 #define JEWELS_RIGHT BUTTON_RC_FF
199 #define JEWELS_SELECT BUTTON_RC_PLAY
200 #define JEWELS_CANCEL BUTTON_RC_REC
201 #define HK_SELECT "PLAY"
202 #define HK_CANCEL "REC"
204 #define JEWELS_RC_CANCEL BUTTON_REC
206 #elif CONFIG_KEYPAD == COWON_D2_PAD
207 #define JEWELS_CANCEL BUTTON_POWER
208 #define HK_CANCEL "POWER"
210 #elif CONFIG_KEYPAD == IAUDIO67_PAD
211 #define JEWELS_UP BUTTON_STOP
212 #define JEWELS_DOWN BUTTON_PLAY
213 #define JEWELS_LEFT BUTTON_LEFT
214 #define JEWELS_RIGHT BUTTON_RIGHT
215 #define JEWELS_SELECT BUTTON_MENU
216 #define JEWELS_CANCEL BUTTON_POWER
217 #define HK_SELECT "MENU"
218 #define HK_CANCEL "POWER"
220 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
221 #define JEWELS_UP BUTTON_UP
222 #define JEWELS_DOWN BUTTON_DOWN
223 #define JEWELS_LEFT BUTTON_LEFT
224 #define JEWELS_RIGHT BUTTON_RIGHT
225 #define JEWELS_SELECT BUTTON_SELECT
226 #define JEWELS_CANCEL BUTTON_BACK
227 #define HK_SELECT "MIDDLE"
228 #define HK_CANCEL "BACK"
230 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
231 #define JEWELS_UP BUTTON_UP
232 #define JEWELS_DOWN BUTTON_DOWN
233 #define JEWELS_LEFT BUTTON_LEFT
234 #define JEWELS_RIGHT BUTTON_RIGHT
235 #define JEWELS_SELECT BUTTON_SELECT
236 #define JEWELS_CANCEL BUTTON_POWER
237 #define HK_SELECT "SELECT"
238 #define HK_CANCEL "POWER"
240 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
241 #define JEWELS_UP BUTTON_UP
242 #define JEWELS_DOWN BUTTON_DOWN
243 #define JEWELS_LEFT BUTTON_LEFT
244 #define JEWELS_RIGHT BUTTON_RIGHT
245 #define JEWELS_SELECT BUTTON_PLAY
246 #define JEWELS_CANCEL BUTTON_POWER
247 #define HK_SELECT "PLAY"
248 #define HK_CANCEL "POWER"
250 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
251 #define JEWELS_UP BUTTON_UP
252 #define JEWELS_DOWN BUTTON_DOWN
253 #define JEWELS_LEFT BUTTON_PREV
254 #define JEWELS_RIGHT BUTTON_NEXT
255 #define JEWELS_SELECT BUTTON_PLAY
256 #define JEWELS_CANCEL BUTTON_POWER
257 #define HK_SELECT "PLAY"
258 #define HK_CANCEL "POWER"
260 #elif CONFIG_KEYPAD == ONDAVX747_PAD || \
261 CONFIG_KEYPAD == ONDAVX777_PAD || \
262 CONFIG_KEYPAD == MROBE500_PAD
263 #define JEWELS_CANCEL BUTTON_POWER
264 #define HK_CANCEL "POWER"
266 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
267 #define JEWELS_UP BUTTON_UP
268 #define JEWELS_DOWN BUTTON_DOWN
269 #define JEWELS_LEFT BUTTON_LEFT
270 #define JEWELS_RIGHT BUTTON_RIGHT
271 #define JEWELS_SELECT BUTTON_PLAY
272 #define JEWELS_CANCEL BUTTON_REW
273 #define HK_SELECT "PLAY"
274 #define HK_CANCEL "REWIND"
276 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
277 #define JEWELS_UP BUTTON_UP
278 #define JEWELS_DOWN BUTTON_DOWN
279 #define JEWELS_LEFT BUTTON_PREV
280 #define JEWELS_RIGHT BUTTON_NEXT
281 #define JEWELS_SELECT BUTTON_OK
282 #define JEWELS_CANCEL BUTTON_REC
283 #define HK_SELECT "OK"
284 #define HK_CANCEL "REC"
286 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
287 #define JEWELS_LEFT BUTTON_VOL_DOWN
288 #define JEWELS_RIGHT BUTTON_VOL_UP
289 #define JEWELS_UP BUTTON_REW
290 #define JEWELS_DOWN BUTTON_FF
291 #define JEWELS_SELECT BUTTON_FUNC
292 #define JEWELS_CANCEL BUTTON_REC
293 #define HK_SELECT "FUNC"
294 #define HK_CANCEL "REC"
296 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
297 #define JEWELS_LEFT BUTTON_REW
298 #define JEWELS_RIGHT BUTTON_FF
299 #define JEWELS_UP BUTTON_UP
300 #define JEWELS_DOWN BUTTON_DOWN
301 #define JEWELS_SELECT BUTTON_ENTER
302 #define JEWELS_CANCEL BUTTON_MENU
303 #define HK_SELECT "ENTER"
304 #define HK_CANCEL "MENU"
307 #error No keymap defined!
310 #ifdef HAVE_TOUCHSCREEN
312 #define JEWELS_UP BUTTON_TOPMIDDLE
315 #define JEWELS_DOWN BUTTON_BOTTOMMIDDLE
318 #define JEWELS_LEFT BUTTON_MIDLEFT
321 #define JEWELS_RIGHT BUTTON_MIDRIGHT
323 #ifndef JEWELS_SELECT
324 #define JEWELS_SELECT BUTTON_CENTER
325 #define HK_SELECT "CENTER"
327 #ifndef JEWELS_CANCEL
328 #define JEWELS_CANCEL BUTTON_TOPLEFT
329 #define HK_CANCEL "TOPLEFT"
333 #define TILE_WIDTH BMPWIDTH_jewels
334 #define TILE_HEIGHT (BMPHEIGHT_jewels/23)
336 #if LCD_HEIGHT < LCD_WIDTH
337 /* This calculation assumes integer division w/ LCD_HEIGHT/TILE_HEIGHT */
338 #define YOFS LCD_HEIGHT-((LCD_HEIGHT/TILE_HEIGHT)*TILE_HEIGHT)
345 /* swap directions */
351 /* play board dimension */
355 /* next level threshold */
356 #define LEVEL_PTS 100
358 /* animation frame rate */
370 /* external bitmaps */
371 extern const fb_data jewels
[];
373 /* tile background colors */
374 #ifdef HAVE_LCD_COLOR
375 static const unsigned jewels_bkgd
[2] = {
376 LCD_RGBPACK(104, 63, 63),
377 LCD_RGBPACK(83, 44, 44)
382 * type is the jewel number 0-7
383 * falling if the jewel is falling
384 * delete marks the jewel for deletion
392 /* the game context struct
393 * score is the current level score
394 * segments is the number of cleared segments in the current run
395 * level is the current level
396 * tmp_type is the select type in the menu
397 * type is the game type (normal or puzzle)
398 * playboard is the game playing board (first row is hidden)
399 * num_jewels is the number of different jewels to use
401 struct game_context
{
403 unsigned int segments
;
406 unsigned int tmp_type
;
407 struct tile playboard
[BJ_HEIGHT
][BJ_WIDTH
];
408 unsigned int num_jewels
;
411 #define MAX_NUM_JEWELS 7
413 #define MAX_PUZZLE_TILES 4
414 #define NUM_PUZZLE_LEVELS 10
422 struct puzzle_level
{
423 unsigned int num_jewels
;
424 unsigned int num_tiles
;
425 struct puzzle_tile tiles
[MAX_PUZZLE_TILES
];
428 #define PUZZLE_TILE_UP 1
429 #define PUZZLE_TILE_DOWN 2
430 #define PUZZLE_TILE_LEFT 4
431 #define PUZZLE_TILE_RIGHT 8
433 struct puzzle_level puzzle_levels
[NUM_PUZZLE_LEVELS
] = {
434 { 5, 2, { {3, 3, PUZZLE_TILE_RIGHT
},
435 {4, 2, PUZZLE_TILE_LEFT
} } },
436 { 5, 2, { {3, 2, PUZZLE_TILE_DOWN
},
437 {3, 4, PUZZLE_TILE_UP
} } },
438 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
439 {3, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
440 {3, 6, PUZZLE_TILE_UP
} } },
441 { 6, 3, { {3, 2, PUZZLE_TILE_RIGHT
},
442 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
443 {5, 4, PUZZLE_TILE_LEFT
} } },
444 { 6, 2, { {3, 4, PUZZLE_TILE_RIGHT
},
445 {4, 2, PUZZLE_TILE_LEFT
} } },
446 { 6, 2, { {3, 2, PUZZLE_TILE_DOWN
},
447 {4, 4, PUZZLE_TILE_UP
} } },
448 { 7, 4, { {3, 2, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
449 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
450 {3, 4, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
451 {4, 4, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
452 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
453 {4, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
454 {3, 6, PUZZLE_TILE_UP
} } },
455 { 7, 3, { {2, 2, PUZZLE_TILE_RIGHT
},
456 {4, 1, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
457 {5, 4, PUZZLE_TILE_LEFT
} } },
458 { 7, 4, { {3, 0, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
459 {5, 0, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
460 {2, 7, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
461 {4, 7, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
464 #define SAVE_FILE PLUGIN_GAMES_DIR "/jewels.save"
465 #define SCORE_FILE PLUGIN_GAMES_DIR "/jewels.score"
466 struct highscore highscores
[NUM_SCORES
];
468 static bool resume_file
= false;
470 /*****************************************************************************
471 * jewels_setcolors() set the foreground and background colors.
472 ******************************************************************************/
473 static inline void jewels_setcolors(void) {
474 #ifdef HAVE_LCD_COLOR
475 rb
->lcd_set_background(LCD_RGBPACK(49, 26, 26));
476 rb
->lcd_set_foreground(LCD_RGBPACK(210, 181, 181));
480 /*****************************************************************************
481 * jewels_loadgame() loads the saved game and returns load success.
482 ******************************************************************************/
483 static bool jewels_loadgame(struct game_context
* bj
)
489 fd
= rb
->open(SAVE_FILE
, O_RDONLY
);
490 if(fd
< 0) return loaded
;
492 /* read in saved game */
494 if(rb
->read(fd
, &bj
->tmp_type
, sizeof(bj
->tmp_type
)) <= 0) break;
495 if(rb
->read(fd
, &bj
->type
, sizeof(bj
->type
)) <= 0) break;
496 if(rb
->read(fd
, &bj
->score
, sizeof(bj
->score
)) <= 0) break;
497 if(rb
->read(fd
, &bj
->level
, sizeof(bj
->level
)) <= 0) break;
498 if(rb
->read(fd
, &bj
->segments
, sizeof(bj
->segments
)) <= 0) break;
499 if(rb
->read(fd
, &bj
->num_jewels
, sizeof(bj
->num_jewels
)) <= 0) break;
500 if(rb
->read(fd
, bj
->playboard
, sizeof(bj
->playboard
)) <= 0) break;
510 /*****************************************************************************
511 * jewels_savegame() saves the current game state.
512 ******************************************************************************/
513 static void jewels_savegame(struct game_context
* bj
)
516 /* write out the game state to the save file */
517 fd
= rb
->open(SAVE_FILE
, O_WRONLY
|O_CREAT
, 0666);
520 rb
->write(fd
, &bj
->tmp_type
, sizeof(bj
->tmp_type
));
521 rb
->write(fd
, &bj
->type
, sizeof(bj
->type
));
522 rb
->write(fd
, &bj
->score
, sizeof(bj
->score
));
523 rb
->write(fd
, &bj
->level
, sizeof(bj
->level
));
524 rb
->write(fd
, &bj
->segments
, sizeof(bj
->segments
));
525 rb
->write(fd
, &bj
->num_jewels
, sizeof(bj
->num_jewels
));
526 rb
->write(fd
, bj
->playboard
, sizeof(bj
->playboard
));
530 /*****************************************************************************
531 * jewels_drawboard() redraws the entire game board.
532 ******************************************************************************/
533 static void jewels_drawboard(struct game_context
* bj
) {
536 unsigned int tempscore
;
538 char *title
= "Level";
541 if (bj
->type
== GAME_TYPE_NORMAL
) {
542 tempscore
= (bj
->score
>LEVEL_PTS
? LEVEL_PTS
: bj
->score
);
545 tempscore
= (bj
->level
>NUM_PUZZLE_LEVELS
? NUM_PUZZLE_LEVELS
: bj
->level
);
546 size
= NUM_PUZZLE_LEVELS
;
550 rb
->lcd_clear_display();
552 /* dispay playing board */
553 for(i
=0; i
<BJ_HEIGHT
-1; i
++){
554 for(j
=0; j
<BJ_WIDTH
; j
++){
555 #ifdef HAVE_LCD_COLOR
556 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
557 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
558 TILE_WIDTH
, TILE_HEIGHT
);
559 rb
->lcd_bitmap_transparent_part(jewels
,
560 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
562 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
563 j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
564 TILE_WIDTH
, TILE_HEIGHT
);
566 rb
->lcd_bitmap_part(jewels
,
567 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
569 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
570 j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
571 TILE_WIDTH
, TILE_HEIGHT
);
576 #if LCD_WIDTH > LCD_HEIGHT /* horizontal layout */
578 /* draw separator lines */
580 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, LCD_HEIGHT
-1);
582 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, 18);
583 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, LCD_HEIGHT
-10);
585 /* draw progress bar */
586 #ifdef HAVE_LCD_COLOR
587 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
589 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
590 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
592 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
593 ((LCD_HEIGHT
-10)-18)*tempscore
/size
);
594 #ifdef HAVE_LCD_COLOR
595 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
596 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
597 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
599 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
600 ((LCD_HEIGHT
-10)-18)*tempscore
/size
-1);
602 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
603 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*tempscore
/size
),
604 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
605 ((LCD_HEIGHT
-10)-18)*tempscore
/size
+1);
609 rb
->lcd_getstringsize(title
, &w
, &h
);
610 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 1, title
);
611 rb
->snprintf(str
, 4, "%d", bj
->level
);
612 rb
->lcd_getstringsize(str
, &w
, &h
);
613 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 10, str
);
615 if (bj
->type
== GAME_TYPE_NORMAL
) {
616 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
617 rb
->lcd_getstringsize(str
, &w
, &h
);
618 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2,
622 #elif LCD_WIDTH < LCD_HEIGHT /* vertical layout */
624 /* draw separator lines */
626 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
627 rb
->lcd_hline(0, LCD_WIDTH
-1, LCD_HEIGHT
-14);
628 rb
->lcd_vline(LCD_WIDTH
/2, LCD_HEIGHT
-14, LCD_HEIGHT
-1);
630 /* draw progress bar */
631 #ifdef HAVE_LCD_COLOR
632 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
634 rb
->lcd_fillrect(0, (8*TILE_HEIGHT
+YOFS
)
635 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
636 LCD_WIDTH
*tempscore
/size
,
637 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
638 #ifdef HAVE_LCD_COLOR
639 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
640 rb
->lcd_drawrect(1, (8*TILE_HEIGHT
+YOFS
)
641 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4+1,
642 LCD_WIDTH
*tempscore
/size
-1,
643 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2-2);
645 rb
->lcd_drawrect(0, (8*TILE_HEIGHT
+YOFS
)
646 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
647 LCD_WIDTH
*tempscore
/size
+1,
648 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
652 rb
->lcd_putsxyf(1, LCD_HEIGHT
-10, "%s %d", title
, bj
->level
);
654 if (bj
->type
== GAME_TYPE_NORMAL
) {
655 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
656 rb
->lcd_getstringsize(str
, &w
, &h
);
657 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
, LCD_HEIGHT
-10, str
);
661 #else /* square layout */
663 /* draw separator lines */
665 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
666 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, 8*TILE_HEIGHT
+YOFS
);
667 rb
->lcd_vline(LCD_WIDTH
/2, 8*TILE_HEIGHT
+YOFS
, LCD_HEIGHT
-1);
669 /* draw progress bar */
670 #ifdef HAVE_LCD_COLOR
671 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
673 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
674 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)*tempscore
/size
,
675 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
676 (8*TILE_HEIGHT
+YOFS
)*tempscore
/size
);
677 #ifdef HAVE_LCD_COLOR
678 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
679 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
680 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
682 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
683 (8*TILE_HEIGHT
+YOFS
)*tempscore
/size
-1);
685 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
686 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
688 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
689 (8*TILE_HEIGHT
+YOFS
)*tempscore
/size
+1);
693 rb
->lcd_putsxyf(1, LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3,"%s %d",
696 if (bj
->type
== GAME_TYPE_NORMAL
) {
697 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
698 rb
->lcd_getstringsize(str
, &w
, &h
);
699 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
,
700 LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3, str
);
708 /*****************************************************************************
709 * jewels_putjewels() makes the jewels fall to fill empty spots and adds
710 * new random jewels at the empty spots at the top of each row.
711 ******************************************************************************/
712 static void jewels_putjewels(struct game_context
* bj
){
715 long lasttick
, currenttick
;
717 /* loop to make all the jewels fall */
719 /* mark falling jewels and add new jewels to hidden top row*/
722 for(j
=0; j
<BJ_WIDTH
; j
++) {
723 if(bj
->playboard
[1][j
].type
== 0) {
724 bj
->playboard
[0][j
].type
= rb
->rand()%bj
->num_jewels
+1;
726 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
727 if(!mark
&& bj
->playboard
[i
+1][j
].type
== 0) {
731 if(mark
) bj
->playboard
[i
][j
].falling
= true;
733 /*if(bj->playboard[1][j].falling) {
734 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
735 bj->playboard[0][j].falling = true;
740 /* break if there are no falling jewels */
743 /* animate falling jewels */
744 lasttick
= *rb
->current_tick
;
746 for(k
=1; k
<=8; k
++) {
747 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
748 for(j
=0; j
<BJ_WIDTH
; j
++) {
749 if(bj
->playboard
[i
][j
].falling
&&
750 bj
->playboard
[i
][j
].type
!= 0) {
751 /* clear old position */
752 #ifdef HAVE_LCD_COLOR
754 rb
->lcd_set_foreground(rb
->lcd_get_background());
756 rb
->lcd_set_foreground(jewels_bkgd
[(i
-1+j
)%2]);
758 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
759 TILE_WIDTH
, TILE_HEIGHT
);
760 if(bj
->playboard
[i
+1][j
].type
== 0) {
761 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
762 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
763 TILE_WIDTH
, TILE_HEIGHT
);
766 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
767 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
768 TILE_WIDTH
, TILE_HEIGHT
);
769 if(bj
->playboard
[i
+1][j
].type
== 0) {
770 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
771 TILE_WIDTH
, TILE_HEIGHT
);
773 rb
->lcd_set_drawmode(DRMODE_SOLID
);
776 /* draw new position */
777 #ifdef HAVE_LCD_COLOR
778 rb
->lcd_bitmap_transparent_part(jewels
, 0,
779 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
784 (i
-1)*TILE_HEIGHT
+YOFS
+
785 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
786 TILE_WIDTH
, TILE_HEIGHT
);
788 rb
->lcd_bitmap_part(jewels
, 0,
789 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
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
),
1012 STRIDE( SCREEN_MAIN
,
1013 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
1014 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
1015 ((((movelen
<<10)*k
)/8)>>10),
1016 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
1017 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1018 TILE_WIDTH
, TILE_HEIGHT
);
1019 rb
->lcd_bitmap_transparent_part(jewels
,
1020 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
1021 STRIDE( SCREEN_MAIN
,
1022 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
1023 x
*TILE_WIDTH
+horzmod
*
1024 ((((movelen
<<10)*k
)/8)>>10),
1025 y
*TILE_HEIGHT
+vertmod
*
1026 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1027 TILE_WIDTH
, TILE_HEIGHT
);
1029 rb
->lcd_bitmap_part(jewels
,
1030 0, TILE_HEIGHT
*(bj
->playboard
1031 [y
+1+vertmod
][x
+horzmod
].type
),
1032 STRIDE( SCREEN_MAIN
,
1033 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
1034 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
1035 ((((movelen
<<10)*k
)/8)>>10),
1036 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
1037 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1038 TILE_WIDTH
, TILE_HEIGHT
);
1039 rb
->lcd_set_drawmode(DRMODE_FG
);
1040 rb
->lcd_bitmap_part(jewels
,
1041 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
1042 STRIDE( SCREEN_MAIN
,
1043 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
1044 x
*TILE_WIDTH
+horzmod
*
1045 ((((movelen
<<10)*k
)/8)>>10),
1046 y
*TILE_HEIGHT
+vertmod
*
1047 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1048 TILE_WIDTH
, TILE_HEIGHT
);
1049 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1052 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
1055 /* framerate limiting */
1056 currenttick
= *rb
->current_tick
;
1057 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
1058 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
1062 lasttick
= currenttick
;
1066 int temp
= bj
->playboard
[y
+1][x
].type
;
1067 bj
->playboard
[y
+1][x
].type
=
1068 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
;
1069 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
= temp
;
1073 points
= jewels_runboard(bj
);
1084 /*****************************************************************************
1085 * jewels_movesavail() uses pattern matching to see if there are any
1086 * available move left.
1087 ******************************************************************************/
1088 static bool jewels_movesavail(struct game_context
* bj
) {
1093 for(i
=1; i
<BJ_HEIGHT
; i
++) {
1094 for(j
=0; j
<BJ_WIDTH
; j
++) {
1095 mytype
= bj
->playboard
[i
][j
].type
;
1096 if(mytype
== 0 || mytype
> MAX_NUM_JEWELS
) continue;
1098 /* check horizontal patterns */
1099 if(j
<= BJ_WIDTH
-3) {
1101 if(bj
->playboard
[i
-1][j
+1].type
== mytype
) {
1102 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1103 {moves
= true; break;}
1104 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1105 {moves
= true; break;}
1107 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1108 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1109 {moves
= true; break;}
1113 if(j
<= BJ_WIDTH
-4) {
1114 if(bj
->playboard
[i
][j
+3].type
== mytype
) {
1115 if(bj
->playboard
[i
][j
+1].type
== mytype
)
1116 {moves
= true; break;}
1117 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1118 {moves
= true; break;}
1122 if(i
< BJ_HEIGHT
-1) {
1123 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1124 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1125 {moves
= true; break;}
1127 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1128 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1129 {moves
= true; break;}
1130 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1131 {moves
= true; break;}
1136 /* check vertical patterns */
1137 if(i
<= BJ_HEIGHT
-3) {
1139 if(bj
->playboard
[i
+1][j
-1].type
== mytype
) {
1140 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1141 {moves
= true; break;}
1142 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1143 {moves
= true; break;}
1145 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1146 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1147 {moves
= true; break;}
1151 if(i
<= BJ_HEIGHT
-4) {
1152 if(bj
->playboard
[i
+3][j
].type
== mytype
) {
1153 if(bj
->playboard
[i
+1][j
].type
== mytype
)
1154 {moves
= true; break;}
1155 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1156 {moves
= true; break;}
1160 if(j
< BJ_WIDTH
-1) {
1161 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1162 if(bj
->playboard
[i
+2][j
+1].type
== mytype
)
1163 {moves
= true; break;}
1165 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1166 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1167 {moves
= true; break;}
1168 if (bj
->playboard
[i
+2][j
+1].type
== mytype
)
1169 {moves
= true; break;}
1179 /*****************************************************************************
1180 * jewels_puzzle_is_finished() checks if the puzzle is finished.
1181 ******************************************************************************/
1182 static bool jewels_puzzle_is_finished(struct game_context
* bj
) {
1184 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1185 for(j
=0; j
<BJ_WIDTH
; j
++) {
1186 int mytype
= bj
->playboard
[i
][j
].type
;
1187 if(mytype
>MAX_NUM_JEWELS
) {
1188 mytype
-= MAX_NUM_JEWELS
;
1189 if(mytype
&PUZZLE_TILE_UP
) {
1190 if(i
==0 || bj
->playboard
[i
-1][j
].type
<=MAX_NUM_JEWELS
||
1191 !((bj
->playboard
[i
-1][j
].type
-MAX_NUM_JEWELS
)
1195 if(mytype
&PUZZLE_TILE_DOWN
) {
1196 if(i
==BJ_HEIGHT
-1 ||
1197 bj
->playboard
[i
+1][j
].type
<=MAX_NUM_JEWELS
||
1198 !((bj
->playboard
[i
+1][j
].type
-MAX_NUM_JEWELS
)
1202 if(mytype
&PUZZLE_TILE_LEFT
) {
1203 if(j
==0 || bj
->playboard
[i
][j
-1].type
<=MAX_NUM_JEWELS
||
1204 !((bj
->playboard
[i
][j
-1].type
-MAX_NUM_JEWELS
)
1205 &PUZZLE_TILE_RIGHT
))
1208 if(mytype
&PUZZLE_TILE_RIGHT
) {
1210 bj
->playboard
[i
][j
+1].type
<=MAX_NUM_JEWELS
||
1211 !((bj
->playboard
[i
][j
+1].type
-MAX_NUM_JEWELS
)
1221 /*****************************************************************************
1222 * jewels_initlevel() initialises a level.
1223 ******************************************************************************/
1224 static unsigned int jewels_initlevel(struct game_context
* bj
) {
1225 unsigned int points
= 0;
1228 case GAME_TYPE_NORMAL
:
1229 bj
->num_jewels
= MAX_NUM_JEWELS
;
1232 case GAME_TYPE_PUZZLE
:
1235 struct puzzle_tile
*tile
;
1237 bj
->num_jewels
= puzzle_levels
[bj
->level
-1].num_jewels
;
1239 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1240 for(j
=0; j
<BJ_WIDTH
; j
++) {
1241 bj
->playboard
[i
][j
].type
= (rb
->rand()%bj
->num_jewels
)+1;
1242 bj
->playboard
[i
][j
].falling
= false;
1243 bj
->playboard
[i
][j
].delete = false;
1246 jewels_runboard(bj
);
1247 tile
= puzzle_levels
[bj
->level
-1].tiles
;
1248 for(i
=0; i
<puzzle_levels
[bj
->level
-1].num_tiles
; i
++, tile
++) {
1249 bj
->playboard
[tile
->y
+1][tile
->x
].type
= MAX_NUM_JEWELS
1256 jewels_drawboard(bj
);
1258 /* run the play board */
1259 jewels_putjewels(bj
);
1260 points
+= jewels_runboard(bj
);
1264 /*****************************************************************************
1265 * jewels_init() initializes jewels data structures.
1266 ******************************************************************************/
1267 static void jewels_init(struct game_context
* bj
) {
1268 /* seed the rand generator */
1269 rb
->srand(*rb
->current_tick
);
1271 bj
->type
= bj
->tmp_type
;
1278 /* clear playing board */
1279 rb
->memset(bj
->playboard
, 0, sizeof(bj
->playboard
));
1281 bj
->score
+= jewels_initlevel(bj
);
1282 } while(!jewels_movesavail(bj
));
1285 /*****************************************************************************
1286 * jewels_nextlevel() advances the game to the next bj->level and returns
1288 ******************************************************************************/
1289 static void jewels_nextlevel(struct game_context
* bj
) {
1291 unsigned int points
= 0;
1294 case GAME_TYPE_NORMAL
:
1295 /* roll over score, change and display level */
1296 while(bj
->score
>= LEVEL_PTS
) {
1297 bj
->score
-= LEVEL_PTS
;
1299 rb
->splashf(HZ
*2, "Level %d", bj
->level
);
1300 jewels_drawboard(bj
);
1303 /* randomly clear some jewels */
1304 for(i
=0; i
<16; i
++) {
1308 if(bj
->playboard
[y
][x
].type
!= 0) {
1310 bj
->playboard
[y
][x
].type
= 0;
1315 case GAME_TYPE_PUZZLE
:
1317 rb
->splashf(HZ
*2, "Level %d", bj
->level
);
1321 points
+= jewels_initlevel(bj
);
1322 bj
->score
+= points
;
1325 static bool jewels_help(void)
1327 static char *help_text
[] = {
1328 "Jewels", "", "Aim", "",
1329 "Swap", "pairs", "of", "jewels", "to", "form", "connected",
1330 "segments", "of", "three", "or", "more", "of", "the", "same",
1332 "The", "goal", "of", "the", "game", "is", "to", "score", "as", "many",
1333 "points", "as", "possible", "before", "running", "out", "of",
1334 "available", "moves.", "", "",
1337 #ifdef JEWELS_SCROLLWHEEL
1341 HK_SELECT
, "to", "select", "",
1342 HK_CANCEL
, "to", "go", "to", "menu"
1344 static struct style_text formation
[]={
1345 { 0, TEXT_CENTER
|TEXT_UNDERLINE
},
1351 rb
->lcd_setfont(FONT_UI
);
1352 if (display_text(ARRAYLEN(help_text
), help_text
, formation
, NULL
, true))
1354 rb
->lcd_setfont(FONT_SYSFIXED
);
1359 static bool _ingame
;
1360 static int jewels_menu_cb(int action
, const struct menu_item_ex
*this_item
)
1362 int i
= ((intptr_t)this_item
);
1363 if(action
== ACTION_REQUEST_MENUITEM
1364 && !_ingame
&& (i
==0 || i
==6))
1365 return ACTION_EXIT_MENUITEM
;
1368 /*****************************************************************************
1369 * jewels_game_menu() shows the game menu.
1370 ******************************************************************************/
1371 static int jewels_game_menu(struct game_context
* bj
, bool ingame
)
1373 rb
->button_clear_queue();
1378 static struct opt_items mode
[] = {
1383 MENUITEM_STRINGLIST (main_menu
, "Jewels Menu", jewels_menu_cb
,
1390 "Quit without Saving",
1394 switch (rb
->do_menu(&main_menu
, &choice
, NULL
, false)) {
1398 rb
->remove(SAVE_FILE
);
1404 rb
->set_option("Mode", &bj
->tmp_type
, INT
, mode
, 2, NULL
);
1411 highscore_show(-1, highscores
, NUM_SCORES
, true);
1414 playback_control(NULL
);
1420 rb
->splash(HZ
*1, "Saving game ...");
1421 jewels_savegame(bj
);
1424 case MENU_ATTACHED_USB
:
1432 static int jewels_main(struct game_context
* bj
) {
1435 bool selected
= false;
1439 bool loaded
= jewels_loadgame(bj
);
1440 resume_file
= loaded
;
1441 if (jewels_game_menu(bj
, loaded
)!=0)
1444 resume_file
= false;
1446 no_movesavail
= false;
1448 /* refresh the board */
1449 jewels_drawboard(bj
);
1451 /* display the cursor */
1453 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
1454 rb
->lcd_fillrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1455 TILE_WIDTH
, TILE_HEIGHT
);
1456 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1458 rb
->lcd_drawrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1459 TILE_WIDTH
, TILE_HEIGHT
);
1461 rb
->lcd_update_rect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1462 TILE_WIDTH
, TILE_HEIGHT
);
1464 /* handle game button presses */
1466 button
= rb
->button_get(true);
1468 case JEWELS_LEFT
: /* move cursor left */
1469 case (JEWELS_LEFT
|BUTTON_REPEAT
):
1471 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_LEFT
);
1473 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1475 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1479 case JEWELS_RIGHT
: /* move cursor right */
1480 case (JEWELS_RIGHT
|BUTTON_REPEAT
):
1482 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_RIGHT
);
1484 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1490 case JEWELS_DOWN
: /* move cursor down */
1491 case (JEWELS_DOWN
|BUTTON_REPEAT
):
1493 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_DOWN
);
1495 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1497 y
= (y
+1)%(BJ_HEIGHT
-1);
1501 case JEWELS_UP
: /* move cursor up */
1502 case (JEWELS_UP
|BUTTON_REPEAT
):
1504 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_UP
);
1506 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1508 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1512 #ifdef JEWELS_SCROLLWHEEL
1513 case JEWELS_PREV
: /* scroll backwards */
1514 case (JEWELS_PREV
|BUTTON_REPEAT
):
1517 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1519 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1523 case JEWELS_NEXT
: /* scroll forwards */
1524 case (JEWELS_NEXT
|BUTTON_REPEAT
):
1526 if(x
== BJ_WIDTH
-1) {
1527 y
= (y
+1)%(BJ_HEIGHT
-1);
1534 case JEWELS_SELECT
: /* toggle selected */
1535 selected
= !selected
;
1538 #ifdef JEWELS_RC_CANCEL
1539 case JEWELS_RC_CANCEL
:
1541 case JEWELS_CANCEL
: /* end game */
1542 if (jewels_game_menu(bj
, true)!=0)
1547 if (rb
->default_event_handler (button
) == SYS_USB_CONNECTED
)
1548 return PLUGIN_USB_CONNECTED
;
1553 case GAME_TYPE_NORMAL
:
1554 if(bj
->score
>= LEVEL_PTS
)
1555 jewels_nextlevel(bj
);
1557 case GAME_TYPE_PUZZLE
:
1558 if (jewels_puzzle_is_finished(bj
)) {
1559 if (bj
->level
< NUM_PUZZLE_LEVELS
) {
1560 jewels_nextlevel(bj
);
1562 rb
->splash(2*HZ
, "Congratulations!");
1563 rb
->splash(2*HZ
, "You have finished the game!");
1564 if (jewels_game_menu(bj
, false)!=0) {
1572 if (no_movesavail
) {
1574 case GAME_TYPE_NORMAL
:
1575 rb
->splash(HZ
*2, "Game Over!");
1576 rb
->lcd_clear_display();
1577 bj
->score
+= (bj
->level
-1)*LEVEL_PTS
;
1578 position
=highscore_update(bj
->score
, bj
->level
, "",
1579 highscores
, NUM_SCORES
);
1583 rb
->splash(HZ
*2, "New High Score");
1584 highscore_show(position
, highscores
, NUM_SCORES
, true);
1587 case GAME_TYPE_PUZZLE
:
1588 rb
->splash(2*HZ
, "Game Over");
1591 if (jewels_game_menu(bj
, false)!=0) {
1598 /* this is the plugin entry point */
1599 enum plugin_status
plugin_start(const void* parameter
)
1603 /* load high scores */
1604 highscore_load(SCORE_FILE
, highscores
, NUM_SCORES
);
1606 rb
->lcd_setfont(FONT_SYSFIXED
);
1608 rb
->lcd_set_backdrop(NULL
);
1611 struct game_context bj
;
1612 bj
.tmp_type
= GAME_TYPE_NORMAL
;
1614 highscore_save(SCORE_FILE
, highscores
, NUM_SCORES
);
1615 rb
->lcd_setfont(FONT_UI
);