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 #ifdef HAVE_LCD_BITMAP
34 /* button definitions */
35 #if CONFIG_KEYPAD == RECORDER_PAD
36 #define JEWELS_UP BUTTON_UP
37 #define JEWELS_DOWN BUTTON_DOWN
38 #define JEWELS_LEFT BUTTON_LEFT
39 #define JEWELS_RIGHT BUTTON_RIGHT
40 #define JEWELS_SELECT BUTTON_PLAY
41 #define JEWELS_CANCEL BUTTON_OFF
42 #define HK_SELECT "PLAY"
43 #define HK_CANCEL "OFF"
45 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
46 #define JEWELS_UP BUTTON_UP
47 #define JEWELS_DOWN BUTTON_DOWN
48 #define JEWELS_LEFT BUTTON_LEFT
49 #define JEWELS_RIGHT BUTTON_RIGHT
50 #define JEWELS_SELECT BUTTON_SELECT
51 #define JEWELS_CANCEL BUTTON_OFF
52 #define HK_SELECT "SELECT"
53 #define HK_CANCEL "OFF"
55 #elif CONFIG_KEYPAD == ONDIO_PAD
56 #define JEWELS_UP BUTTON_UP
57 #define JEWELS_DOWN BUTTON_DOWN
58 #define JEWELS_LEFT BUTTON_LEFT
59 #define JEWELS_RIGHT BUTTON_RIGHT
60 #define JEWELS_SELECT BUTTON_MENU
61 #define JEWELS_CANCEL BUTTON_OFF
62 #define HK_SELECT "MENU"
63 #define HK_CANCEL "OFF"
65 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
66 #define JEWELS_UP BUTTON_UP
67 #define JEWELS_DOWN BUTTON_DOWN
68 #define JEWELS_LEFT BUTTON_LEFT
69 #define JEWELS_RIGHT BUTTON_RIGHT
70 #define JEWELS_SELECT BUTTON_SELECT
71 #define JEWELS_CANCEL BUTTON_OFF
72 #define JEWELS_RC_CANCEL BUTTON_RC_STOP
73 #define HK_SELECT "SELECT"
74 #define HK_CANCEL "OFF"
76 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
77 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
78 #define JEWELS_SCROLLWHEEL
79 #define JEWELS_UP BUTTON_MENU
80 #define JEWELS_DOWN BUTTON_PLAY
81 #define JEWELS_LEFT BUTTON_LEFT
82 #define JEWELS_RIGHT BUTTON_RIGHT
83 #define JEWELS_PREV BUTTON_SCROLL_BACK
84 #define JEWELS_NEXT BUTTON_SCROLL_FWD
85 #define JEWELS_SELECT BUTTON_SELECT
86 #define JEWELS_CANCEL (BUTTON_SELECT | BUTTON_MENU)
87 #define HK_SELECT "SELECT"
88 #define HK_CANCEL "SEL + MENU"
90 #elif (CONFIG_KEYPAD == IPOD_3G_PAD)
91 #define JEWELS_LEFT BUTTON_LEFT
92 #define JEWELS_RIGHT BUTTON_RIGHT
93 #define JEWELS_UP BUTTON_SCROLL_BACK
94 #define JEWELS_DOWN BUTTON_SCROLL_FWD
95 #define JEWELS_SELECT BUTTON_SELECT
96 #define JEWELS_CANCEL BUTTON_MENU
97 #define HK_SELECT "SELECT"
98 #define HK_CANCEL "MENU"
100 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
101 #define JEWELS_UP BUTTON_UP
102 #define JEWELS_DOWN BUTTON_DOWN
103 #define JEWELS_LEFT BUTTON_LEFT
104 #define JEWELS_RIGHT BUTTON_RIGHT
105 #define JEWELS_SELECT BUTTON_SELECT
106 #define JEWELS_CANCEL BUTTON_PLAY
107 #define HK_SELECT "SELECT"
108 #define HK_CANCEL "PLAY"
110 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
111 #define JEWELS_UP BUTTON_UP
112 #define JEWELS_DOWN BUTTON_DOWN
113 #define JEWELS_LEFT BUTTON_LEFT
114 #define JEWELS_RIGHT BUTTON_RIGHT
115 #define JEWELS_SELECT BUTTON_SELECT
116 #define JEWELS_CANCEL BUTTON_POWER
117 #define HK_SELECT "SELECT"
118 #define HK_CANCEL "POWER"
120 #elif CONFIG_KEYPAD == GIGABEAT_PAD
121 #define JEWELS_UP BUTTON_UP
122 #define JEWELS_DOWN BUTTON_DOWN
123 #define JEWELS_LEFT BUTTON_LEFT
124 #define JEWELS_RIGHT BUTTON_RIGHT
125 #define JEWELS_SELECT BUTTON_SELECT
126 #define JEWELS_CANCEL BUTTON_POWER
127 #define HK_SELECT "SELECT"
128 #define HK_CANCEL "POWER"
130 #elif CONFIG_KEYPAD == SANSA_E200_PAD
131 #define JEWELS_SCROLLWHEEL
132 #define JEWELS_UP BUTTON_UP
133 #define JEWELS_DOWN BUTTON_DOWN
134 #define JEWELS_LEFT BUTTON_LEFT
135 #define JEWELS_RIGHT BUTTON_RIGHT
136 #define JEWELS_PREV BUTTON_SCROLL_BACK
137 #define JEWELS_NEXT BUTTON_SCROLL_FWD
138 #define JEWELS_SELECT BUTTON_SELECT
139 #define JEWELS_CANCEL BUTTON_POWER
140 #define HK_SELECT "SELECT"
141 #define HK_CANCEL "POWER"
143 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
144 #define JEWELS_SCROLLWHEEL
145 #define JEWELS_UP BUTTON_UP
146 #define JEWELS_DOWN BUTTON_DOWN
147 #define JEWELS_LEFT BUTTON_LEFT
148 #define JEWELS_RIGHT BUTTON_RIGHT
149 #define JEWELS_PREV BUTTON_SCROLL_BACK
150 #define JEWELS_NEXT BUTTON_SCROLL_FWD
151 #define JEWELS_SELECT BUTTON_SELECT
152 #define JEWELS_CANCEL (BUTTON_HOME|BUTTON_REPEAT)
153 #define HK_SELECT "SELECT"
154 #define HK_CANCEL "HOME"
156 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
157 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
158 CONFIG_KEYPAD == SANSA_M200_PAD
159 #define JEWELS_UP BUTTON_UP
160 #define JEWELS_DOWN BUTTON_DOWN
161 #define JEWELS_LEFT BUTTON_LEFT
162 #define JEWELS_RIGHT BUTTON_RIGHT
163 #define JEWELS_SELECT BUTTON_SELECT
164 #define JEWELS_CANCEL BUTTON_POWER
165 #define HK_SELECT "SELECT"
166 #define HK_CANCEL "POWER"
168 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
169 #define JEWELS_UP BUTTON_SCROLL_UP
170 #define JEWELS_DOWN BUTTON_SCROLL_DOWN
171 #define JEWELS_LEFT BUTTON_LEFT
172 #define JEWELS_RIGHT BUTTON_RIGHT
173 #define JEWELS_SELECT BUTTON_PLAY
174 #define JEWELS_CANCEL BUTTON_POWER
175 #define HK_SELECT "PLAY"
176 #define HK_CANCEL "POWER"
178 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
179 #define JEWELS_UP BUTTON_UP
180 #define JEWELS_DOWN BUTTON_DOWN
181 #define JEWELS_LEFT BUTTON_LEFT
182 #define JEWELS_RIGHT BUTTON_RIGHT
183 #define JEWELS_SELECT BUTTON_SELECT
184 #define JEWELS_CANCEL BUTTON_BACK
185 #define HK_SELECT "SELECT"
186 #define HK_CANCEL "BACK"
188 #elif CONFIG_KEYPAD == MROBE100_PAD
189 #define JEWELS_UP BUTTON_UP
190 #define JEWELS_DOWN BUTTON_DOWN
191 #define JEWELS_LEFT BUTTON_LEFT
192 #define JEWELS_RIGHT BUTTON_RIGHT
193 #define JEWELS_SELECT BUTTON_SELECT
194 #define JEWELS_CANCEL BUTTON_POWER
195 #define HK_SELECT "SELECT"
196 #define HK_CANCEL "POWER"
198 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
199 #define JEWELS_UP BUTTON_RC_VOL_UP
200 #define JEWELS_DOWN BUTTON_RC_VOL_DOWN
201 #define JEWELS_LEFT BUTTON_RC_REW
202 #define JEWELS_RIGHT BUTTON_RC_FF
203 #define JEWELS_SELECT BUTTON_RC_PLAY
204 #define JEWELS_CANCEL BUTTON_RC_REC
205 #define HK_SELECT "PLAY"
206 #define HK_CANCEL "REC"
208 #define JEWELS_RC_CANCEL BUTTON_REC
210 #elif CONFIG_KEYPAD == COWOND2_PAD
211 #define JEWELS_CANCEL BUTTON_POWER
212 #define HK_CANCEL "POWER"
214 #elif CONFIG_KEYPAD == IAUDIO67_PAD
215 #define JEWELS_UP BUTTON_STOP
216 #define JEWELS_DOWN BUTTON_PLAY
217 #define JEWELS_LEFT BUTTON_LEFT
218 #define JEWELS_RIGHT BUTTON_RIGHT
219 #define JEWELS_SELECT BUTTON_MENU
220 #define JEWELS_CANCEL BUTTON_POWER
221 #define HK_SELECT "MENU"
222 #define HK_CANCEL "POWER"
224 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
225 #define JEWELS_UP BUTTON_UP
226 #define JEWELS_DOWN BUTTON_DOWN
227 #define JEWELS_LEFT BUTTON_LEFT
228 #define JEWELS_RIGHT BUTTON_RIGHT
229 #define JEWELS_SELECT BUTTON_SELECT
230 #define JEWELS_CANCEL BUTTON_BACK
231 #define HK_SELECT "MIDDLE"
232 #define HK_CANCEL "BACK"
234 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
235 #define JEWELS_UP BUTTON_UP
236 #define JEWELS_DOWN BUTTON_DOWN
237 #define JEWELS_LEFT BUTTON_LEFT
238 #define JEWELS_RIGHT BUTTON_RIGHT
239 #define JEWELS_SELECT BUTTON_SELECT
240 #define JEWELS_CANCEL BUTTON_POWER
241 #define HK_SELECT "SELECT"
242 #define HK_CANCEL "POWER"
244 #elif CONFIG_KEYPAD == ONDAVX747_PAD || \
245 CONFIG_KEYPAD == ONDAVX777_PAD || \
246 CONFIG_KEYPAD == MROBE500_PAD
247 #define JEWELS_CANCEL BUTTON_POWER
248 #define HK_CANCEL "POWER"
250 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
251 #define JEWELS_UP BUTTON_UP
252 #define JEWELS_DOWN BUTTON_DOWN
253 #define JEWELS_LEFT BUTTON_LEFT
254 #define JEWELS_RIGHT BUTTON_RIGHT
255 #define JEWELS_SELECT BUTTON_PLAY
256 #define JEWELS_CANCEL BUTTON_REW
257 #define HK_SELECT "PLAY"
258 #define HK_CANCEL "REWIND"
261 #error No keymap defined!
264 #ifdef HAVE_TOUCHSCREEN
266 #define JEWELS_UP BUTTON_TOPMIDDLE
269 #define JEWELS_DOWN BUTTON_BOTTOMMIDDLE
272 #define JEWELS_LEFT BUTTON_MIDLEFT
275 #define JEWELS_RIGHT BUTTON_MIDRIGHT
277 #ifndef JEWELS_SELECT
278 #define JEWELS_SELECT BUTTON_CENTER
279 #define HK_SELECT "CENTER"
281 #ifndef JEWELS_CANCEL
282 #define JEWELS_CANCEL BUTTON_TOPLEFT
283 #define HK_CANCEL "TOPLEFT"
287 #define TILE_WIDTH BMPWIDTH_jewels
288 #define TILE_HEIGHT (BMPHEIGHT_jewels/23)
290 #if LCD_HEIGHT < LCD_WIDTH
291 /* This calculation assumes integer division w/ LCD_HEIGHT/TILE_HEIGHT */
292 #define YOFS LCD_HEIGHT-((LCD_HEIGHT/TILE_HEIGHT)*TILE_HEIGHT)
299 /* swap directions */
305 /* play board dimension */
309 /* next level threshold */
310 #define LEVEL_PTS 100
312 /* animation frame rate */
324 /* external bitmaps */
325 extern const fb_data jewels
[];
327 /* tile background colors */
328 #ifdef HAVE_LCD_COLOR
329 static const unsigned jewels_bkgd
[2] = {
330 LCD_RGBPACK(104, 63, 63),
331 LCD_RGBPACK(83, 44, 44)
336 * type is the jewel number 0-7
337 * falling if the jewel is falling
338 * delete marks the jewel for deletion
346 /* the game context struct
347 * score is the current level score
348 * segments is the number of cleared segments in the current run
349 * level is the current level
350 * tmp_type is the select type in the menu
351 * type is the game type (normal or puzzle)
352 * playboard is the game playing board (first row is hidden)
353 * num_jewels is the number of different jewels to use
355 struct game_context
{
357 unsigned int segments
;
360 unsigned int tmp_type
;
361 struct tile playboard
[BJ_HEIGHT
][BJ_WIDTH
];
362 unsigned int num_jewels
;
365 #define MAX_NUM_JEWELS 7
367 #define MAX_PUZZLE_TILES 4
368 #define NUM_PUZZLE_LEVELS 10
376 struct puzzle_level
{
377 unsigned int num_jewels
;
378 unsigned int num_tiles
;
379 struct puzzle_tile tiles
[MAX_PUZZLE_TILES
];
382 #define PUZZLE_TILE_UP 1
383 #define PUZZLE_TILE_DOWN 2
384 #define PUZZLE_TILE_LEFT 4
385 #define PUZZLE_TILE_RIGHT 8
387 struct puzzle_level puzzle_levels
[NUM_PUZZLE_LEVELS
] = {
388 { 5, 2, { {3, 3, PUZZLE_TILE_RIGHT
},
389 {4, 2, PUZZLE_TILE_LEFT
} } },
390 { 5, 2, { {3, 2, PUZZLE_TILE_DOWN
},
391 {3, 4, PUZZLE_TILE_UP
} } },
392 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
393 {3, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
394 {3, 6, PUZZLE_TILE_UP
} } },
395 { 6, 3, { {3, 2, PUZZLE_TILE_RIGHT
},
396 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
397 {5, 4, PUZZLE_TILE_LEFT
} } },
398 { 6, 2, { {3, 4, PUZZLE_TILE_RIGHT
},
399 {4, 2, PUZZLE_TILE_LEFT
} } },
400 { 6, 2, { {3, 2, PUZZLE_TILE_DOWN
},
401 {4, 4, PUZZLE_TILE_UP
} } },
402 { 7, 4, { {3, 2, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
403 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
404 {3, 4, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
405 {4, 4, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
406 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
407 {4, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
408 {3, 6, PUZZLE_TILE_UP
} } },
409 { 7, 3, { {2, 2, PUZZLE_TILE_RIGHT
},
410 {4, 1, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
411 {5, 4, PUZZLE_TILE_LEFT
} } },
412 { 7, 4, { {3, 0, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
413 {5, 0, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
414 {2, 7, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
415 {4, 7, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
418 #define SAVE_FILE PLUGIN_GAMES_DIR "/jewels.save"
420 #define HIGH_SCORE PLUGIN_GAMES_DIR "/jewels.score"
421 struct highscore highest
[NUM_SCORES
];
423 static bool resume_file
= false;
425 /*****************************************************************************
426 * jewels_setcolors() set the foreground and background colors.
427 ******************************************************************************/
428 static inline void jewels_setcolors(void) {
429 #ifdef HAVE_LCD_COLOR
430 rb
->lcd_set_background(LCD_RGBPACK(49, 26, 26));
431 rb
->lcd_set_foreground(LCD_RGBPACK(210, 181, 181));
435 /*****************************************************************************
436 * jewels_loadgame() loads the saved game and returns load success.
437 ******************************************************************************/
438 static bool jewels_loadgame(struct game_context
* bj
)
444 fd
= rb
->open(SAVE_FILE
, O_RDONLY
);
445 if(fd
< 0) return loaded
;
447 /* read in saved game */
449 if(rb
->read(fd
, &bj
->tmp_type
, sizeof(bj
->tmp_type
)) <= 0) break;
450 if(rb
->read(fd
, &bj
->type
, sizeof(bj
->type
)) <= 0) break;
451 if(rb
->read(fd
, &bj
->score
, sizeof(bj
->score
)) <= 0) break;
452 if(rb
->read(fd
, &bj
->level
, sizeof(bj
->level
)) <= 0) break;
453 if(rb
->read(fd
, &bj
->segments
, sizeof(bj
->segments
)) <= 0) break;
454 if(rb
->read(fd
, &bj
->num_jewels
, sizeof(bj
->num_jewels
)) <= 0) break;
455 if(rb
->read(fd
, bj
->playboard
, sizeof(bj
->playboard
)) <= 0) break;
465 /*****************************************************************************
466 * jewels_savegame() saves the current game state.
467 ******************************************************************************/
468 static void jewels_savegame(struct game_context
* bj
)
471 /* write out the game state to the save file */
472 fd
= rb
->open(SAVE_FILE
, O_WRONLY
|O_CREAT
);
473 rb
->write(fd
, &bj
->tmp_type
, sizeof(bj
->tmp_type
));
474 rb
->write(fd
, &bj
->type
, sizeof(bj
->type
));
475 rb
->write(fd
, &bj
->score
, sizeof(bj
->score
));
476 rb
->write(fd
, &bj
->level
, sizeof(bj
->level
));
477 rb
->write(fd
, &bj
->segments
, sizeof(bj
->segments
));
478 rb
->write(fd
, &bj
->num_jewels
, sizeof(bj
->num_jewels
));
479 rb
->write(fd
, bj
->playboard
, sizeof(bj
->playboard
));
483 /*****************************************************************************
484 * jewels_drawboard() redraws the entire game board.
485 ******************************************************************************/
486 static void jewels_drawboard(struct game_context
* bj
) {
489 unsigned int tempscore
;
491 char *title
= "Level";
494 if (bj
->type
== GAME_TYPE_NORMAL
) {
495 tempscore
= (bj
->score
>LEVEL_PTS
? LEVEL_PTS
: bj
->score
);
498 tempscore
= (bj
->level
>NUM_PUZZLE_LEVELS
? NUM_PUZZLE_LEVELS
: bj
->level
);
499 size
= NUM_PUZZLE_LEVELS
;
503 rb
->lcd_clear_display();
505 /* dispay playing board */
506 for(i
=0; i
<BJ_HEIGHT
-1; i
++){
507 for(j
=0; j
<BJ_WIDTH
; j
++){
508 #ifdef HAVE_LCD_COLOR
509 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
510 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
511 TILE_WIDTH
, TILE_HEIGHT
);
512 rb
->lcd_bitmap_transparent_part(jewels
,
513 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
515 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
516 j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
517 TILE_WIDTH
, TILE_HEIGHT
);
519 rb
->lcd_bitmap_part(jewels
,
520 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
522 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
523 j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
524 TILE_WIDTH
, TILE_HEIGHT
);
529 #if LCD_WIDTH > LCD_HEIGHT /* horizontal layout */
531 /* draw separator lines */
533 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, LCD_HEIGHT
-1);
535 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, 18);
536 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, LCD_HEIGHT
-10);
538 /* draw progress bar */
539 #ifdef HAVE_LCD_COLOR
540 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
542 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
543 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
545 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
546 ((LCD_HEIGHT
-10)-18)*tempscore
/size
);
547 #ifdef HAVE_LCD_COLOR
548 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
549 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
550 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
552 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
553 ((LCD_HEIGHT
-10)-18)*tempscore
/size
-1);
555 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
556 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*tempscore
/size
),
557 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
558 ((LCD_HEIGHT
-10)-18)*tempscore
/size
+1);
562 rb
->lcd_getstringsize(title
, &w
, &h
);
563 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 1, title
);
564 rb
->snprintf(str
, 4, "%d", bj
->level
);
565 rb
->lcd_getstringsize(str
, &w
, &h
);
566 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 10, str
);
568 if (bj
->type
== GAME_TYPE_NORMAL
) {
569 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
570 rb
->lcd_getstringsize(str
, &w
, &h
);
571 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2,
575 #elif LCD_WIDTH < LCD_HEIGHT /* vertical layout */
577 /* draw separator lines */
579 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
580 rb
->lcd_hline(0, LCD_WIDTH
-1, LCD_HEIGHT
-14);
581 rb
->lcd_vline(LCD_WIDTH
/2, LCD_HEIGHT
-14, LCD_HEIGHT
-1);
583 /* draw progress bar */
584 #ifdef HAVE_LCD_COLOR
585 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
587 rb
->lcd_fillrect(0, (8*TILE_HEIGHT
+YOFS
)
588 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
589 LCD_WIDTH
*tempscore
/size
,
590 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
591 #ifdef HAVE_LCD_COLOR
592 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
593 rb
->lcd_drawrect(1, (8*TILE_HEIGHT
+YOFS
)
594 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4+1,
595 LCD_WIDTH
*tempscore
/size
-1,
596 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2-2);
598 rb
->lcd_drawrect(0, (8*TILE_HEIGHT
+YOFS
)
599 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
600 LCD_WIDTH
*tempscore
/size
+1,
601 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
605 rb
->snprintf(str
, 10, "%s %d", title
, bj
->level
);
606 rb
->lcd_putsxy(1, LCD_HEIGHT
-10, str
);
608 if (bj
->type
== GAME_TYPE_NORMAL
) {
609 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
610 rb
->lcd_getstringsize(str
, &w
, &h
);
611 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
, LCD_HEIGHT
-10, str
);
615 #else /* square layout */
617 /* draw separator lines */
619 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
620 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, 8*TILE_HEIGHT
+YOFS
);
621 rb
->lcd_vline(LCD_WIDTH
/2, 8*TILE_HEIGHT
+YOFS
, LCD_HEIGHT
-1);
623 /* draw progress bar */
624 #ifdef HAVE_LCD_COLOR
625 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
627 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
628 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)*tempscore
/size
,
629 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
630 (8*TILE_HEIGHT
+YOFS
)*tempscore
/size
);
631 #ifdef HAVE_LCD_COLOR
632 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
633 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
634 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
636 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
637 (8*TILE_HEIGHT
+YOFS
)*tempscore
/size
-1);
639 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
640 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
642 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
643 (8*TILE_HEIGHT
+YOFS
)*tempscore
/size
+1);
647 rb
->snprintf(str
, 10, "%s %d", title
, bj
->level
);
648 rb
->lcd_putsxy(1, LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3, str
);
650 if (bj
->type
== GAME_TYPE_NORMAL
) {
651 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
652 rb
->lcd_getstringsize(str
, &w
, &h
);
653 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
,
654 LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3, str
);
662 /*****************************************************************************
663 * jewels_putjewels() makes the jewels fall to fill empty spots and adds
664 * new random jewels at the empty spots at the top of each row.
665 ******************************************************************************/
666 static void jewels_putjewels(struct game_context
* bj
){
669 long lasttick
, currenttick
;
671 /* loop to make all the jewels fall */
673 /* mark falling jewels and add new jewels to hidden top row*/
676 for(j
=0; j
<BJ_WIDTH
; j
++) {
677 if(bj
->playboard
[1][j
].type
== 0) {
678 bj
->playboard
[0][j
].type
= rb
->rand()%bj
->num_jewels
+1;
680 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
681 if(!mark
&& bj
->playboard
[i
+1][j
].type
== 0) {
685 if(mark
) bj
->playboard
[i
][j
].falling
= true;
687 /*if(bj->playboard[1][j].falling) {
688 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
689 bj->playboard[0][j].falling = true;
694 /* break if there are no falling jewels */
697 /* animate falling jewels */
698 lasttick
= *rb
->current_tick
;
700 for(k
=1; k
<=8; k
++) {
701 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
702 for(j
=0; j
<BJ_WIDTH
; j
++) {
703 if(bj
->playboard
[i
][j
].falling
&&
704 bj
->playboard
[i
][j
].type
!= 0) {
705 /* clear old position */
706 #ifdef HAVE_LCD_COLOR
708 rb
->lcd_set_foreground(rb
->lcd_get_background());
710 rb
->lcd_set_foreground(jewels_bkgd
[(i
-1+j
)%2]);
712 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
713 TILE_WIDTH
, TILE_HEIGHT
);
714 if(bj
->playboard
[i
+1][j
].type
== 0) {
715 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
716 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
717 TILE_WIDTH
, TILE_HEIGHT
);
720 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
721 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
722 TILE_WIDTH
, TILE_HEIGHT
);
723 if(bj
->playboard
[i
+1][j
].type
== 0) {
724 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
725 TILE_WIDTH
, TILE_HEIGHT
);
727 rb
->lcd_set_drawmode(DRMODE_SOLID
);
730 /* draw new position */
731 #ifdef HAVE_LCD_COLOR
732 rb
->lcd_bitmap_transparent_part(jewels
, 0,
733 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
738 (i
-1)*TILE_HEIGHT
+YOFS
+
739 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
740 TILE_WIDTH
, TILE_HEIGHT
);
742 rb
->lcd_bitmap_part(jewels
, 0,
743 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
748 (i
-1)*TILE_HEIGHT
+YOFS
+
749 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
750 TILE_WIDTH
, TILE_HEIGHT
);
756 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
759 /* framerate limiting */
760 currenttick
= *rb
->current_tick
;
761 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
762 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
766 lasttick
= currenttick
;
769 /* shift jewels down */
770 for(j
=0; j
<BJ_WIDTH
; j
++) {
771 for(i
=BJ_HEIGHT
-1; i
>=1; i
--) {
772 if(bj
->playboard
[i
-1][j
].falling
) {
773 bj
->playboard
[i
][j
].type
= bj
->playboard
[i
-1][j
].type
;
778 /* clear out top row */
779 for(j
=0; j
<BJ_WIDTH
; j
++) {
780 bj
->playboard
[0][j
].type
= 0;
783 /* mark everything not falling */
784 for(i
=0; i
<BJ_HEIGHT
; i
++) {
785 for(j
=0; j
<BJ_WIDTH
; j
++) {
786 bj
->playboard
[i
][j
].falling
= false;
792 /*****************************************************************************
793 * jewels_clearjewels() finds all the connected rows and columns and
794 * calculates and returns the points earned.
795 ******************************************************************************/
796 static unsigned int jewels_clearjewels(struct game_context
* bj
) {
799 unsigned int points
= 0;
801 /* check for connected rows */
802 for(i
=1; i
<BJ_HEIGHT
; i
++) {
805 for(j
=0; j
<BJ_WIDTH
; j
++) {
806 if(bj
->playboard
[i
][j
].type
== last
&&
807 bj
->playboard
[i
][j
].type
!= 0 &&
808 bj
->playboard
[i
][j
].type
<= MAX_NUM_JEWELS
) {
813 points
+= bj
->segments
;
814 bj
->playboard
[i
][j
].delete = true;
815 bj
->playboard
[i
][j
-1].delete = true;
816 bj
->playboard
[i
][j
-2].delete = true;
819 bj
->playboard
[i
][j
].delete = true;
823 last
= bj
->playboard
[i
][j
].type
;
828 /* check for connected columns */
829 for(j
=0; j
<BJ_WIDTH
; j
++) {
832 for(i
=1; i
<BJ_HEIGHT
; i
++) {
833 if(bj
->playboard
[i
][j
].type
!= 0 &&
834 bj
->playboard
[i
][j
].type
== last
&&
835 bj
->playboard
[i
][j
].type
<= MAX_NUM_JEWELS
) {
840 points
+= bj
->segments
;
841 bj
->playboard
[i
][j
].delete = true;
842 bj
->playboard
[i
-1][j
].delete = true;
843 bj
->playboard
[i
-2][j
].delete = true;
846 bj
->playboard
[i
][j
].delete = true;
850 last
= bj
->playboard
[i
][j
].type
;
855 /* clear deleted jewels */
856 for(i
=1; i
<BJ_HEIGHT
; i
++) {
857 for(j
=0; j
<BJ_WIDTH
; j
++) {
858 if(bj
->playboard
[i
][j
].delete) {
859 bj
->playboard
[i
][j
].delete = false;
860 bj
->playboard
[i
][j
].type
= 0;
868 /*****************************************************************************
869 * jewels_runboard() runs the board until it settles in a fixed state and
870 * returns points earned.
871 ******************************************************************************/
872 static unsigned int jewels_runboard(struct game_context
* bj
) {
873 unsigned int points
= 0;
878 while((ret
= jewels_clearjewels(bj
)) > 0) {
880 jewels_drawboard(bj
);
881 jewels_putjewels(bj
);
887 /*****************************************************************************
888 * jewels_swapjewels() swaps two jewels as long as it results in points and
889 * returns points earned.
890 ******************************************************************************/
891 static unsigned int jewels_swapjewels(struct game_context
* bj
,
892 int x
, int y
, int direc
) {
894 int horzmod
, vertmod
;
897 unsigned int points
= 0;
898 long lasttick
, currenttick
;
900 /* check for invalid parameters */
901 if(x
< 0 || x
>= BJ_WIDTH
|| y
< 0 || y
>= BJ_HEIGHT
-1 ||
902 direc
< SWAP_UP
|| direc
> SWAP_LEFT
) {
906 /* check for invalid directions */
907 if((x
== 0 && direc
== SWAP_LEFT
) ||
908 (x
== BJ_WIDTH
-1 && direc
== SWAP_RIGHT
) ||
909 (y
== 0 && direc
== SWAP_UP
) ||
910 (y
== BJ_HEIGHT
-2 && direc
== SWAP_DOWN
)) {
914 /* set direction variables */
920 movelen
= TILE_HEIGHT
;
924 movelen
= TILE_WIDTH
;
928 movelen
= TILE_HEIGHT
;
932 movelen
= TILE_WIDTH
;
937 lasttick
= *rb
->current_tick
;
939 /* animate swapping jewels */
940 for(k
=0; k
<=8; k
++) {
941 /* clear old position */
942 #ifdef HAVE_LCD_COLOR
943 rb
->lcd_set_foreground(jewels_bkgd
[(x
+y
)%2]);
944 rb
->lcd_fillrect(x
*TILE_WIDTH
,
946 TILE_WIDTH
, TILE_HEIGHT
);
947 rb
->lcd_set_foreground(jewels_bkgd
[(x
+horzmod
+y
+vertmod
)%2]);
948 rb
->lcd_fillrect((x
+horzmod
)*TILE_WIDTH
,
949 (y
+vertmod
)*TILE_HEIGHT
+YOFS
,
950 TILE_WIDTH
, TILE_HEIGHT
);
952 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
953 rb
->lcd_fillrect(x
*TILE_WIDTH
,
955 TILE_WIDTH
, TILE_HEIGHT
);
956 rb
->lcd_fillrect((x
+horzmod
)*TILE_WIDTH
,
957 (y
+vertmod
)*TILE_HEIGHT
+YOFS
,
958 TILE_WIDTH
, TILE_HEIGHT
);
959 rb
->lcd_set_drawmode(DRMODE_SOLID
);
961 /* draw new position */
962 #ifdef HAVE_LCD_COLOR
963 rb
->lcd_bitmap_transparent_part(jewels
,
964 0, TILE_HEIGHT
*(bj
->playboard
965 [y
+1+vertmod
][x
+horzmod
].type
),
967 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
968 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
969 ((((movelen
<<10)*k
)/8)>>10),
970 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
971 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
972 TILE_WIDTH
, TILE_HEIGHT
);
973 rb
->lcd_bitmap_transparent_part(jewels
,
974 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
976 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
977 x
*TILE_WIDTH
+horzmod
*
978 ((((movelen
<<10)*k
)/8)>>10),
979 y
*TILE_HEIGHT
+vertmod
*
980 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
981 TILE_WIDTH
, TILE_HEIGHT
);
983 rb
->lcd_bitmap_part(jewels
,
984 0, TILE_HEIGHT
*(bj
->playboard
985 [y
+1+vertmod
][x
+horzmod
].type
),
987 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
988 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
989 ((((movelen
<<10)*k
)/8)>>10),
990 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
991 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
992 TILE_WIDTH
, TILE_HEIGHT
);
993 rb
->lcd_set_drawmode(DRMODE_FG
);
994 rb
->lcd_bitmap_part(jewels
,
995 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
997 BMPWIDTH_jewels
, BMPHEIGHT_jewels
),
998 x
*TILE_WIDTH
+horzmod
*
999 ((((movelen
<<10)*k
)/8)>>10),
1000 y
*TILE_HEIGHT
+vertmod
*
1001 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1002 TILE_WIDTH
, TILE_HEIGHT
);
1003 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1006 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
1009 /* framerate limiting */
1010 currenttick
= *rb
->current_tick
;
1011 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
1012 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
1016 lasttick
= currenttick
;
1020 int temp
= bj
->playboard
[y
+1][x
].type
;
1021 bj
->playboard
[y
+1][x
].type
=
1022 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
;
1023 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
= temp
;
1027 points
= jewels_runboard(bj
);
1038 /*****************************************************************************
1039 * jewels_movesavail() uses pattern matching to see if there are any
1040 * available move left.
1041 ******************************************************************************/
1042 static bool jewels_movesavail(struct game_context
* bj
) {
1047 for(i
=1; i
<BJ_HEIGHT
; i
++) {
1048 for(j
=0; j
<BJ_WIDTH
; j
++) {
1049 mytype
= bj
->playboard
[i
][j
].type
;
1050 if(mytype
== 0 || mytype
> MAX_NUM_JEWELS
) continue;
1052 /* check horizontal patterns */
1053 if(j
<= BJ_WIDTH
-3) {
1055 if(bj
->playboard
[i
-1][j
+1].type
== mytype
) {
1056 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1057 {moves
= true; break;}
1058 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1059 {moves
= true; break;}
1061 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1062 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1063 {moves
= true; break;}
1067 if(j
<= BJ_WIDTH
-4) {
1068 if(bj
->playboard
[i
][j
+3].type
== mytype
) {
1069 if(bj
->playboard
[i
][j
+1].type
== mytype
)
1070 {moves
= true; break;}
1071 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1072 {moves
= true; break;}
1076 if(i
< BJ_HEIGHT
-1) {
1077 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1078 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1079 {moves
= true; break;}
1081 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1082 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1083 {moves
= true; break;}
1084 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1085 {moves
= true; break;}
1090 /* check vertical patterns */
1091 if(i
<= BJ_HEIGHT
-3) {
1093 if(bj
->playboard
[i
+1][j
-1].type
== mytype
) {
1094 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1095 {moves
= true; break;}
1096 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1097 {moves
= true; break;}
1099 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1100 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1101 {moves
= true; break;}
1105 if(i
<= BJ_HEIGHT
-4) {
1106 if(bj
->playboard
[i
+3][j
].type
== mytype
) {
1107 if(bj
->playboard
[i
+1][j
].type
== mytype
)
1108 {moves
= true; break;}
1109 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1110 {moves
= true; break;}
1114 if(j
< BJ_WIDTH
-1) {
1115 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1116 if(bj
->playboard
[i
+2][j
+1].type
== mytype
)
1117 {moves
= true; break;}
1119 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1120 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1121 {moves
= true; break;}
1122 if (bj
->playboard
[i
+2][j
+1].type
== mytype
)
1123 {moves
= true; break;}
1133 /*****************************************************************************
1134 * jewels_puzzle_is_finished() checks if the puzzle is finished.
1135 ******************************************************************************/
1136 static bool jewels_puzzle_is_finished(struct game_context
* bj
) {
1138 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1139 for(j
=0; j
<BJ_WIDTH
; j
++) {
1140 int mytype
= bj
->playboard
[i
][j
].type
;
1141 if(mytype
>MAX_NUM_JEWELS
) {
1142 mytype
-= MAX_NUM_JEWELS
;
1143 if(mytype
&PUZZLE_TILE_UP
) {
1144 if(i
==0 || bj
->playboard
[i
-1][j
].type
<=MAX_NUM_JEWELS
||
1145 !((bj
->playboard
[i
-1][j
].type
-MAX_NUM_JEWELS
)
1149 if(mytype
&PUZZLE_TILE_DOWN
) {
1150 if(i
==BJ_HEIGHT
-1 ||
1151 bj
->playboard
[i
+1][j
].type
<=MAX_NUM_JEWELS
||
1152 !((bj
->playboard
[i
+1][j
].type
-MAX_NUM_JEWELS
)
1156 if(mytype
&PUZZLE_TILE_LEFT
) {
1157 if(j
==0 || bj
->playboard
[i
][j
-1].type
<=MAX_NUM_JEWELS
||
1158 !((bj
->playboard
[i
][j
-1].type
-MAX_NUM_JEWELS
)
1159 &PUZZLE_TILE_RIGHT
))
1162 if(mytype
&PUZZLE_TILE_RIGHT
) {
1164 bj
->playboard
[i
][j
+1].type
<=MAX_NUM_JEWELS
||
1165 !((bj
->playboard
[i
][j
+1].type
-MAX_NUM_JEWELS
)
1175 /*****************************************************************************
1176 * jewels_initlevel() initialises a level.
1177 ******************************************************************************/
1178 static unsigned int jewels_initlevel(struct game_context
* bj
) {
1179 unsigned int points
= 0;
1182 case GAME_TYPE_NORMAL
:
1183 bj
->num_jewels
= MAX_NUM_JEWELS
;
1186 case GAME_TYPE_PUZZLE
:
1189 struct puzzle_tile
*tile
;
1191 bj
->num_jewels
= puzzle_levels
[bj
->level
-1].num_jewels
;
1193 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1194 for(j
=0; j
<BJ_WIDTH
; j
++) {
1195 bj
->playboard
[i
][j
].type
= (rb
->rand()%bj
->num_jewels
)+1;
1196 bj
->playboard
[i
][j
].falling
= false;
1197 bj
->playboard
[i
][j
].delete = false;
1200 jewels_runboard(bj
);
1201 tile
= puzzle_levels
[bj
->level
-1].tiles
;
1202 for(i
=0; i
<puzzle_levels
[bj
->level
-1].num_tiles
; i
++, tile
++) {
1203 bj
->playboard
[tile
->y
+1][tile
->x
].type
= MAX_NUM_JEWELS
1210 jewels_drawboard(bj
);
1212 /* run the play board */
1213 jewels_putjewels(bj
);
1214 points
+= jewels_runboard(bj
);
1218 /*****************************************************************************
1219 * jewels_init() initializes jewels data structures.
1220 ******************************************************************************/
1221 static void jewels_init(struct game_context
* bj
) {
1222 /* seed the rand generator */
1223 rb
->srand(*rb
->current_tick
);
1225 bj
->type
= bj
->tmp_type
;
1232 /* clear playing board */
1233 rb
->memset(bj
->playboard
, 0, sizeof(bj
->playboard
));
1235 bj
->score
+= jewels_initlevel(bj
);
1236 } while(!jewels_movesavail(bj
));
1239 /*****************************************************************************
1240 * jewels_nextlevel() advances the game to the next bj->level and returns
1242 ******************************************************************************/
1243 static void jewels_nextlevel(struct game_context
* bj
) {
1245 unsigned int points
= 0;
1248 case GAME_TYPE_NORMAL
:
1249 /* roll over score, change and display level */
1250 while(bj
->score
>= LEVEL_PTS
) {
1251 bj
->score
-= LEVEL_PTS
;
1253 rb
->splashf(HZ
*2, "Level %d", bj
->level
);
1254 jewels_drawboard(bj
);
1257 /* randomly clear some jewels */
1258 for(i
=0; i
<16; i
++) {
1262 if(bj
->playboard
[y
][x
].type
!= 0) {
1264 bj
->playboard
[y
][x
].type
= 0;
1269 case GAME_TYPE_PUZZLE
:
1271 rb
->splashf(HZ
*2, "Level %d", bj
->level
);
1275 points
+= jewels_initlevel(bj
);
1276 bj
->score
+= points
;
1279 static bool jewels_help(void)
1281 rb
->lcd_setfont(FONT_UI
);
1282 #define WORDS (sizeof help_text / sizeof (char*))
1283 static char *help_text
[] = {
1284 "Jewels", "", "Aim", "",
1285 "Swap", "pairs", "of", "jewels", "to", "form", "connected",
1286 "segments", "of", "three", "or", "more", "of", "the", "same",
1288 "The", "goal", "of", "the", "game", "is", "to", "score", "as", "many",
1289 "points", "as", "possible", "before", "running", "out", "of",
1290 "available", "moves.", "", "",
1293 #ifdef JEWELS_SCROLLWHEEL
1297 HK_SELECT
, "to", "select", "",
1298 HK_CANCEL
, "to", "go", "to", "menu"
1300 static struct style_text formation
[]={
1301 { 0, TEXT_CENTER
|TEXT_UNDERLINE
},
1306 #ifdef HAVE_LCD_COLOR
1307 rb
->lcd_set_background(LCD_BLACK
);
1308 rb
->lcd_set_foreground(LCD_WHITE
);
1311 if (display_text(WORDS
, help_text
, formation
, NULL
))
1314 button
= rb
->button_get(true);
1315 if (rb
->default_event_handler (button
) == SYS_USB_CONNECTED
) {
1318 } while( ( button
== BUTTON_NONE
)
1319 || ( button
& (BUTTON_REL
|BUTTON_REPEAT
) ) );
1320 rb
->lcd_setfont(FONT_SYSFIXED
);
1325 static bool _ingame
;
1326 static int jewels_menu_cb(int action
, const struct menu_item_ex
*this_item
)
1328 int i
= ((intptr_t)this_item
);
1329 if(action
== ACTION_REQUEST_MENUITEM
1330 && !_ingame
&& (i
==0 || i
==6))
1331 return ACTION_EXIT_MENUITEM
;
1334 /*****************************************************************************
1335 * jewels_game_menu() shows the game menu.
1336 ******************************************************************************/
1337 static int jewels_game_menu(struct game_context
* bj
, bool ingame
)
1339 rb
->button_clear_queue();
1344 static struct opt_items mode
[] = {
1349 MENUITEM_STRINGLIST (main_menu
, "Jewels Menu", jewels_menu_cb
,
1356 "Quit without Saving",
1360 switch (rb
->do_menu(&main_menu
, &choice
, NULL
, false)) {
1364 rb
->remove(SAVE_FILE
);
1370 rb
->set_option("Mode", &bj
->tmp_type
, INT
, mode
, 2, NULL
);
1377 highscore_show(NUM_SCORES
, highest
, NUM_SCORES
, true);
1380 playback_control(NULL
);
1386 rb
->splash(HZ
*1, "Saving game ...");
1387 jewels_savegame(bj
);
1390 case MENU_ATTACHED_USB
:
1398 static int jewels_main(struct game_context
* bj
) {
1401 bool selected
= false;
1405 bool loaded
= jewels_loadgame(bj
);
1406 resume_file
= loaded
;
1407 if (jewels_game_menu(bj
, loaded
)!=0)
1410 resume_file
= false;
1412 no_movesavail
= false;
1414 /* refresh the board */
1415 jewels_drawboard(bj
);
1417 /* display the cursor */
1419 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
1420 rb
->lcd_fillrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1421 TILE_WIDTH
, TILE_HEIGHT
);
1422 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1424 rb
->lcd_drawrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1425 TILE_WIDTH
, TILE_HEIGHT
);
1427 rb
->lcd_update_rect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1428 TILE_WIDTH
, TILE_HEIGHT
);
1430 /* handle game button presses */
1432 button
= rb
->button_get(true);
1434 case JEWELS_LEFT
: /* move cursor left */
1435 case (JEWELS_LEFT
|BUTTON_REPEAT
):
1437 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_LEFT
);
1439 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1441 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1445 case JEWELS_RIGHT
: /* move cursor right */
1446 case (JEWELS_RIGHT
|BUTTON_REPEAT
):
1448 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_RIGHT
);
1450 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1456 case JEWELS_DOWN
: /* move cursor down */
1457 case (JEWELS_DOWN
|BUTTON_REPEAT
):
1459 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_DOWN
);
1461 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1463 y
= (y
+1)%(BJ_HEIGHT
-1);
1467 case JEWELS_UP
: /* move cursor up */
1468 case (JEWELS_UP
|BUTTON_REPEAT
):
1470 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_UP
);
1472 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1474 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1478 #ifdef JEWELS_SCROLLWHEEL
1479 case JEWELS_PREV
: /* scroll backwards */
1480 case (JEWELS_PREV
|BUTTON_REPEAT
):
1483 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1485 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1489 case JEWELS_NEXT
: /* scroll forwards */
1490 case (JEWELS_NEXT
|BUTTON_REPEAT
):
1492 if(x
== BJ_WIDTH
-1) {
1493 y
= (y
+1)%(BJ_HEIGHT
-1);
1500 case JEWELS_SELECT
: /* toggle selected */
1501 selected
= !selected
;
1504 #ifdef JEWELS_RC_CANCEL
1505 case JEWELS_RC_CANCEL
:
1507 case JEWELS_CANCEL
: /* end game */
1508 if (jewels_game_menu(bj
, true)!=0)
1513 if (rb
->default_event_handler (button
) == SYS_USB_CONNECTED
)
1514 return PLUGIN_USB_CONNECTED
;
1519 case GAME_TYPE_NORMAL
:
1520 if(bj
->score
>= LEVEL_PTS
)
1521 jewels_nextlevel(bj
);
1523 case GAME_TYPE_PUZZLE
:
1524 if (jewels_puzzle_is_finished(bj
)) {
1525 if (bj
->level
< NUM_PUZZLE_LEVELS
) {
1526 jewels_nextlevel(bj
);
1528 rb
->splash(2*HZ
, "Congratulations!");
1529 rb
->splash(2*HZ
, "You have finished the game!");
1530 if (jewels_game_menu(bj
, false)!=0) {
1538 if (no_movesavail
) {
1540 case GAME_TYPE_NORMAL
:
1541 rb
->splash(HZ
*2, "Game Over!");
1542 rb
->lcd_clear_display();
1543 bj
->score
+= (bj
->level
-1)*LEVEL_PTS
;
1544 position
=highscore_update(bj
->score
, bj
->level
, "",
1545 highest
, NUM_SCORES
);
1547 rb
->splash(HZ
*2, "New High Score");
1549 highscore_show(position
, highest
, NUM_SCORES
, true);
1551 case GAME_TYPE_PUZZLE
:
1552 rb
->splash(2*HZ
, "Game Over");
1555 if (jewels_game_menu(bj
, false)!=0) {
1562 /* this is the plugin entry point */
1563 enum plugin_status
plugin_start(const void* parameter
)
1567 /* load high scores */
1568 highscore_load(HIGH_SCORE
,highest
,NUM_SCORES
);
1570 rb
->lcd_setfont(FONT_SYSFIXED
);
1572 rb
->lcd_set_backdrop(NULL
);
1575 struct game_context bj
;
1576 bj
.tmp_type
= GAME_TYPE_NORMAL
;
1578 highscore_save(HIGH_SCORE
,highest
,NUM_SCORES
);
1579 rb
->lcd_setfont(FONT_UI
);
1584 #endif /* HAVE_LCD_BITMAP */