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 (CONFIG_KEYPAD == SANSA_CONNECT_PAD)
128 #define JEWELS_SCROLLWHEEL
129 #define JEWELS_UP BUTTON_UP
130 #define JEWELS_DOWN BUTTON_DOWN
131 #define JEWELS_LEFT BUTTON_LEFT
132 #define JEWELS_RIGHT BUTTON_RIGHT
133 #define JEWELS_PREV BUTTON_SCROLL_BACK
134 #define JEWELS_NEXT BUTTON_SCROLL_FWD
135 #define JEWELS_SELECT BUTTON_SELECT
136 #define JEWELS_CANCEL BUTTON_POWER
137 #define HK_SELECT "SELECT"
138 #define HK_CANCEL "POWER"
140 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
141 #define JEWELS_SCROLLWHEEL
142 #define JEWELS_UP BUTTON_UP
143 #define JEWELS_DOWN BUTTON_DOWN
144 #define JEWELS_LEFT BUTTON_LEFT
145 #define JEWELS_RIGHT BUTTON_RIGHT
146 #define JEWELS_PREV BUTTON_SCROLL_BACK
147 #define JEWELS_NEXT BUTTON_SCROLL_FWD
148 #define JEWELS_SELECT BUTTON_SELECT
149 #define JEWELS_CANCEL (BUTTON_HOME|BUTTON_REPEAT)
150 #define HK_SELECT "SELECT"
151 #define HK_CANCEL "HOME"
153 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
154 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
155 CONFIG_KEYPAD == SANSA_M200_PAD
156 #define JEWELS_UP BUTTON_UP
157 #define JEWELS_DOWN BUTTON_DOWN
158 #define JEWELS_LEFT BUTTON_LEFT
159 #define JEWELS_RIGHT BUTTON_RIGHT
160 #define JEWELS_SELECT BUTTON_SELECT
161 #define JEWELS_CANCEL BUTTON_POWER
162 #define HK_SELECT "SELECT"
163 #define HK_CANCEL "POWER"
165 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
166 #define JEWELS_UP BUTTON_SCROLL_UP
167 #define JEWELS_DOWN BUTTON_SCROLL_DOWN
168 #define JEWELS_LEFT BUTTON_LEFT
169 #define JEWELS_RIGHT BUTTON_RIGHT
170 #define JEWELS_SELECT BUTTON_PLAY
171 #define JEWELS_CANCEL BUTTON_POWER
172 #define HK_SELECT "PLAY"
173 #define HK_CANCEL "POWER"
175 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD || \
176 CONFIG_KEYPAD == SAMSUNG_YPR0_PAD
177 #define JEWELS_UP BUTTON_UP
178 #define JEWELS_DOWN BUTTON_DOWN
179 #define JEWELS_LEFT BUTTON_LEFT
180 #define JEWELS_RIGHT BUTTON_RIGHT
181 #define JEWELS_SELECT BUTTON_SELECT
182 #define JEWELS_CANCEL BUTTON_BACK
183 #define HK_SELECT "SELECT"
184 #define HK_CANCEL "BACK"
186 #elif CONFIG_KEYPAD == MROBE100_PAD
187 #define JEWELS_UP BUTTON_UP
188 #define JEWELS_DOWN BUTTON_DOWN
189 #define JEWELS_LEFT BUTTON_LEFT
190 #define JEWELS_RIGHT BUTTON_RIGHT
191 #define JEWELS_SELECT BUTTON_SELECT
192 #define JEWELS_CANCEL BUTTON_POWER
193 #define HK_SELECT "SELECT"
194 #define HK_CANCEL "POWER"
196 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
197 #define JEWELS_UP BUTTON_RC_VOL_UP
198 #define JEWELS_DOWN BUTTON_RC_VOL_DOWN
199 #define JEWELS_LEFT BUTTON_RC_REW
200 #define JEWELS_RIGHT BUTTON_RC_FF
201 #define JEWELS_SELECT BUTTON_RC_PLAY
202 #define JEWELS_CANCEL BUTTON_RC_REC
203 #define HK_SELECT "PLAY"
204 #define HK_CANCEL "REC"
206 #define JEWELS_RC_CANCEL BUTTON_REC
208 #elif CONFIG_KEYPAD == COWON_D2_PAD
209 #define JEWELS_CANCEL BUTTON_POWER
210 #define HK_CANCEL "POWER"
212 #elif CONFIG_KEYPAD == IAUDIO67_PAD
213 #define JEWELS_UP BUTTON_STOP
214 #define JEWELS_DOWN BUTTON_PLAY
215 #define JEWELS_LEFT BUTTON_LEFT
216 #define JEWELS_RIGHT BUTTON_RIGHT
217 #define JEWELS_SELECT BUTTON_MENU
218 #define JEWELS_CANCEL BUTTON_POWER
219 #define HK_SELECT "MENU"
220 #define HK_CANCEL "POWER"
222 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
223 #define JEWELS_UP BUTTON_UP
224 #define JEWELS_DOWN BUTTON_DOWN
225 #define JEWELS_LEFT BUTTON_LEFT
226 #define JEWELS_RIGHT BUTTON_RIGHT
227 #define JEWELS_SELECT BUTTON_SELECT
228 #define JEWELS_CANCEL BUTTON_BACK
229 #define HK_SELECT "MIDDLE"
230 #define HK_CANCEL "BACK"
232 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
233 #define JEWELS_UP BUTTON_UP
234 #define JEWELS_DOWN BUTTON_DOWN
235 #define JEWELS_LEFT BUTTON_LEFT
236 #define JEWELS_RIGHT BUTTON_RIGHT
237 #define JEWELS_SELECT BUTTON_SELECT
238 #define JEWELS_CANCEL BUTTON_POWER
239 #define HK_SELECT "SELECT"
240 #define HK_CANCEL "POWER"
242 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
243 #define JEWELS_UP BUTTON_UP
244 #define JEWELS_DOWN BUTTON_DOWN
245 #define JEWELS_LEFT BUTTON_LEFT
246 #define JEWELS_RIGHT BUTTON_RIGHT
247 #define JEWELS_SELECT BUTTON_PLAY
248 #define JEWELS_CANCEL BUTTON_POWER
249 #define HK_SELECT "PLAY"
250 #define HK_CANCEL "POWER"
252 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
253 #define JEWELS_UP BUTTON_UP
254 #define JEWELS_DOWN BUTTON_DOWN
255 #define JEWELS_LEFT BUTTON_PREV
256 #define JEWELS_RIGHT BUTTON_NEXT
257 #define JEWELS_SELECT BUTTON_PLAY
258 #define JEWELS_CANCEL BUTTON_POWER
259 #define HK_SELECT "PLAY"
260 #define HK_CANCEL "POWER"
262 #elif CONFIG_KEYPAD == ONDAVX747_PAD || \
263 CONFIG_KEYPAD == ONDAVX777_PAD || \
264 CONFIG_KEYPAD == MROBE500_PAD
265 #define JEWELS_CANCEL BUTTON_POWER
266 #define HK_CANCEL "POWER"
268 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
269 #define JEWELS_UP BUTTON_UP
270 #define JEWELS_DOWN BUTTON_DOWN
271 #define JEWELS_LEFT BUTTON_LEFT
272 #define JEWELS_RIGHT BUTTON_RIGHT
273 #define JEWELS_SELECT BUTTON_PLAY
274 #define JEWELS_CANCEL BUTTON_REW
275 #define HK_SELECT "PLAY"
276 #define HK_CANCEL "REWIND"
278 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
279 #define JEWELS_UP BUTTON_UP
280 #define JEWELS_DOWN BUTTON_DOWN
281 #define JEWELS_LEFT BUTTON_PREV
282 #define JEWELS_RIGHT BUTTON_NEXT
283 #define JEWELS_SELECT BUTTON_OK
284 #define JEWELS_CANCEL BUTTON_REC
285 #define HK_SELECT "OK"
286 #define HK_CANCEL "REC"
288 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
289 #define JEWELS_LEFT BUTTON_VOL_DOWN
290 #define JEWELS_RIGHT BUTTON_VOL_UP
291 #define JEWELS_UP BUTTON_REW
292 #define JEWELS_DOWN BUTTON_FF
293 #define JEWELS_SELECT BUTTON_FUNC
294 #define JEWELS_CANCEL BUTTON_REC
295 #define HK_SELECT "FUNC"
296 #define HK_CANCEL "REC"
298 #elif CONFIG_KEYPAD == MPIO_HD300_PAD
299 #define JEWELS_LEFT BUTTON_REW
300 #define JEWELS_RIGHT BUTTON_FF
301 #define JEWELS_UP BUTTON_UP
302 #define JEWELS_DOWN BUTTON_DOWN
303 #define JEWELS_SELECT BUTTON_ENTER
304 #define JEWELS_CANCEL BUTTON_MENU
305 #define HK_SELECT "ENTER"
306 #define HK_CANCEL "MENU"
308 #elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
309 #define JEWELS_LEFT BUTTON_LEFT
310 #define JEWELS_RIGHT BUTTON_RIGHT
311 #define JEWELS_UP BUTTON_UP
312 #define JEWELS_DOWN BUTTON_DOWN
313 #define JEWELS_SELECT BUTTON_SELECT
314 #define JEWELS_CANCEL BUTTON_POWER
315 #define HK_SELECT "SELECT"
316 #define HK_CANCEL "POWER"
318 #elif (CONFIG_KEYPAD == HM60X_PAD) || \
319 (CONFIG_KEYPAD == HM801_PAD)
320 #define JEWELS_LEFT BUTTON_LEFT
321 #define JEWELS_RIGHT BUTTON_RIGHT
322 #define JEWELS_UP BUTTON_UP
323 #define JEWELS_DOWN BUTTON_DOWN
324 #define JEWELS_SELECT BUTTON_SELECT
325 #define JEWELS_CANCEL BUTTON_POWER
326 #define HK_SELECT "SELECT"
327 #define HK_CANCEL "POWER"
330 #error No keymap defined!
333 #ifdef HAVE_TOUCHSCREEN
335 #define JEWELS_UP BUTTON_TOPMIDDLE
338 #define JEWELS_DOWN BUTTON_BOTTOMMIDDLE
341 #define JEWELS_LEFT BUTTON_MIDLEFT
344 #define JEWELS_RIGHT BUTTON_MIDRIGHT
346 #ifndef JEWELS_SELECT
347 #define JEWELS_SELECT BUTTON_CENTER
348 #define HK_SELECT "CENTER"
350 #ifndef JEWELS_CANCEL
351 #define JEWELS_CANCEL BUTTON_TOPLEFT
352 #define HK_CANCEL "TOPLEFT"
356 #define TILE_WIDTH BMPWIDTH_jewels
357 #define TILE_HEIGHT (BMPHEIGHT_jewels/23)
359 #if LCD_HEIGHT < LCD_WIDTH
360 /* This calculation assumes integer division w/ LCD_HEIGHT/TILE_HEIGHT */
361 #define YOFS LCD_HEIGHT-((LCD_HEIGHT/TILE_HEIGHT)*TILE_HEIGHT)
368 /* swap directions */
374 /* play board dimension */
378 /* next level threshold */
379 #define LEVEL_PTS 100
381 /* animation frame rate */
393 /* external bitmaps */
394 extern const fb_data jewels
[];
396 /* tile background colors */
397 #ifdef HAVE_LCD_COLOR
398 static const unsigned jewels_bkgd
[2] = {
399 LCD_RGBPACK(104, 63, 63),
400 LCD_RGBPACK(83, 44, 44)
405 * type is the jewel number 0-7
406 * falling if the jewel is falling
407 * delete marks the jewel for deletion
415 /* the game context struct
416 * score is the current level score
417 * segments is the number of cleared segments in the current run
418 * level is the current level
419 * tmp_type is the select type in the menu
420 * type is the game type (normal or puzzle)
421 * playboard is the game playing board (first row is hidden)
422 * num_jewels is the number of different jewels to use
424 struct game_context
{
426 unsigned int segments
;
429 unsigned int tmp_type
;
430 struct tile playboard
[BJ_HEIGHT
][BJ_WIDTH
];
431 unsigned int num_jewels
;
434 #define MAX_NUM_JEWELS 7
436 #define MAX_PUZZLE_TILES 4
437 #define NUM_PUZZLE_LEVELS 10
445 struct puzzle_level
{
446 unsigned int num_jewels
;
447 unsigned int num_tiles
;
448 struct puzzle_tile tiles
[MAX_PUZZLE_TILES
];
451 #define PUZZLE_TILE_UP 1
452 #define PUZZLE_TILE_DOWN 2
453 #define PUZZLE_TILE_LEFT 4
454 #define PUZZLE_TILE_RIGHT 8
456 struct puzzle_level puzzle_levels
[NUM_PUZZLE_LEVELS
] = {
457 { 5, 2, { {3, 3, PUZZLE_TILE_RIGHT
},
458 {4, 2, PUZZLE_TILE_LEFT
} } },
459 { 5, 2, { {3, 2, PUZZLE_TILE_DOWN
},
460 {3, 4, PUZZLE_TILE_UP
} } },
461 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
462 {3, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
463 {3, 6, PUZZLE_TILE_UP
} } },
464 { 6, 3, { {3, 2, PUZZLE_TILE_RIGHT
},
465 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
466 {5, 4, PUZZLE_TILE_LEFT
} } },
467 { 6, 2, { {3, 4, PUZZLE_TILE_RIGHT
},
468 {4, 2, PUZZLE_TILE_LEFT
} } },
469 { 6, 2, { {3, 2, PUZZLE_TILE_DOWN
},
470 {4, 4, PUZZLE_TILE_UP
} } },
471 { 7, 4, { {3, 2, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
472 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
473 {3, 4, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
474 {4, 4, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
475 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
476 {4, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
477 {3, 6, PUZZLE_TILE_UP
} } },
478 { 7, 3, { {2, 2, PUZZLE_TILE_RIGHT
},
479 {4, 1, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
480 {5, 4, PUZZLE_TILE_LEFT
} } },
481 { 7, 4, { {3, 0, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
482 {5, 0, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
483 {2, 7, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
484 {4, 7, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
487 #define SAVE_FILE PLUGIN_GAMES_DATA_DIR "/jewels.save"
488 #define SCORE_FILE PLUGIN_GAMES_DATA_DIR "/jewels.score"
489 struct highscore highscores
[NUM_SCORES
];
491 static bool resume_file
= false;
493 /*****************************************************************************
494 * jewels_setcolors() set the foreground and background colors.
495 ******************************************************************************/
496 static inline void jewels_setcolors(void) {
497 #ifdef HAVE_LCD_COLOR
498 rb
->lcd_set_background(LCD_RGBPACK(49, 26, 26));
499 rb
->lcd_set_foreground(LCD_RGBPACK(210, 181, 181));
503 /*****************************************************************************
504 * jewels_loadgame() loads the saved game and returns load success.
505 ******************************************************************************/
506 static bool jewels_loadgame(struct game_context
* bj
)
512 fd
= rb
->open(SAVE_FILE
, O_RDONLY
);
513 if(fd
< 0) return loaded
;
515 /* read in saved game */
517 if(rb
->read(fd
, &bj
->tmp_type
, sizeof(bj
->tmp_type
)) <= 0) break;
518 if(rb
->read(fd
, &bj
->type
, sizeof(bj
->type
)) <= 0) break;
519 if(rb
->read(fd
, &bj
->score
, sizeof(bj
->score
)) <= 0) break;
520 if(rb
->read(fd
, &bj
->level
, sizeof(bj
->level
)) <= 0) break;
521 if(rb
->read(fd
, &bj
->segments
, sizeof(bj
->segments
)) <= 0) break;
522 if(rb
->read(fd
, &bj
->num_jewels
, sizeof(bj
->num_jewels
)) <= 0) break;
523 if(rb
->read(fd
, bj
->playboard
, sizeof(bj
->playboard
)) <= 0) break;
533 /*****************************************************************************
534 * jewels_savegame() saves the current game state.
535 ******************************************************************************/
536 static void jewels_savegame(struct game_context
* bj
)
539 /* write out the game state to the save file */
540 fd
= rb
->open(SAVE_FILE
, O_WRONLY
|O_CREAT
, 0666);
543 rb
->write(fd
, &bj
->tmp_type
, sizeof(bj
->tmp_type
));
544 rb
->write(fd
, &bj
->type
, sizeof(bj
->type
));
545 rb
->write(fd
, &bj
->score
, sizeof(bj
->score
));
546 rb
->write(fd
, &bj
->level
, sizeof(bj
->level
));
547 rb
->write(fd
, &bj
->segments
, sizeof(bj
->segments
));
548 rb
->write(fd
, &bj
->num_jewels
, sizeof(bj
->num_jewels
));
549 rb
->write(fd
, bj
->playboard
, sizeof(bj
->playboard
));
553 /*****************************************************************************
554 * jewels_drawboard() redraws the entire game board.
555 ******************************************************************************/
556 static void jewels_drawboard(struct game_context
* bj
) {
559 unsigned int tempscore
;
561 char *title
= "Level";
564 if (bj
->type
== GAME_TYPE_NORMAL
) {
565 tempscore
= (bj
->score
>LEVEL_PTS
? LEVEL_PTS
: bj
->score
);
568 tempscore
= (bj
->level
>NUM_PUZZLE_LEVELS
? NUM_PUZZLE_LEVELS
: bj
->level
);
569 size
= NUM_PUZZLE_LEVELS
;
573 rb
->lcd_clear_display();
575 /* dispay playing board */
576 for(i
=0; i
<BJ_HEIGHT
-1; i
++){
577 for(j
=0; j
<BJ_WIDTH
; j
++){
578 #ifdef HAVE_LCD_COLOR
579 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
580 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
581 TILE_WIDTH
, TILE_HEIGHT
);
582 rb
->lcd_bitmap_transparent_part(jewels
,
583 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
585 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
586 j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
587 TILE_WIDTH
, TILE_HEIGHT
);
589 rb
->lcd_bitmap_part(jewels
,
590 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
592 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
593 j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
594 TILE_WIDTH
, TILE_HEIGHT
);
599 #if LCD_WIDTH > LCD_HEIGHT /* horizontal layout */
601 /* draw separator lines */
603 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, LCD_HEIGHT
-1);
605 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, 18);
606 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, LCD_HEIGHT
-10);
608 /* draw progress bar */
609 #ifdef HAVE_LCD_COLOR
610 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
612 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
613 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
615 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
616 ((LCD_HEIGHT
-10)-18)*tempscore
/size
);
617 #ifdef HAVE_LCD_COLOR
618 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
619 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
620 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
622 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
623 ((LCD_HEIGHT
-10)-18)*tempscore
/size
-1);
625 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
626 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*tempscore
/size
),
627 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
628 ((LCD_HEIGHT
-10)-18)*tempscore
/size
+1);
632 rb
->lcd_getstringsize(title
, &w
, &h
);
633 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 1, title
);
634 rb
->snprintf(str
, 4, "%d", bj
->level
);
635 rb
->lcd_getstringsize(str
, &w
, &h
);
636 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 10, str
);
638 if (bj
->type
== GAME_TYPE_NORMAL
) {
639 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
640 rb
->lcd_getstringsize(str
, &w
, &h
);
641 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2,
645 #elif LCD_WIDTH < LCD_HEIGHT /* vertical layout */
647 /* draw separator lines */
649 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
650 rb
->lcd_hline(0, LCD_WIDTH
-1, LCD_HEIGHT
-14);
651 rb
->lcd_vline(LCD_WIDTH
/2, LCD_HEIGHT
-14, LCD_HEIGHT
-1);
653 /* draw progress bar */
654 #ifdef HAVE_LCD_COLOR
655 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
657 rb
->lcd_fillrect(0, (8*TILE_HEIGHT
+YOFS
)
658 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
659 LCD_WIDTH
*tempscore
/size
,
660 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
661 #ifdef HAVE_LCD_COLOR
662 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
663 rb
->lcd_drawrect(1, (8*TILE_HEIGHT
+YOFS
)
664 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4+1,
665 LCD_WIDTH
*tempscore
/size
-1,
666 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2-2);
668 rb
->lcd_drawrect(0, (8*TILE_HEIGHT
+YOFS
)
669 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
670 LCD_WIDTH
*tempscore
/size
+1,
671 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
675 rb
->lcd_putsxyf(1, LCD_HEIGHT
-10, "%s %d", title
, bj
->level
);
677 if (bj
->type
== GAME_TYPE_NORMAL
) {
678 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
679 rb
->lcd_getstringsize(str
, &w
, &h
);
680 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
, LCD_HEIGHT
-10, str
);
684 #else /* square layout */
686 /* draw separator lines */
688 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
689 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, 8*TILE_HEIGHT
+YOFS
);
690 rb
->lcd_vline(LCD_WIDTH
/2, 8*TILE_HEIGHT
+YOFS
, LCD_HEIGHT
-1);
692 /* draw progress bar */
693 #ifdef HAVE_LCD_COLOR
694 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
696 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
697 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)*tempscore
/size
,
698 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
699 (8*TILE_HEIGHT
+YOFS
)*tempscore
/size
);
700 #ifdef HAVE_LCD_COLOR
701 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
702 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
703 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
705 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
706 (8*TILE_HEIGHT
+YOFS
)*tempscore
/size
-1);
708 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
709 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
711 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
712 (8*TILE_HEIGHT
+YOFS
)*tempscore
/size
+1);
716 rb
->lcd_putsxyf(1, LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3,"%s %d",
719 if (bj
->type
== GAME_TYPE_NORMAL
) {
720 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
721 rb
->lcd_getstringsize(str
, &w
, &h
);
722 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
,
723 LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3, str
);
731 /*****************************************************************************
732 * jewels_putjewels() makes the jewels fall to fill empty spots and adds
733 * new random jewels at the empty spots at the top of each row.
734 ******************************************************************************/
735 static void jewels_putjewels(struct game_context
* bj
){
738 long lasttick
, currenttick
;
740 /* loop to make all the jewels fall */
742 /* mark falling jewels and add new jewels to hidden top row*/
745 for(j
=0; j
<BJ_WIDTH
; j
++) {
746 if(bj
->playboard
[1][j
].type
== 0) {
747 bj
->playboard
[0][j
].type
= rb
->rand()%bj
->num_jewels
+1;
749 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
750 if(!mark
&& bj
->playboard
[i
+1][j
].type
== 0) {
754 if(mark
) bj
->playboard
[i
][j
].falling
= true;
756 /*if(bj->playboard[1][j].falling) {
757 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
758 bj->playboard[0][j].falling = true;
763 /* break if there are no falling jewels */
766 /* animate falling jewels */
767 lasttick
= *rb
->current_tick
;
769 for(k
=1; k
<=8; k
++) {
770 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
771 for(j
=0; j
<BJ_WIDTH
; j
++) {
772 if(bj
->playboard
[i
][j
].falling
&&
773 bj
->playboard
[i
][j
].type
!= 0) {
774 /* clear old position */
775 #ifdef HAVE_LCD_COLOR
777 rb
->lcd_set_foreground(rb
->lcd_get_background());
779 rb
->lcd_set_foreground(jewels_bkgd
[(i
-1+j
)%2]);
781 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
782 TILE_WIDTH
, TILE_HEIGHT
);
783 if(bj
->playboard
[i
+1][j
].type
== 0) {
784 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
785 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
786 TILE_WIDTH
, TILE_HEIGHT
);
789 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
790 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
791 TILE_WIDTH
, TILE_HEIGHT
);
792 if(bj
->playboard
[i
+1][j
].type
== 0) {
793 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
794 TILE_WIDTH
, TILE_HEIGHT
);
796 rb
->lcd_set_drawmode(DRMODE_SOLID
);
799 /* draw new position */
800 #ifdef HAVE_LCD_COLOR
801 rb
->lcd_bitmap_transparent_part(jewels
, 0,
802 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
807 (i
-1)*TILE_HEIGHT
+YOFS
+
808 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
809 TILE_WIDTH
, TILE_HEIGHT
);
811 rb
->lcd_bitmap_part(jewels
, 0,
812 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
817 (i
-1)*TILE_HEIGHT
+YOFS
+
818 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
819 TILE_WIDTH
, TILE_HEIGHT
);
825 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
828 /* framerate limiting */
829 currenttick
= *rb
->current_tick
;
830 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
831 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
835 lasttick
= currenttick
;
838 /* shift jewels down */
839 for(j
=0; j
<BJ_WIDTH
; j
++) {
840 for(i
=BJ_HEIGHT
-1; i
>=1; i
--) {
841 if(bj
->playboard
[i
-1][j
].falling
) {
842 bj
->playboard
[i
][j
].type
= bj
->playboard
[i
-1][j
].type
;
847 /* clear out top row */
848 for(j
=0; j
<BJ_WIDTH
; j
++) {
849 bj
->playboard
[0][j
].type
= 0;
852 /* mark everything not falling */
853 for(i
=0; i
<BJ_HEIGHT
; i
++) {
854 for(j
=0; j
<BJ_WIDTH
; j
++) {
855 bj
->playboard
[i
][j
].falling
= false;
861 /*****************************************************************************
862 * jewels_clearjewels() finds all the connected rows and columns and
863 * calculates and returns the points earned.
864 ******************************************************************************/
865 static unsigned int jewels_clearjewels(struct game_context
* bj
) {
868 unsigned int points
= 0;
870 /* check for connected rows */
871 for(i
=1; i
<BJ_HEIGHT
; i
++) {
874 for(j
=0; j
<BJ_WIDTH
; j
++) {
875 if(bj
->playboard
[i
][j
].type
== last
&&
876 bj
->playboard
[i
][j
].type
!= 0 &&
877 bj
->playboard
[i
][j
].type
<= MAX_NUM_JEWELS
) {
882 points
+= bj
->segments
;
883 bj
->playboard
[i
][j
].delete = true;
884 bj
->playboard
[i
][j
-1].delete = true;
885 bj
->playboard
[i
][j
-2].delete = true;
888 bj
->playboard
[i
][j
].delete = true;
892 last
= bj
->playboard
[i
][j
].type
;
897 /* check for connected columns */
898 for(j
=0; j
<BJ_WIDTH
; j
++) {
901 for(i
=1; i
<BJ_HEIGHT
; i
++) {
902 if(bj
->playboard
[i
][j
].type
!= 0 &&
903 bj
->playboard
[i
][j
].type
== last
&&
904 bj
->playboard
[i
][j
].type
<= MAX_NUM_JEWELS
) {
909 points
+= bj
->segments
;
910 bj
->playboard
[i
][j
].delete = true;
911 bj
->playboard
[i
-1][j
].delete = true;
912 bj
->playboard
[i
-2][j
].delete = true;
915 bj
->playboard
[i
][j
].delete = true;
919 last
= bj
->playboard
[i
][j
].type
;
924 /* clear deleted jewels */
925 for(i
=1; i
<BJ_HEIGHT
; i
++) {
926 for(j
=0; j
<BJ_WIDTH
; j
++) {
927 if(bj
->playboard
[i
][j
].delete) {
928 bj
->playboard
[i
][j
].delete = false;
929 bj
->playboard
[i
][j
].type
= 0;
937 /*****************************************************************************
938 * jewels_runboard() runs the board until it settles in a fixed state and
939 * returns points earned.
940 ******************************************************************************/
941 static unsigned int jewels_runboard(struct game_context
* bj
) {
942 unsigned int points
= 0;
947 while((ret
= jewels_clearjewels(bj
)) > 0) {
949 jewels_drawboard(bj
);
950 jewels_putjewels(bj
);
956 /*****************************************************************************
957 * jewels_swapjewels() swaps two jewels as long as it results in points and
958 * returns points earned.
959 ******************************************************************************/
960 static unsigned int jewels_swapjewels(struct game_context
* bj
,
961 int x
, int y
, int direc
) {
963 int horzmod
, vertmod
;
966 unsigned int points
= 0;
967 long lasttick
, currenttick
;
969 /* check for invalid parameters */
970 if(x
< 0 || x
>= BJ_WIDTH
|| y
< 0 || y
>= BJ_HEIGHT
-1 ||
971 direc
< SWAP_UP
|| direc
> SWAP_LEFT
) {
975 /* check for invalid directions */
976 if((x
== 0 && direc
== SWAP_LEFT
) ||
977 (x
== BJ_WIDTH
-1 && direc
== SWAP_RIGHT
) ||
978 (y
== 0 && direc
== SWAP_UP
) ||
979 (y
== BJ_HEIGHT
-2 && direc
== SWAP_DOWN
)) {
983 /* set direction variables */
989 movelen
= TILE_HEIGHT
;
993 movelen
= TILE_WIDTH
;
997 movelen
= TILE_HEIGHT
;
1001 movelen
= TILE_WIDTH
;
1006 lasttick
= *rb
->current_tick
;
1008 /* animate swapping jewels */
1009 for(k
=0; k
<=8; k
++) {
1010 /* clear old position */
1011 #ifdef HAVE_LCD_COLOR
1012 rb
->lcd_set_foreground(jewels_bkgd
[(x
+y
)%2]);
1013 rb
->lcd_fillrect(x
*TILE_WIDTH
,
1015 TILE_WIDTH
, TILE_HEIGHT
);
1016 rb
->lcd_set_foreground(jewels_bkgd
[(x
+horzmod
+y
+vertmod
)%2]);
1017 rb
->lcd_fillrect((x
+horzmod
)*TILE_WIDTH
,
1018 (y
+vertmod
)*TILE_HEIGHT
+YOFS
,
1019 TILE_WIDTH
, TILE_HEIGHT
);
1021 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
1022 rb
->lcd_fillrect(x
*TILE_WIDTH
,
1024 TILE_WIDTH
, TILE_HEIGHT
);
1025 rb
->lcd_fillrect((x
+horzmod
)*TILE_WIDTH
,
1026 (y
+vertmod
)*TILE_HEIGHT
+YOFS
,
1027 TILE_WIDTH
, TILE_HEIGHT
);
1028 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1030 /* draw new position */
1031 #ifdef HAVE_LCD_COLOR
1032 rb
->lcd_bitmap_transparent_part(jewels
,
1033 0, TILE_HEIGHT
*(bj
->playboard
1034 [y
+1+vertmod
][x
+horzmod
].type
),
1035 STRIDE( SCREEN_MAIN
,
1036 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
1037 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
1038 ((((movelen
<<10)*k
)/8)>>10),
1039 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
1040 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1041 TILE_WIDTH
, TILE_HEIGHT
);
1042 rb
->lcd_bitmap_transparent_part(jewels
,
1043 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
1044 STRIDE( SCREEN_MAIN
,
1045 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
1046 x
*TILE_WIDTH
+horzmod
*
1047 ((((movelen
<<10)*k
)/8)>>10),
1048 y
*TILE_HEIGHT
+vertmod
*
1049 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1050 TILE_WIDTH
, TILE_HEIGHT
);
1052 rb
->lcd_bitmap_part(jewels
,
1053 0, TILE_HEIGHT
*(bj
->playboard
1054 [y
+1+vertmod
][x
+horzmod
].type
),
1055 STRIDE( SCREEN_MAIN
,
1056 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
1057 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
1058 ((((movelen
<<10)*k
)/8)>>10),
1059 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
1060 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1061 TILE_WIDTH
, TILE_HEIGHT
);
1062 rb
->lcd_set_drawmode(DRMODE_FG
);
1063 rb
->lcd_bitmap_part(jewels
,
1064 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
1065 STRIDE( SCREEN_MAIN
,
1066 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
1067 x
*TILE_WIDTH
+horzmod
*
1068 ((((movelen
<<10)*k
)/8)>>10),
1069 y
*TILE_HEIGHT
+vertmod
*
1070 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1071 TILE_WIDTH
, TILE_HEIGHT
);
1072 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1075 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
1078 /* framerate limiting */
1079 currenttick
= *rb
->current_tick
;
1080 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
1081 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
1085 lasttick
= currenttick
;
1089 int temp
= bj
->playboard
[y
+1][x
].type
;
1090 bj
->playboard
[y
+1][x
].type
=
1091 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
;
1092 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
= temp
;
1096 points
= jewels_runboard(bj
);
1107 /*****************************************************************************
1108 * jewels_movesavail() uses pattern matching to see if there are any
1109 * available move left.
1110 ******************************************************************************/
1111 static bool jewels_movesavail(struct game_context
* bj
) {
1116 for(i
=1; i
<BJ_HEIGHT
; i
++) {
1117 for(j
=0; j
<BJ_WIDTH
; j
++) {
1118 mytype
= bj
->playboard
[i
][j
].type
;
1119 if(mytype
== 0 || mytype
> MAX_NUM_JEWELS
) continue;
1121 /* check horizontal patterns */
1122 if(j
<= BJ_WIDTH
-3) {
1124 if(bj
->playboard
[i
-1][j
+1].type
== mytype
) {
1125 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1126 {moves
= true; break;}
1127 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1128 {moves
= true; break;}
1130 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1131 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1132 {moves
= true; break;}
1136 if(j
<= BJ_WIDTH
-4) {
1137 if(bj
->playboard
[i
][j
+3].type
== mytype
) {
1138 if(bj
->playboard
[i
][j
+1].type
== mytype
)
1139 {moves
= true; break;}
1140 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1141 {moves
= true; break;}
1145 if(i
< BJ_HEIGHT
-1) {
1146 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1147 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1148 {moves
= true; break;}
1150 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1151 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1152 {moves
= true; break;}
1153 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1154 {moves
= true; break;}
1159 /* check vertical patterns */
1160 if(i
<= BJ_HEIGHT
-3) {
1162 if(bj
->playboard
[i
+1][j
-1].type
== mytype
) {
1163 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1164 {moves
= true; break;}
1165 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1166 {moves
= true; break;}
1168 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1169 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1170 {moves
= true; break;}
1174 if(i
<= BJ_HEIGHT
-4) {
1175 if(bj
->playboard
[i
+3][j
].type
== mytype
) {
1176 if(bj
->playboard
[i
+1][j
].type
== mytype
)
1177 {moves
= true; break;}
1178 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1179 {moves
= true; break;}
1183 if(j
< BJ_WIDTH
-1) {
1184 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1185 if(bj
->playboard
[i
+2][j
+1].type
== mytype
)
1186 {moves
= true; break;}
1188 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1189 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1190 {moves
= true; break;}
1191 if (bj
->playboard
[i
+2][j
+1].type
== mytype
)
1192 {moves
= true; break;}
1202 /*****************************************************************************
1203 * jewels_puzzle_is_finished() checks if the puzzle is finished.
1204 ******************************************************************************/
1205 static bool jewels_puzzle_is_finished(struct game_context
* bj
) {
1207 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1208 for(j
=0; j
<BJ_WIDTH
; j
++) {
1209 int mytype
= bj
->playboard
[i
][j
].type
;
1210 if(mytype
>MAX_NUM_JEWELS
) {
1211 mytype
-= MAX_NUM_JEWELS
;
1212 if(mytype
&PUZZLE_TILE_UP
) {
1213 if(i
==0 || bj
->playboard
[i
-1][j
].type
<=MAX_NUM_JEWELS
||
1214 !((bj
->playboard
[i
-1][j
].type
-MAX_NUM_JEWELS
)
1218 if(mytype
&PUZZLE_TILE_DOWN
) {
1219 if(i
==BJ_HEIGHT
-1 ||
1220 bj
->playboard
[i
+1][j
].type
<=MAX_NUM_JEWELS
||
1221 !((bj
->playboard
[i
+1][j
].type
-MAX_NUM_JEWELS
)
1225 if(mytype
&PUZZLE_TILE_LEFT
) {
1226 if(j
==0 || bj
->playboard
[i
][j
-1].type
<=MAX_NUM_JEWELS
||
1227 !((bj
->playboard
[i
][j
-1].type
-MAX_NUM_JEWELS
)
1228 &PUZZLE_TILE_RIGHT
))
1231 if(mytype
&PUZZLE_TILE_RIGHT
) {
1233 bj
->playboard
[i
][j
+1].type
<=MAX_NUM_JEWELS
||
1234 !((bj
->playboard
[i
][j
+1].type
-MAX_NUM_JEWELS
)
1244 /*****************************************************************************
1245 * jewels_initlevel() initialises a level.
1246 ******************************************************************************/
1247 static unsigned int jewels_initlevel(struct game_context
* bj
) {
1248 unsigned int points
= 0;
1251 case GAME_TYPE_NORMAL
:
1252 bj
->num_jewels
= MAX_NUM_JEWELS
;
1255 case GAME_TYPE_PUZZLE
:
1258 struct puzzle_tile
*tile
;
1260 bj
->num_jewels
= puzzle_levels
[bj
->level
-1].num_jewels
;
1262 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1263 for(j
=0; j
<BJ_WIDTH
; j
++) {
1264 bj
->playboard
[i
][j
].type
= (rb
->rand()%bj
->num_jewels
)+1;
1265 bj
->playboard
[i
][j
].falling
= false;
1266 bj
->playboard
[i
][j
].delete = false;
1269 jewels_runboard(bj
);
1270 tile
= puzzle_levels
[bj
->level
-1].tiles
;
1271 for(i
=0; i
<puzzle_levels
[bj
->level
-1].num_tiles
; i
++, tile
++) {
1272 bj
->playboard
[tile
->y
+1][tile
->x
].type
= MAX_NUM_JEWELS
1279 jewels_drawboard(bj
);
1281 /* run the play board */
1282 jewels_putjewels(bj
);
1283 points
+= jewels_runboard(bj
);
1287 /*****************************************************************************
1288 * jewels_init() initializes jewels data structures.
1289 ******************************************************************************/
1290 static void jewels_init(struct game_context
* bj
) {
1291 /* seed the rand generator */
1292 rb
->srand(*rb
->current_tick
);
1294 bj
->type
= bj
->tmp_type
;
1301 /* clear playing board */
1302 rb
->memset(bj
->playboard
, 0, sizeof(bj
->playboard
));
1304 bj
->score
+= jewels_initlevel(bj
);
1305 } while(!jewels_movesavail(bj
));
1308 /*****************************************************************************
1309 * jewels_nextlevel() advances the game to the next bj->level and returns
1311 ******************************************************************************/
1312 static void jewels_nextlevel(struct game_context
* bj
) {
1314 unsigned int points
= 0;
1317 case GAME_TYPE_NORMAL
:
1318 /* roll over score, change and display level */
1319 while(bj
->score
>= LEVEL_PTS
) {
1320 bj
->score
-= LEVEL_PTS
;
1322 rb
->splashf(HZ
*2, "Level %d", bj
->level
);
1323 jewels_drawboard(bj
);
1326 /* randomly clear some jewels */
1327 for(i
=0; i
<16; i
++) {
1331 if(bj
->playboard
[y
][x
].type
!= 0) {
1333 bj
->playboard
[y
][x
].type
= 0;
1338 case GAME_TYPE_PUZZLE
:
1340 rb
->splashf(HZ
*2, "Level %d", bj
->level
);
1344 points
+= jewels_initlevel(bj
);
1345 bj
->score
+= points
;
1348 static bool jewels_help(void)
1350 static char *help_text
[] = {
1351 "Jewels", "", "Aim", "",
1352 "Swap", "pairs", "of", "jewels", "to", "form", "connected",
1353 "segments", "of", "three", "or", "more", "of", "the", "same",
1355 "The", "goal", "of", "the", "game", "is", "to", "score", "as", "many",
1356 "points", "as", "possible", "before", "running", "out", "of",
1357 "available", "moves.", "", "",
1360 #ifdef JEWELS_SCROLLWHEEL
1364 HK_SELECT
, "to", "select", "",
1365 HK_CANCEL
, "to", "go", "to", "menu"
1367 static struct style_text formation
[]={
1368 { 0, TEXT_CENTER
|TEXT_UNDERLINE
},
1374 rb
->lcd_setfont(FONT_UI
);
1375 if (display_text(ARRAYLEN(help_text
), help_text
, formation
, NULL
, true))
1377 rb
->lcd_setfont(FONT_SYSFIXED
);
1382 static bool _ingame
;
1383 static int jewels_menu_cb(int action
, const struct menu_item_ex
*this_item
)
1385 int i
= ((intptr_t)this_item
);
1386 if(action
== ACTION_REQUEST_MENUITEM
1387 && !_ingame
&& (i
==0 || i
==6))
1388 return ACTION_EXIT_MENUITEM
;
1391 /*****************************************************************************
1392 * jewels_game_menu() shows the game menu.
1393 ******************************************************************************/
1394 static int jewels_game_menu(struct game_context
* bj
, bool ingame
)
1396 rb
->button_clear_queue();
1401 static struct opt_items mode
[] = {
1406 MENUITEM_STRINGLIST (main_menu
, "Jewels Menu", jewels_menu_cb
,
1413 "Quit without Saving",
1417 switch (rb
->do_menu(&main_menu
, &choice
, NULL
, false)) {
1421 rb
->remove(SAVE_FILE
);
1427 rb
->set_option("Mode", &bj
->tmp_type
, INT
, mode
, 2, NULL
);
1434 highscore_show(-1, highscores
, NUM_SCORES
, true);
1437 playback_control(NULL
);
1443 rb
->splash(HZ
*1, "Saving game ...");
1444 jewels_savegame(bj
);
1447 case MENU_ATTACHED_USB
:
1455 static int jewels_main(struct game_context
* bj
) {
1458 bool selected
= false;
1461 bool loaded
= jewels_loadgame(bj
);
1462 resume_file
= loaded
;
1463 if (jewels_game_menu(bj
, loaded
)!=0)
1466 resume_file
= false;
1468 /* refresh the board */
1469 jewels_drawboard(bj
);
1471 /* display the cursor */
1473 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
1474 rb
->lcd_fillrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1475 TILE_WIDTH
, TILE_HEIGHT
);
1476 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1478 rb
->lcd_drawrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1479 TILE_WIDTH
, TILE_HEIGHT
);
1481 rb
->lcd_update_rect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1482 TILE_WIDTH
, TILE_HEIGHT
);
1484 /* handle game button presses */
1486 button
= rb
->button_get(true);
1488 case JEWELS_LEFT
: /* move cursor left */
1489 case (JEWELS_LEFT
|BUTTON_REPEAT
):
1491 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_LEFT
);
1494 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1498 case JEWELS_RIGHT
: /* move cursor right */
1499 case (JEWELS_RIGHT
|BUTTON_REPEAT
):
1501 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_RIGHT
);
1508 case JEWELS_DOWN
: /* move cursor down */
1509 case (JEWELS_DOWN
|BUTTON_REPEAT
):
1511 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_DOWN
);
1514 y
= (y
+1)%(BJ_HEIGHT
-1);
1518 case JEWELS_UP
: /* move cursor up */
1519 case (JEWELS_UP
|BUTTON_REPEAT
):
1521 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_UP
);
1524 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1528 #ifdef JEWELS_SCROLLWHEEL
1529 case JEWELS_PREV
: /* scroll backwards */
1530 case (JEWELS_PREV
|BUTTON_REPEAT
):
1533 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1535 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1539 case JEWELS_NEXT
: /* scroll forwards */
1540 case (JEWELS_NEXT
|BUTTON_REPEAT
):
1542 if(x
== BJ_WIDTH
-1) {
1543 y
= (y
+1)%(BJ_HEIGHT
-1);
1550 case JEWELS_SELECT
: /* toggle selected */
1551 selected
= !selected
;
1554 #ifdef JEWELS_RC_CANCEL
1555 case JEWELS_RC_CANCEL
:
1557 case JEWELS_CANCEL
: /* end game */
1558 if (jewels_game_menu(bj
, true)!=0)
1563 if (rb
->default_event_handler (button
) == SYS_USB_CONNECTED
)
1564 return PLUGIN_USB_CONNECTED
;
1569 case GAME_TYPE_NORMAL
:
1570 if(bj
->score
>= LEVEL_PTS
)
1571 jewels_nextlevel(bj
);
1573 case GAME_TYPE_PUZZLE
:
1574 if (jewels_puzzle_is_finished(bj
)) {
1575 if (bj
->level
< NUM_PUZZLE_LEVELS
) {
1576 jewels_nextlevel(bj
);
1578 rb
->splash(2*HZ
, "Congratulations!");
1579 rb
->splash(2*HZ
, "You have finished the game!");
1580 if (jewels_game_menu(bj
, false)!=0) {
1588 if (!jewels_movesavail(bj
)) {
1590 case GAME_TYPE_NORMAL
:
1591 rb
->splash(HZ
*2, "Game Over!");
1592 rb
->lcd_clear_display();
1593 bj
->score
+= (bj
->level
-1)*LEVEL_PTS
;
1594 position
=highscore_update(bj
->score
, bj
->level
, "",
1595 highscores
, NUM_SCORES
);
1599 rb
->splash(HZ
*2, "New High Score");
1600 highscore_show(position
, highscores
, NUM_SCORES
, true);
1603 case GAME_TYPE_PUZZLE
:
1604 rb
->splash(2*HZ
, "Game Over");
1607 if (jewels_game_menu(bj
, false)!=0) {
1614 /* this is the plugin entry point */
1615 enum plugin_status
plugin_start(const void* parameter
)
1619 /* load high scores */
1620 highscore_load(SCORE_FILE
, highscores
, NUM_SCORES
);
1622 rb
->lcd_setfont(FONT_SYSFIXED
);
1624 rb
->lcd_set_backdrop(NULL
);
1627 struct game_context bj
;
1628 bj
.tmp_type
= GAME_TYPE_NORMAL
;
1630 highscore_save(SCORE_FILE
, highscores
, NUM_SCORES
);
1631 rb
->lcd_setfont(FONT_UI
);