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"
29 #ifdef HAVE_LCD_BITMAP
33 /* button definitions */
34 #if CONFIG_KEYPAD == RECORDER_PAD
35 #define JEWELS_UP BUTTON_UP
36 #define JEWELS_DOWN BUTTON_DOWN
37 #define JEWELS_LEFT BUTTON_LEFT
38 #define JEWELS_RIGHT BUTTON_RIGHT
39 #define JEWELS_SELECT BUTTON_PLAY
40 #define JEWELS_CANCEL BUTTON_OFF
41 #define HK_SELECT "PLAY"
42 #define HK_CANCEL "OFF"
44 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
45 #define JEWELS_UP BUTTON_UP
46 #define JEWELS_DOWN BUTTON_DOWN
47 #define JEWELS_LEFT BUTTON_LEFT
48 #define JEWELS_RIGHT BUTTON_RIGHT
49 #define JEWELS_SELECT BUTTON_SELECT
50 #define JEWELS_CANCEL BUTTON_OFF
51 #define HK_SELECT "SELECT"
52 #define HK_CANCEL "OFF"
54 #elif CONFIG_KEYPAD == ONDIO_PAD
55 #define JEWELS_UP BUTTON_UP
56 #define JEWELS_DOWN BUTTON_DOWN
57 #define JEWELS_LEFT BUTTON_LEFT
58 #define JEWELS_RIGHT BUTTON_RIGHT
59 #define JEWELS_SELECT BUTTON_MENU
60 #define JEWELS_CANCEL BUTTON_OFF
61 #define HK_SELECT "MENU"
62 #define HK_CANCEL "OFF"
64 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
65 #define JEWELS_UP BUTTON_UP
66 #define JEWELS_DOWN BUTTON_DOWN
67 #define JEWELS_LEFT BUTTON_LEFT
68 #define JEWELS_RIGHT BUTTON_RIGHT
69 #define JEWELS_SELECT BUTTON_SELECT
70 #define JEWELS_CANCEL BUTTON_OFF
71 #define JEWELS_RC_CANCEL BUTTON_RC_STOP
72 #define HK_SELECT "SELECT"
73 #define HK_CANCEL "OFF"
75 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
76 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
77 #define JEWELS_SCROLLWHEEL
78 #define JEWELS_UP BUTTON_MENU
79 #define JEWELS_DOWN BUTTON_PLAY
80 #define JEWELS_LEFT BUTTON_LEFT
81 #define JEWELS_RIGHT BUTTON_RIGHT
82 #define JEWELS_PREV BUTTON_SCROLL_BACK
83 #define JEWELS_NEXT BUTTON_SCROLL_FWD
84 #define JEWELS_SELECT BUTTON_SELECT
85 #define JEWELS_CANCEL (BUTTON_SELECT | BUTTON_MENU)
86 #define HK_SELECT "SELECT"
87 #define HK_CANCEL "SEL + MENU"
89 #elif (CONFIG_KEYPAD == IPOD_3G_PAD)
90 #define JEWELS_LEFT BUTTON_LEFT
91 #define JEWELS_RIGHT BUTTON_RIGHT
92 #define JEWELS_UP BUTTON_SCROLL_BACK
93 #define JEWELS_DOWN BUTTON_SCROLL_FWD
94 #define JEWELS_SELECT BUTTON_SELECT
95 #define JEWELS_CANCEL BUTTON_MENU
96 #define HK_SELECT "SELECT"
97 #define HK_CANCEL "MENU"
99 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
100 #define JEWELS_UP BUTTON_UP
101 #define JEWELS_DOWN BUTTON_DOWN
102 #define JEWELS_LEFT BUTTON_LEFT
103 #define JEWELS_RIGHT BUTTON_RIGHT
104 #define JEWELS_SELECT BUTTON_SELECT
105 #define JEWELS_CANCEL BUTTON_PLAY
106 #define HK_SELECT "SELECT"
107 #define HK_CANCEL "PLAY"
109 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
110 #define JEWELS_UP BUTTON_UP
111 #define JEWELS_DOWN BUTTON_DOWN
112 #define JEWELS_LEFT BUTTON_LEFT
113 #define JEWELS_RIGHT BUTTON_RIGHT
114 #define JEWELS_SELECT BUTTON_SELECT
115 #define JEWELS_CANCEL BUTTON_POWER
116 #define HK_SELECT "SELECT"
117 #define HK_CANCEL "POWER"
119 #elif CONFIG_KEYPAD == GIGABEAT_PAD
120 #define JEWELS_UP BUTTON_UP
121 #define JEWELS_DOWN BUTTON_DOWN
122 #define JEWELS_LEFT BUTTON_LEFT
123 #define JEWELS_RIGHT BUTTON_RIGHT
124 #define JEWELS_SELECT BUTTON_SELECT
125 #define JEWELS_CANCEL BUTTON_POWER
126 #define HK_SELECT "SELECT"
127 #define HK_CANCEL "POWER"
129 #elif CONFIG_KEYPAD == SANSA_E200_PAD
130 #define JEWELS_SCROLLWHEEL
131 #define JEWELS_UP BUTTON_UP
132 #define JEWELS_DOWN BUTTON_DOWN
133 #define JEWELS_LEFT BUTTON_LEFT
134 #define JEWELS_RIGHT BUTTON_RIGHT
135 #define JEWELS_PREV BUTTON_SCROLL_BACK
136 #define JEWELS_NEXT BUTTON_SCROLL_FWD
137 #define JEWELS_SELECT BUTTON_SELECT
138 #define JEWELS_CANCEL BUTTON_POWER
139 #define HK_SELECT "SELECT"
140 #define HK_CANCEL "POWER"
142 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
143 #define JEWELS_SCROLLWHEEL
144 #define JEWELS_UP BUTTON_UP
145 #define JEWELS_DOWN BUTTON_DOWN
146 #define JEWELS_LEFT BUTTON_LEFT
147 #define JEWELS_RIGHT BUTTON_RIGHT
148 #define JEWELS_PREV BUTTON_SCROLL_BACK
149 #define JEWELS_NEXT BUTTON_SCROLL_FWD
150 #define JEWELS_SELECT BUTTON_SELECT
151 #define JEWELS_CANCEL (BUTTON_HOME|BUTTON_REPEAT)
152 #define HK_SELECT "SELECT"
153 #define HK_CANCEL "HOME"
155 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
156 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
157 CONFIG_KEYPAD == SANSA_M200_PAD
158 #define JEWELS_UP BUTTON_UP
159 #define JEWELS_DOWN BUTTON_DOWN
160 #define JEWELS_LEFT BUTTON_LEFT
161 #define JEWELS_RIGHT BUTTON_RIGHT
162 #define JEWELS_SELECT BUTTON_SELECT
163 #define JEWELS_CANCEL BUTTON_POWER
164 #define HK_SELECT "SELECT"
165 #define HK_CANCEL "POWER"
167 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
168 #define JEWELS_UP BUTTON_SCROLL_UP
169 #define JEWELS_DOWN BUTTON_SCROLL_DOWN
170 #define JEWELS_LEFT BUTTON_LEFT
171 #define JEWELS_RIGHT BUTTON_RIGHT
172 #define JEWELS_SELECT BUTTON_PLAY
173 #define JEWELS_CANCEL BUTTON_POWER
174 #define HK_SELECT "PLAY"
175 #define HK_CANCEL "POWER"
177 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
178 #define JEWELS_UP BUTTON_UP
179 #define JEWELS_DOWN BUTTON_DOWN
180 #define JEWELS_LEFT BUTTON_LEFT
181 #define JEWELS_RIGHT BUTTON_RIGHT
182 #define JEWELS_SELECT BUTTON_SELECT
183 #define JEWELS_CANCEL BUTTON_BACK
184 #define HK_SELECT "SELECT"
185 #define HK_CANCEL "BACK"
187 #elif CONFIG_KEYPAD == MROBE100_PAD
188 #define JEWELS_UP BUTTON_UP
189 #define JEWELS_DOWN BUTTON_DOWN
190 #define JEWELS_LEFT BUTTON_LEFT
191 #define JEWELS_RIGHT BUTTON_RIGHT
192 #define JEWELS_SELECT BUTTON_SELECT
193 #define JEWELS_CANCEL BUTTON_POWER
194 #define HK_SELECT "SELECT"
195 #define HK_CANCEL "POWER"
197 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
198 #define JEWELS_UP BUTTON_RC_VOL_UP
199 #define JEWELS_DOWN BUTTON_RC_VOL_DOWN
200 #define JEWELS_LEFT BUTTON_RC_REW
201 #define JEWELS_RIGHT BUTTON_RC_FF
202 #define JEWELS_SELECT BUTTON_RC_PLAY
203 #define JEWELS_CANCEL BUTTON_RC_REC
204 #define HK_SELECT "PLAY"
205 #define HK_CANCEL "REC"
207 #define JEWELS_RC_CANCEL BUTTON_REC
209 #elif CONFIG_KEYPAD == COWOND2_PAD
210 #define JEWELS_CANCEL BUTTON_POWER
211 #define HK_CANCEL "POWER"
213 #elif CONFIG_KEYPAD == IAUDIO67_PAD
214 #define JEWELS_UP BUTTON_STOP
215 #define JEWELS_DOWN BUTTON_PLAY
216 #define JEWELS_LEFT BUTTON_LEFT
217 #define JEWELS_RIGHT BUTTON_RIGHT
218 #define JEWELS_SELECT BUTTON_MENU
219 #define JEWELS_CANCEL BUTTON_POWER
220 #define HK_SELECT "MENU"
221 #define HK_CANCEL "POWER"
223 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
224 #define JEWELS_UP BUTTON_UP
225 #define JEWELS_DOWN BUTTON_DOWN
226 #define JEWELS_LEFT BUTTON_LEFT
227 #define JEWELS_RIGHT BUTTON_RIGHT
228 #define JEWELS_SELECT BUTTON_SELECT
229 #define JEWELS_CANCEL BUTTON_BACK
230 #define HK_SELECT "MIDDLE"
231 #define HK_CANCEL "BACK"
233 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
234 #define JEWELS_UP BUTTON_UP
235 #define JEWELS_DOWN BUTTON_DOWN
236 #define JEWELS_LEFT BUTTON_LEFT
237 #define JEWELS_RIGHT BUTTON_RIGHT
238 #define JEWELS_SELECT BUTTON_SELECT
239 #define JEWELS_CANCEL BUTTON_POWER
240 #define HK_SELECT "SELECT"
241 #define HK_CANCEL "POWER"
243 #elif CONFIG_KEYPAD == ONDAVX747_PAD || \
244 CONFIG_KEYPAD == MROBE500_PAD
245 #define JEWELS_CANCEL BUTTON_POWER
246 #define HK_CANCEL "POWER"
249 #error No keymap defined!
252 #ifdef HAVE_TOUCHSCREEN
254 #define JEWELS_UP BUTTON_TOPMIDDLE
257 #define JEWELS_DOWN BUTTON_BOTTOMMIDDLE
260 #define JEWELS_LEFT BUTTON_MIDLEFT
263 #define JEWELS_RIGHT BUTTON_MIDRIGHT
265 #ifndef JEWELS_SELECT
266 #define JEWELS_SELECT BUTTON_CENTER
267 #define HK_SELECT "CENTER"
269 #ifndef JEWELS_CANCEL
270 #define JEWELS_CANCEL BUTTON_TOPLEFT
271 #define HK_CANCEL "TOPLEFT"
275 /* use 30x30 tiles (iPod Video, Gigabeat, Onda VX747) */
276 #if (LCD_HEIGHT == 240) && (LCD_WIDTH == 320) || \
277 ((LCD_HEIGHT == 320) && (LCD_WIDTH == 240)) || \
278 ((LCD_HEIGHT == 400) && (LCD_WIDTH == 240))
279 #define TILE_WIDTH 30
280 #define TILE_HEIGHT 30
282 #define NUM_SCORES 10
284 /* use 22x22 tiles (H300, iPod Color) */
285 #elif ((LCD_HEIGHT == 176) && (LCD_WIDTH == 220)) || \
286 ((LCD_HEIGHT == 220) && (LCD_WIDTH == 176))
287 #define TILE_WIDTH 22
288 #define TILE_HEIGHT 22
292 /* use 16x16 tiles (iPod Nano) */
293 #elif (LCD_HEIGHT == 132) && (LCD_WIDTH == 176)
294 #define TILE_WIDTH 16
295 #define TILE_HEIGHT 16
299 /* use 16x16 tiles (H100, iAudio X5, iPod 3G, iPod 4G grayscale) */
300 #elif (LCD_HEIGHT == 128) && (LCD_WIDTH == 160)
301 #define TILE_WIDTH 16
302 #define TILE_HEIGHT 16
306 /* use 14x14 tiles (H10 5/6 GB) */
307 #elif (LCD_HEIGHT == 128) && (LCD_WIDTH == 128)
308 #define TILE_WIDTH 14
309 #define TILE_HEIGHT 14
313 /* use 13x13 tiles (iPod Mini) */
314 #elif (LCD_HEIGHT == 110) && (LCD_WIDTH == 138)
315 #define TILE_WIDTH 13
316 #define TILE_HEIGHT 13
320 /* use 12x12 tiles (iAudio M3) */
321 #elif (LCD_HEIGHT == 96) && (LCD_WIDTH == 128)
322 #define TILE_WIDTH 12
323 #define TILE_HEIGHT 12
327 /* use 10x10 tiles (Sansa c200) */
328 #elif (LCD_HEIGHT == 80) && (LCD_WIDTH == 132)
329 #define TILE_WIDTH 10
330 #define TILE_HEIGHT 10
334 /* use 10x8 tiles (iFP 700) */
335 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 128)
336 #define TILE_WIDTH 10
337 #define TILE_HEIGHT 8
341 /* use 10x8 tiles (Recorder, Ondio) */
342 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 112)
343 #define TILE_WIDTH 10
344 #define TILE_HEIGHT 8
349 #error JEWELS: Unsupported LCD
352 /* swap directions */
358 /* play board dimension */
362 /* next level threshold */
363 #define LEVEL_PTS 100
365 /* animation frame rate */
377 /* external bitmaps */
378 extern const fb_data jewels
[];
380 /* tile background colors */
381 #ifdef HAVE_LCD_COLOR
382 static const unsigned jewels_bkgd
[2] = {
383 LCD_RGBPACK(104, 63, 63),
384 LCD_RGBPACK(83, 44, 44)
389 * type is the jewel number 0-7
390 * falling if the jewel is falling
391 * delete marks the jewel for deletion
399 /* the game context struct
400 * score is the current level score
401 * segments is the number of cleared segments in the current run
402 * level is the current level
403 * tmp_type is the select type in the menu
404 * type is the game type (normal or puzzle)
405 * playboard is the game playing board (first row is hidden)
406 * num_jewels is the number of different jewels to use
408 struct game_context
{
410 unsigned int segments
;
413 unsigned int tmp_type
;
414 struct tile playboard
[BJ_HEIGHT
][BJ_WIDTH
];
415 unsigned int num_jewels
;
418 #define MAX_NUM_JEWELS 7
420 #define MAX_PUZZLE_TILES 4
421 #define NUM_PUZZLE_LEVELS 10
429 struct puzzle_level
{
430 unsigned int num_jewels
;
431 unsigned int num_tiles
;
432 struct puzzle_tile tiles
[MAX_PUZZLE_TILES
];
435 #define PUZZLE_TILE_UP 1
436 #define PUZZLE_TILE_DOWN 2
437 #define PUZZLE_TILE_LEFT 4
438 #define PUZZLE_TILE_RIGHT 8
440 struct puzzle_level puzzle_levels
[NUM_PUZZLE_LEVELS
] = {
441 { 5, 2, { {3, 3, PUZZLE_TILE_RIGHT
},
442 {4, 2, PUZZLE_TILE_LEFT
} } },
443 { 5, 2, { {3, 2, PUZZLE_TILE_DOWN
},
444 {3, 4, PUZZLE_TILE_UP
} } },
445 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
446 {3, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
447 {3, 6, PUZZLE_TILE_UP
} } },
448 { 6, 3, { {3, 2, PUZZLE_TILE_RIGHT
},
449 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
450 {5, 4, PUZZLE_TILE_LEFT
} } },
451 { 6, 2, { {3, 4, PUZZLE_TILE_RIGHT
},
452 {4, 2, PUZZLE_TILE_LEFT
} } },
453 { 6, 2, { {3, 2, PUZZLE_TILE_DOWN
},
454 {4, 4, PUZZLE_TILE_UP
} } },
455 { 7, 4, { {3, 2, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
456 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
457 {3, 4, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
458 {4, 4, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
459 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
460 {4, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
461 {3, 6, PUZZLE_TILE_UP
} } },
462 { 7, 3, { {2, 2, PUZZLE_TILE_RIGHT
},
463 {4, 1, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
464 {5, 4, PUZZLE_TILE_LEFT
} } },
465 { 7, 4, { {3, 0, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
466 {5, 0, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
467 {2, 7, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
468 {4, 7, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
471 #define SAVE_FILE PLUGIN_GAMES_DIR "/jewels.save"
473 #define HIGH_SCORE PLUGIN_GAMES_DIR "/jewels.score"
474 struct highscore highest
[NUM_SCORES
];
475 bool highest_updated
= false;
478 /*****************************************************************************
479 * jewels_setcolors() set the foreground and background colors.
480 ******************************************************************************/
481 static inline void jewels_setcolors(void) {
482 #ifdef HAVE_LCD_COLOR
483 rb
->lcd_set_background(LCD_RGBPACK(49, 26, 26));
484 rb
->lcd_set_foreground(LCD_RGBPACK(210, 181, 181));
488 /*****************************************************************************
489 * jewels_loadgame() loads the saved game and returns load success.
490 ******************************************************************************/
491 static bool jewels_loadgame(struct game_context
* bj
)
497 fd
= rb
->open(SAVE_FILE
, O_RDONLY
);
498 if(fd
< 0) return loaded
;
500 /* read in saved game */
502 if(rb
->read(fd
, &bj
->tmp_type
, sizeof(bj
->tmp_type
)) <= 0) break;
503 if(rb
->read(fd
, &bj
->type
, sizeof(bj
->type
)) <= 0) break;
504 if(rb
->read(fd
, &bj
->score
, sizeof(bj
->score
)) <= 0) break;
505 if(rb
->read(fd
, &bj
->level
, sizeof(bj
->level
)) <= 0) break;
506 if(rb
->read(fd
, &bj
->segments
, sizeof(bj
->segments
)) <= 0) break;
507 if(rb
->read(fd
, &bj
->num_jewels
, sizeof(bj
->num_jewels
)) <= 0) break;
508 if(rb
->read(fd
, bj
->playboard
, sizeof(bj
->playboard
)) <= 0) break;
515 /* delete saved file */
516 rb
->remove(SAVE_FILE
);
520 /*****************************************************************************
521 * jewels_savegame() saves the current game state.
522 ******************************************************************************/
523 static void jewels_savegame(struct game_context
* bj
)
526 /* write out the game state to the save file */
527 fd
= rb
->open(SAVE_FILE
, O_WRONLY
|O_CREAT
);
528 rb
->write(fd
, &bj
->tmp_type
, sizeof(bj
->tmp_type
));
529 rb
->write(fd
, &bj
->type
, sizeof(bj
->type
));
530 rb
->write(fd
, &bj
->score
, sizeof(bj
->score
));
531 rb
->write(fd
, &bj
->level
, sizeof(bj
->level
));
532 rb
->write(fd
, &bj
->segments
, sizeof(bj
->segments
));
533 rb
->write(fd
, &bj
->num_jewels
, sizeof(bj
->num_jewels
));
534 rb
->write(fd
, bj
->playboard
, sizeof(bj
->playboard
));
538 /*****************************************************************************
539 * jewels_drawboard() redraws the entire game board.
540 ******************************************************************************/
541 static void jewels_drawboard(struct game_context
* bj
) {
544 unsigned int tempscore
;
545 char *title
= "Level";
548 tempscore
= (bj
->score
>LEVEL_PTS
? LEVEL_PTS
: bj
->score
);
551 rb
->lcd_clear_display();
553 /* dispay playing board */
554 for(i
=0; i
<BJ_HEIGHT
-1; i
++){
555 for(j
=0; j
<BJ_WIDTH
; j
++){
556 #ifdef HAVE_LCD_COLOR
557 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
558 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
559 TILE_WIDTH
, TILE_HEIGHT
);
560 rb
->lcd_bitmap_transparent_part(jewels
,
561 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
562 TILE_WIDTH
, j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
563 TILE_WIDTH
, TILE_HEIGHT
);
565 rb
->lcd_bitmap_part(jewels
,
566 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
567 TILE_WIDTH
, j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
568 TILE_WIDTH
, TILE_HEIGHT
);
573 #if LCD_WIDTH > LCD_HEIGHT /* horizontal layout */
575 /* draw separator lines */
577 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, LCD_HEIGHT
-1);
578 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, 18);
579 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, LCD_HEIGHT
-10);
581 /* draw progress bar */
582 #ifdef HAVE_LCD_COLOR
583 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
585 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
586 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
587 tempscore
/LEVEL_PTS
),
588 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
589 ((LCD_HEIGHT
-10)-18)*tempscore
/LEVEL_PTS
);
590 #ifdef HAVE_LCD_COLOR
591 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
592 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
593 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
594 tempscore
/LEVEL_PTS
)+1,
595 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
596 ((LCD_HEIGHT
-10)-18)*tempscore
/LEVEL_PTS
-1);
598 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
599 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
600 tempscore
/LEVEL_PTS
),
601 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
602 ((LCD_HEIGHT
-10)-18)*tempscore
/LEVEL_PTS
+1);
606 rb
->lcd_getstringsize(title
, &w
, &h
);
607 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 1, title
);
609 rb
->snprintf(str
, 4, "%d", bj
->level
);
610 rb
->lcd_getstringsize(str
, &w
, &h
);
611 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 10, str
);
613 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
614 rb
->lcd_getstringsize(str
, &w
, &h
);
615 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2,
618 #elif LCD_WIDTH < LCD_HEIGHT /* vertical layout */
620 /* draw separator lines */
622 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
623 rb
->lcd_hline(0, LCD_WIDTH
-1, LCD_HEIGHT
-14);
624 rb
->lcd_vline(LCD_WIDTH
/2, LCD_HEIGHT
-14, LCD_HEIGHT
-1);
626 /* draw progress bar */
627 #ifdef HAVE_LCD_COLOR
628 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
630 rb
->lcd_fillrect(0, (8*TILE_HEIGHT
+YOFS
)
631 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
632 LCD_WIDTH
*tempscore
/LEVEL_PTS
,
633 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
634 #ifdef HAVE_LCD_COLOR
635 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
636 rb
->lcd_drawrect(1, (8*TILE_HEIGHT
+YOFS
)
637 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4+1,
638 LCD_WIDTH
*tempscore
/LEVEL_PTS
-1,
639 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2-2);
641 rb
->lcd_drawrect(0, (8*TILE_HEIGHT
+YOFS
)
642 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
643 LCD_WIDTH
*tempscore
/LEVEL_PTS
+1,
644 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
648 rb
->snprintf(str
, 10, "%s %d", title
, bj
->level
);
649 rb
->lcd_putsxy(1, LCD_HEIGHT
-10, str
);
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
, LCD_HEIGHT
-10, str
);
655 #else /* square layout */
657 /* draw separator lines */
659 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
660 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, 8*TILE_HEIGHT
+YOFS
);
661 rb
->lcd_vline(LCD_WIDTH
/2, 8*TILE_HEIGHT
+YOFS
, LCD_HEIGHT
-1);
663 /* draw progress bar */
664 #ifdef HAVE_LCD_COLOR
665 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
667 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
668 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
669 *tempscore
/LEVEL_PTS
,
670 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
671 (8*TILE_HEIGHT
+YOFS
)*tempscore
/LEVEL_PTS
);
672 #ifdef HAVE_LCD_COLOR
673 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
674 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
675 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
676 *tempscore
/LEVEL_PTS
+1,
677 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
678 (8*TILE_HEIGHT
+YOFS
)*tempscore
/LEVEL_PTS
-1);
680 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
681 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
682 *tempscore
/LEVEL_PTS
,
683 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
684 (8*TILE_HEIGHT
+YOFS
)*tempscore
/LEVEL_PTS
+1);
688 rb
->snprintf(str
, 10, "%s %d", title
, bj
->level
);
689 rb
->lcd_putsxy(1, LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3, str
);
691 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
692 rb
->lcd_getstringsize(str
, &w
, &h
);
693 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
,
694 LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3, str
);
701 /*****************************************************************************
702 * jewels_putjewels() makes the jewels fall to fill empty spots and adds
703 * new random jewels at the empty spots at the top of each row.
704 ******************************************************************************/
705 static void jewels_putjewels(struct game_context
* bj
){
708 long lasttick
, currenttick
;
710 /* loop to make all the jewels fall */
712 /* mark falling jewels and add new jewels to hidden top row*/
715 for(j
=0; j
<BJ_WIDTH
; j
++) {
716 if(bj
->playboard
[1][j
].type
== 0) {
717 bj
->playboard
[0][j
].type
= rb
->rand()%bj
->num_jewels
+1;
719 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
720 if(!mark
&& bj
->playboard
[i
+1][j
].type
== 0) {
724 if(mark
) bj
->playboard
[i
][j
].falling
= true;
726 /*if(bj->playboard[1][j].falling) {
727 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
728 bj->playboard[0][j].falling = true;
733 /* break if there are no falling jewels */
736 /* animate falling jewels */
737 lasttick
= *rb
->current_tick
;
739 for(k
=1; k
<=8; k
++) {
740 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
741 for(j
=0; j
<BJ_WIDTH
; j
++) {
742 if(bj
->playboard
[i
][j
].falling
&&
743 bj
->playboard
[i
][j
].type
!= 0) {
744 /* clear old position */
745 #ifdef HAVE_LCD_COLOR
747 rb
->lcd_set_foreground(rb
->lcd_get_background());
749 rb
->lcd_set_foreground(jewels_bkgd
[(i
-1+j
)%2]);
751 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
752 TILE_WIDTH
, TILE_HEIGHT
);
753 if(bj
->playboard
[i
+1][j
].type
== 0) {
754 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
755 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
756 TILE_WIDTH
, TILE_HEIGHT
);
759 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
760 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
761 TILE_WIDTH
, TILE_HEIGHT
);
762 if(bj
->playboard
[i
+1][j
].type
== 0) {
763 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
764 TILE_WIDTH
, TILE_HEIGHT
);
766 rb
->lcd_set_drawmode(DRMODE_SOLID
);
769 /* draw new position */
770 #ifdef HAVE_LCD_COLOR
771 rb
->lcd_bitmap_transparent_part(jewels
, 0,
772 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
773 TILE_WIDTH
, j
*TILE_WIDTH
,
774 (i
-1)*TILE_HEIGHT
+YOFS
+
775 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
776 TILE_WIDTH
, TILE_HEIGHT
);
778 rb
->lcd_bitmap_part(jewels
, 0,
779 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
780 TILE_WIDTH
, j
*TILE_WIDTH
,
781 (i
-1)*TILE_HEIGHT
+YOFS
+
782 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
783 TILE_WIDTH
, TILE_HEIGHT
);
789 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
792 /* framerate limiting */
793 currenttick
= *rb
->current_tick
;
794 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
795 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
799 lasttick
= currenttick
;
802 /* shift jewels down */
803 for(j
=0; j
<BJ_WIDTH
; j
++) {
804 for(i
=BJ_HEIGHT
-1; i
>=1; i
--) {
805 if(bj
->playboard
[i
-1][j
].falling
) {
806 bj
->playboard
[i
][j
].type
= bj
->playboard
[i
-1][j
].type
;
811 /* clear out top row */
812 for(j
=0; j
<BJ_WIDTH
; j
++) {
813 bj
->playboard
[0][j
].type
= 0;
816 /* mark everything not falling */
817 for(i
=0; i
<BJ_HEIGHT
; i
++) {
818 for(j
=0; j
<BJ_WIDTH
; j
++) {
819 bj
->playboard
[i
][j
].falling
= false;
825 /*****************************************************************************
826 * jewels_clearjewels() finds all the connected rows and columns and
827 * calculates and returns the points earned.
828 ******************************************************************************/
829 static unsigned int jewels_clearjewels(struct game_context
* bj
) {
832 unsigned int points
= 0;
834 /* check for connected rows */
835 for(i
=1; i
<BJ_HEIGHT
; i
++) {
838 for(j
=0; j
<BJ_WIDTH
; j
++) {
839 if(bj
->playboard
[i
][j
].type
== last
&&
840 bj
->playboard
[i
][j
].type
!= 0 &&
841 bj
->playboard
[i
][j
].type
<= MAX_NUM_JEWELS
) {
846 points
+= bj
->segments
;
847 bj
->playboard
[i
][j
].delete = true;
848 bj
->playboard
[i
][j
-1].delete = true;
849 bj
->playboard
[i
][j
-2].delete = true;
852 bj
->playboard
[i
][j
].delete = true;
856 last
= bj
->playboard
[i
][j
].type
;
861 /* check for connected columns */
862 for(j
=0; j
<BJ_WIDTH
; j
++) {
865 for(i
=1; i
<BJ_HEIGHT
; i
++) {
866 if(bj
->playboard
[i
][j
].type
!= 0 &&
867 bj
->playboard
[i
][j
].type
== last
&&
868 bj
->playboard
[i
][j
].type
<= MAX_NUM_JEWELS
) {
873 points
+= bj
->segments
;
874 bj
->playboard
[i
][j
].delete = true;
875 bj
->playboard
[i
-1][j
].delete = true;
876 bj
->playboard
[i
-2][j
].delete = true;
879 bj
->playboard
[i
][j
].delete = true;
883 last
= bj
->playboard
[i
][j
].type
;
888 /* clear deleted jewels */
889 for(i
=1; i
<BJ_HEIGHT
; i
++) {
890 for(j
=0; j
<BJ_WIDTH
; j
++) {
891 if(bj
->playboard
[i
][j
].delete) {
892 bj
->playboard
[i
][j
].delete = false;
893 bj
->playboard
[i
][j
].type
= 0;
901 /*****************************************************************************
902 * jewels_runboard() runs the board until it settles in a fixed state and
903 * returns points earned.
904 ******************************************************************************/
905 static unsigned int jewels_runboard(struct game_context
* bj
) {
906 unsigned int points
= 0;
911 while((ret
= jewels_clearjewels(bj
)) > 0) {
913 jewels_drawboard(bj
);
914 jewels_putjewels(bj
);
920 /*****************************************************************************
921 * jewels_swapjewels() swaps two jewels as long as it results in points and
922 * returns points earned.
923 ******************************************************************************/
924 static unsigned int jewels_swapjewels(struct game_context
* bj
,
925 int x
, int y
, int direc
) {
927 int horzmod
, vertmod
;
930 unsigned int points
= 0;
931 long lasttick
, currenttick
;
933 /* check for invalid parameters */
934 if(x
< 0 || x
>= BJ_WIDTH
|| y
< 0 || y
>= BJ_HEIGHT
-1 ||
935 direc
< SWAP_UP
|| direc
> SWAP_LEFT
) {
939 /* check for invalid directions */
940 if((x
== 0 && direc
== SWAP_LEFT
) ||
941 (x
== BJ_WIDTH
-1 && direc
== SWAP_RIGHT
) ||
942 (y
== 0 && direc
== SWAP_UP
) ||
943 (y
== BJ_HEIGHT
-2 && direc
== SWAP_DOWN
)) {
947 /* set direction variables */
953 movelen
= TILE_HEIGHT
;
957 movelen
= TILE_WIDTH
;
961 movelen
= TILE_HEIGHT
;
965 movelen
= TILE_WIDTH
;
970 lasttick
= *rb
->current_tick
;
972 /* animate swapping jewels */
973 for(k
=0; k
<=8; k
++) {
974 /* clear old position */
975 #ifdef HAVE_LCD_COLOR
976 rb
->lcd_set_foreground(jewels_bkgd
[(x
+y
)%2]);
977 rb
->lcd_fillrect(x
*TILE_WIDTH
,
979 TILE_WIDTH
, TILE_HEIGHT
);
980 rb
->lcd_set_foreground(jewels_bkgd
[(x
+horzmod
+y
+vertmod
)%2]);
981 rb
->lcd_fillrect((x
+horzmod
)*TILE_WIDTH
,
982 (y
+vertmod
)*TILE_HEIGHT
+YOFS
,
983 TILE_WIDTH
, TILE_HEIGHT
);
985 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
986 rb
->lcd_fillrect(x
*TILE_WIDTH
,
988 TILE_WIDTH
, TILE_HEIGHT
);
989 rb
->lcd_fillrect((x
+horzmod
)*TILE_WIDTH
,
990 (y
+vertmod
)*TILE_HEIGHT
+YOFS
,
991 TILE_WIDTH
, TILE_HEIGHT
);
992 rb
->lcd_set_drawmode(DRMODE_SOLID
);
994 /* draw new position */
995 #ifdef HAVE_LCD_COLOR
996 rb
->lcd_bitmap_transparent_part(jewels
,
997 0, TILE_HEIGHT
*(bj
->playboard
998 [y
+1+vertmod
][x
+horzmod
].type
), TILE_WIDTH
,
999 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
1000 ((((movelen
<<10)*k
)/8)>>10),
1001 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
1002 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1003 TILE_WIDTH
, TILE_HEIGHT
);
1004 rb
->lcd_bitmap_transparent_part(jewels
,
1005 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
1006 TILE_WIDTH
, x
*TILE_WIDTH
+horzmod
*
1007 ((((movelen
<<10)*k
)/8)>>10),
1008 y
*TILE_HEIGHT
+vertmod
*
1009 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1010 TILE_WIDTH
, TILE_HEIGHT
);
1012 rb
->lcd_bitmap_part(jewels
,
1013 0, TILE_HEIGHT
*(bj
->playboard
1014 [y
+1+vertmod
][x
+horzmod
].type
), TILE_WIDTH
,
1015 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
1016 ((((movelen
<<10)*k
)/8)>>10),
1017 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
1018 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1019 TILE_WIDTH
, TILE_HEIGHT
);
1020 rb
->lcd_set_drawmode(DRMODE_FG
);
1021 rb
->lcd_bitmap_part(jewels
,
1022 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
1023 TILE_WIDTH
, 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
);
1028 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1031 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
1034 /* framerate limiting */
1035 currenttick
= *rb
->current_tick
;
1036 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
1037 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
1041 lasttick
= currenttick
;
1045 int temp
= bj
->playboard
[y
+1][x
].type
;
1046 bj
->playboard
[y
+1][x
].type
=
1047 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
;
1048 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
= temp
;
1052 points
= jewels_runboard(bj
);
1063 /*****************************************************************************
1064 * jewels_movesavail() uses pattern matching to see if there are any
1065 * available move left.
1066 ******************************************************************************/
1067 static bool jewels_movesavail(struct game_context
* bj
) {
1072 for(i
=1; i
<BJ_HEIGHT
; i
++) {
1073 for(j
=0; j
<BJ_WIDTH
; j
++) {
1074 mytype
= bj
->playboard
[i
][j
].type
;
1075 if(mytype
== 0 || mytype
> MAX_NUM_JEWELS
) continue;
1077 /* check horizontal patterns */
1078 if(j
<= BJ_WIDTH
-3) {
1080 if(bj
->playboard
[i
-1][j
+1].type
== mytype
) {
1081 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1082 {moves
= true; break;}
1083 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1084 {moves
= true; break;}
1086 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1087 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1088 {moves
= true; break;}
1092 if(j
<= BJ_WIDTH
-4) {
1093 if(bj
->playboard
[i
][j
+3].type
== mytype
) {
1094 if(bj
->playboard
[i
][j
+1].type
== mytype
)
1095 {moves
= true; break;}
1096 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1097 {moves
= true; break;}
1101 if(i
< BJ_HEIGHT
-1) {
1102 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1103 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1104 {moves
= true; break;}
1106 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1107 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1108 {moves
= true; break;}
1109 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1110 {moves
= true; break;}
1115 /* check vertical patterns */
1116 if(i
<= BJ_HEIGHT
-3) {
1118 if(bj
->playboard
[i
+1][j
-1].type
== mytype
) {
1119 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1120 {moves
= true; break;}
1121 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1122 {moves
= true; break;}
1124 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1125 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1126 {moves
= true; break;}
1130 if(i
<= BJ_HEIGHT
-4) {
1131 if(bj
->playboard
[i
+3][j
].type
== mytype
) {
1132 if(bj
->playboard
[i
+1][j
].type
== mytype
)
1133 {moves
= true; break;}
1134 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1135 {moves
= true; break;}
1139 if(j
< BJ_WIDTH
-1) {
1140 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1141 if(bj
->playboard
[i
+2][j
+1].type
== mytype
)
1142 {moves
= true; break;}
1144 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1145 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1146 {moves
= true; break;}
1147 if (bj
->playboard
[i
+2][j
+1].type
== mytype
)
1148 {moves
= true; break;}
1158 /*****************************************************************************
1159 * jewels_puzzle_is_finished() checks if the puzzle is finished.
1160 ******************************************************************************/
1161 static bool jewels_puzzle_is_finished(struct game_context
* bj
) {
1163 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1164 for(j
=0; j
<BJ_WIDTH
; j
++) {
1165 int mytype
= bj
->playboard
[i
][j
].type
;
1166 if(mytype
>MAX_NUM_JEWELS
) {
1167 mytype
-= MAX_NUM_JEWELS
;
1168 if(mytype
&PUZZLE_TILE_UP
) {
1169 if(i
==0 || bj
->playboard
[i
-1][j
].type
<=MAX_NUM_JEWELS
||
1170 !((bj
->playboard
[i
-1][j
].type
-MAX_NUM_JEWELS
)
1174 if(mytype
&PUZZLE_TILE_DOWN
) {
1175 if(i
==BJ_HEIGHT
-1 ||
1176 bj
->playboard
[i
+1][j
].type
<=MAX_NUM_JEWELS
||
1177 !((bj
->playboard
[i
+1][j
].type
-MAX_NUM_JEWELS
)
1181 if(mytype
&PUZZLE_TILE_LEFT
) {
1182 if(j
==0 || bj
->playboard
[i
][j
-1].type
<=MAX_NUM_JEWELS
||
1183 !((bj
->playboard
[i
][j
-1].type
-MAX_NUM_JEWELS
)
1184 &PUZZLE_TILE_RIGHT
))
1187 if(mytype
&PUZZLE_TILE_RIGHT
) {
1189 bj
->playboard
[i
][j
+1].type
<=MAX_NUM_JEWELS
||
1190 !((bj
->playboard
[i
][j
+1].type
-MAX_NUM_JEWELS
)
1200 /*****************************************************************************
1201 * jewels_initlevel() initialises a level.
1202 ******************************************************************************/
1203 static unsigned int jewels_initlevel(struct game_context
* bj
) {
1204 unsigned int points
= 0;
1207 case GAME_TYPE_NORMAL
:
1208 bj
->num_jewels
= MAX_NUM_JEWELS
;
1211 case GAME_TYPE_PUZZLE
:
1214 struct puzzle_tile
*tile
;
1216 bj
->num_jewels
= puzzle_levels
[bj
->level
-1].num_jewels
;
1218 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1219 for(j
=0; j
<BJ_WIDTH
; j
++) {
1220 bj
->playboard
[i
][j
].type
= (rb
->rand()%bj
->num_jewels
)+1;
1221 bj
->playboard
[i
][j
].falling
= false;
1222 bj
->playboard
[i
][j
].delete = false;
1225 jewels_runboard(bj
);
1226 tile
= puzzle_levels
[bj
->level
-1].tiles
;
1227 for(i
=0; i
<puzzle_levels
[bj
->level
-1].num_tiles
; i
++, tile
++) {
1228 bj
->playboard
[tile
->y
+1][tile
->x
].type
= MAX_NUM_JEWELS
1235 jewels_drawboard(bj
);
1237 /* run the play board */
1238 jewels_putjewels(bj
);
1239 points
+= jewels_runboard(bj
);
1243 /*****************************************************************************
1244 * jewels_init() initializes jewels data structures.
1245 ******************************************************************************/
1246 static void jewels_init(struct game_context
* bj
) {
1247 /* seed the rand generator */
1248 rb
->srand(*rb
->current_tick
);
1250 bj
->type
= bj
->tmp_type
;
1257 /* clear playing board */
1258 rb
->memset(bj
->playboard
, 0, sizeof(bj
->playboard
));
1260 bj
->score
+= jewels_initlevel(bj
);
1261 } while(!jewels_movesavail(bj
));
1264 /*****************************************************************************
1265 * jewels_nextlevel() advances the game to the next bj->level and returns
1267 ******************************************************************************/
1268 static void jewels_nextlevel(struct game_context
* bj
) {
1270 unsigned int points
= 0;
1273 case GAME_TYPE_NORMAL
:
1274 /* roll over score, change and display level */
1275 while(bj
->score
>= LEVEL_PTS
) {
1276 bj
->score
-= LEVEL_PTS
;
1278 rb
->splashf(HZ
*2, "Level %d", bj
->level
);
1279 jewels_drawboard(bj
);
1282 /* randomly clear some jewels */
1283 for(i
=0; i
<16; i
++) {
1287 if(bj
->playboard
[y
][x
].type
!= 0) {
1289 bj
->playboard
[y
][x
].type
= 0;
1294 case GAME_TYPE_PUZZLE
:
1296 rb
->splashf(HZ
*2, "Level %d", bj
->level
);
1300 points
+= jewels_initlevel(bj
);
1301 bj
->score
+= points
;
1304 static void jewels_show_highscores(int position
)
1309 #ifdef HAVE_LCD_COLOR
1310 rb
->lcd_set_background(LCD_BLACK
);
1311 rb
->lcd_set_foreground(LCD_WHITE
);
1313 rb
->button_clear_queue();
1314 rb
->lcd_clear_display();
1316 rb
->lcd_setfont(FONT_UI
);
1317 rb
->lcd_getstringsize("High Scores", &w
, &h
);
1318 /* check wether it fits on screen */
1319 if ((4*h
+ h
*(NUM_SCORES
-1) + MARGIN
) > LCD_HEIGHT
) {
1320 rb
->lcd_setfont(FONT_SYSFIXED
);
1321 rb
->lcd_getstringsize("High Scores", &w
, &h
);
1323 rb
->lcd_putsxy(LCD_WIDTH
/2-w
/2, MARGIN
, "High Scores");
1324 rb
->lcd_putsxy(LCD_WIDTH
/4-w
/4,2*h
, "Score");
1325 rb
->lcd_putsxy(LCD_WIDTH
*3/4-w
/4,2*h
, "Level");
1327 for (i
= 0; i
<NUM_SCORES
; i
++)
1329 #ifdef HAVE_LCD_COLOR
1330 if (i
== position
) {
1331 rb
->lcd_set_foreground(LCD_RGBPACK(245,0,0));
1334 rb
->snprintf (str
, sizeof (str
), "%d)", i
+1);
1335 rb
->lcd_putsxy (MARGIN
,3*h
+ h
*i
, str
);
1336 rb
->snprintf (str
, sizeof (str
), "%d", highest
[i
].score
);
1337 rb
->lcd_putsxy (LCD_WIDTH
/4-w
/4,3*h
+ h
*i
, str
);
1338 rb
->snprintf (str
, sizeof (str
), "%d", highest
[i
].level
);
1339 rb
->lcd_putsxy (LCD_WIDTH
*3/4-w
/4,3*h
+ h
*i
, str
);
1341 #ifdef HAVE_LCD_COLOR
1342 rb
->lcd_set_foreground(LCD_WHITE
);
1344 rb
->lcd_hline(MARGIN
, LCD_WIDTH
-MARGIN
, 3*h
+ h
*(i
+1));
1349 rb
->button_get(true);
1350 rb
->lcd_setfont(FONT_SYSFIXED
);
1353 static int jewels_help(void)
1355 rb
->lcd_setfont(FONT_UI
);
1356 #define WORDS (sizeof help_text / sizeof (char*))
1357 static char *help_text
[] = {
1358 "Jewels", "", "Aim", "",
1359 "Swap", "pairs", "of", "jewels", "to", "form", "connected",
1360 "segments", "of", "three", "or", "more", "of", "the", "same",
1362 "The", "goal", "of", "the", "game", "is", "to", "score", "as", "many",
1363 "points", "as", "possible", "before", "running", "out", "of",
1364 "available", "moves.", "", "",
1367 #ifdef JEWELS_SCROLLWHEEL
1371 HK_SELECT
, "to", "select", "",
1372 HK_CANCEL
, "to", "go", "to", "menu"
1374 static struct style_text formation
[]={
1375 { 0, TEXT_CENTER
|TEXT_UNDERLINE
},
1380 #ifdef HAVE_LCD_COLOR
1381 rb
->lcd_set_background(LCD_BLACK
);
1382 rb
->lcd_set_foreground(LCD_WHITE
);
1384 if (display_text(WORDS
, help_text
, formation
, NULL
)==PLUGIN_USB_CONNECTED
)
1385 return PLUGIN_USB_CONNECTED
;
1388 button
= rb
->button_get(true);
1389 if (button
== SYS_USB_CONNECTED
) {
1390 return PLUGIN_USB_CONNECTED
;
1392 } while( ( button
== BUTTON_NONE
)
1393 || ( button
& (BUTTON_REL
|BUTTON_REPEAT
) ) );
1394 rb
->lcd_setfont(FONT_SYSFIXED
);
1399 static bool _ingame
;
1400 static int jewels_menu_cb(int action
, const struct menu_item_ex
*this_item
)
1402 int i
= ((intptr_t)this_item
);
1403 if(action
== ACTION_REQUEST_MENUITEM
1404 && !_ingame
&& (i
==0 || i
==6))
1405 return ACTION_EXIT_MENUITEM
;
1408 /*****************************************************************************
1409 * jewels_game_menu() shows the game menu.
1410 ******************************************************************************/
1411 static int jewels_game_menu(struct game_context
* bj
, bool ingame
)
1413 rb
->button_clear_queue();
1418 static struct opt_items mode
[] = {
1423 MENUITEM_STRINGLIST (main_menu
, "Jewels Menu", jewels_menu_cb
,
1434 switch (rb
->do_menu(&main_menu
, &choice
, NULL
, false)) {
1442 rb
->set_option("Mode", &bj
->tmp_type
, INT
, mode
, 2, NULL
);
1448 jewels_show_highscores(NUM_SCORES
);
1451 playback_control(NULL
);
1455 rb
->splash(HZ
*1, "Saving game ...");
1456 jewels_savegame(bj
);
1461 case MENU_ATTACHED_USB
:
1469 static int jewels_main(struct game_context
* bj
) {
1472 bool selected
= false;
1476 bool loaded
= jewels_loadgame(bj
);
1477 if (jewels_game_menu(bj
, loaded
)!=0)
1481 no_movesavail
= false;
1483 /* refresh the board */
1484 jewels_drawboard(bj
);
1486 /* display the cursor */
1488 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
1489 rb
->lcd_fillrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1490 TILE_WIDTH
, TILE_HEIGHT
);
1491 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1493 rb
->lcd_drawrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1494 TILE_WIDTH
, TILE_HEIGHT
);
1496 rb
->lcd_update_rect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1497 TILE_WIDTH
, TILE_HEIGHT
);
1499 /* handle game button presses */
1501 button
= rb
->button_get(true);
1503 case JEWELS_LEFT
: /* move cursor left */
1504 case (JEWELS_LEFT
|BUTTON_REPEAT
):
1506 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_LEFT
);
1508 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1510 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1514 case JEWELS_RIGHT
: /* move cursor right */
1515 case (JEWELS_RIGHT
|BUTTON_REPEAT
):
1517 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_RIGHT
);
1519 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1525 case JEWELS_DOWN
: /* move cursor down */
1526 case (JEWELS_DOWN
|BUTTON_REPEAT
):
1528 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_DOWN
);
1530 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1532 y
= (y
+1)%(BJ_HEIGHT
-1);
1536 case JEWELS_UP
: /* move cursor up */
1537 case (JEWELS_UP
|BUTTON_REPEAT
):
1539 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_UP
);
1541 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1543 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1547 #ifdef JEWELS_SCROLLWHEEL
1548 case JEWELS_PREV
: /* scroll backwards */
1549 case (JEWELS_PREV
|BUTTON_REPEAT
):
1552 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1554 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1558 case JEWELS_NEXT
: /* scroll forwards */
1559 case (JEWELS_NEXT
|BUTTON_REPEAT
):
1561 if(x
== BJ_WIDTH
-1) {
1562 y
= (y
+1)%(BJ_HEIGHT
-1);
1569 case JEWELS_SELECT
: /* toggle selected */
1570 selected
= !selected
;
1573 #ifdef JEWELS_RC_CANCEL
1574 case JEWELS_RC_CANCEL
:
1576 case JEWELS_CANCEL
: /* end game */
1577 if (jewels_game_menu(bj
, true)!=0)
1582 if (rb
->default_event_handler (button
) == SYS_USB_CONNECTED
)
1583 return PLUGIN_USB_CONNECTED
;
1588 case GAME_TYPE_NORMAL
:
1589 if(bj
->score
>= LEVEL_PTS
)
1590 jewels_nextlevel(bj
);
1592 case GAME_TYPE_PUZZLE
:
1593 if (jewels_puzzle_is_finished(bj
)) {
1594 if (bj
->level
< NUM_PUZZLE_LEVELS
) {
1595 jewels_nextlevel(bj
);
1597 rb
->splash(2*HZ
, "Congratulations!");
1598 rb
->splash(2*HZ
, "You have finished the game!");
1599 if (jewels_game_menu(bj
, false)!=0) {
1607 if (no_movesavail
) {
1609 case GAME_TYPE_NORMAL
:
1610 rb
->splash(HZ
*2, "Game Over!");
1611 rb
->lcd_clear_display();
1612 if (highscore_would_update(bj
->score
, highest
,
1614 position
=highscore_update(bj
->score
,
1616 highest
,NUM_SCORES
);
1617 highest_updated
= true;
1618 if (position
== 0) {
1619 rb
->splash(HZ
*2, "New High Score");
1621 jewels_show_highscores(position
);
1624 case GAME_TYPE_PUZZLE
:
1625 rb
->splash(2*HZ
, "Game Over");
1628 if (jewels_game_menu(bj
, false)!=0) {
1635 /* this is the plugin entry point */
1636 enum plugin_status
plugin_start(const void* parameter
)
1640 /* load high scores */
1641 highscore_load(HIGH_SCORE
,highest
,NUM_SCORES
);
1642 highest_updated
= false;
1644 rb
->lcd_setfont(FONT_SYSFIXED
);
1646 rb
->lcd_set_backdrop(NULL
);
1649 struct game_context bj
;
1650 bj
.tmp_type
= GAME_TYPE_NORMAL
;
1653 highscore_save(HIGH_SCORE
,highest
,NUM_SCORES
);
1654 rb
->lcd_setfont(FONT_UI
);
1659 #endif /* HAVE_LCD_BITMAP */