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/playback_control.h"
27 #ifdef HAVE_LCD_BITMAP
31 /* button definitions */
32 #if CONFIG_KEYPAD == RECORDER_PAD
33 #define JEWELS_UP BUTTON_UP
34 #define JEWELS_DOWN BUTTON_DOWN
35 #define JEWELS_LEFT BUTTON_LEFT
36 #define JEWELS_RIGHT BUTTON_RIGHT
37 #define JEWELS_SELECT BUTTON_PLAY
38 #define JEWELS_CANCEL BUTTON_OFF
40 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
41 #define JEWELS_UP BUTTON_UP
42 #define JEWELS_DOWN BUTTON_DOWN
43 #define JEWELS_LEFT BUTTON_LEFT
44 #define JEWELS_RIGHT BUTTON_RIGHT
45 #define JEWELS_SELECT BUTTON_SELECT
46 #define JEWELS_CANCEL BUTTON_OFF
48 #elif CONFIG_KEYPAD == ONDIO_PAD
49 #define JEWELS_UP BUTTON_UP
50 #define JEWELS_DOWN BUTTON_DOWN
51 #define JEWELS_LEFT BUTTON_LEFT
52 #define JEWELS_RIGHT BUTTON_RIGHT
53 #define JEWELS_SELECT BUTTON_MENU
54 #define JEWELS_CANCEL BUTTON_OFF
56 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
57 #define JEWELS_UP BUTTON_UP
58 #define JEWELS_DOWN BUTTON_DOWN
59 #define JEWELS_LEFT BUTTON_LEFT
60 #define JEWELS_RIGHT BUTTON_RIGHT
61 #define JEWELS_SELECT BUTTON_SELECT
62 #define JEWELS_MENU BUTTON_MODE
63 #define JEWELS_CANCEL BUTTON_OFF
64 #define JEWELS_RC_CANCEL BUTTON_RC_STOP
66 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
67 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
68 #define JEWELS_SCROLLWHEEL
69 #define JEWELS_UP BUTTON_MENU
70 #define JEWELS_DOWN BUTTON_PLAY
71 #define JEWELS_LEFT BUTTON_LEFT
72 #define JEWELS_RIGHT BUTTON_RIGHT
73 #define JEWELS_PREV BUTTON_SCROLL_BACK
74 #define JEWELS_NEXT BUTTON_SCROLL_FWD
75 #define JEWELS_SELECT BUTTON_SELECT
77 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
78 #define JEWELS_UP BUTTON_UP
79 #define JEWELS_DOWN BUTTON_DOWN
80 #define JEWELS_LEFT BUTTON_LEFT
81 #define JEWELS_RIGHT BUTTON_RIGHT
82 #define JEWELS_SELECT BUTTON_SELECT
83 #define JEWELS_CANCEL BUTTON_PLAY
85 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
86 #define JEWELS_UP BUTTON_UP
87 #define JEWELS_DOWN BUTTON_DOWN
88 #define JEWELS_LEFT BUTTON_LEFT
89 #define JEWELS_RIGHT BUTTON_RIGHT
90 #define JEWELS_SELECT BUTTON_SELECT
91 #define JEWELS_CANCEL BUTTON_POWER
93 #elif CONFIG_KEYPAD == GIGABEAT_PAD
94 #define JEWELS_UP BUTTON_UP
95 #define JEWELS_DOWN BUTTON_DOWN
96 #define JEWELS_LEFT BUTTON_LEFT
97 #define JEWELS_RIGHT BUTTON_RIGHT
98 #define JEWELS_SELECT BUTTON_SELECT
99 #define JEWELS_CANCEL BUTTON_POWER
101 #elif CONFIG_KEYPAD == SANSA_E200_PAD
102 #define JEWELS_SCROLLWHEEL
103 #define JEWELS_UP BUTTON_UP
104 #define JEWELS_DOWN BUTTON_DOWN
105 #define JEWELS_LEFT BUTTON_LEFT
106 #define JEWELS_RIGHT BUTTON_RIGHT
107 #define JEWELS_PREV BUTTON_SCROLL_BACK
108 #define JEWELS_NEXT BUTTON_SCROLL_FWD
109 #define JEWELS_SELECT BUTTON_SELECT
110 #define JEWELS_CANCEL BUTTON_POWER
112 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
113 #define JEWELS_SCROLLWHEEL
114 #define JEWELS_UP BUTTON_UP
115 #define JEWELS_DOWN BUTTON_DOWN
116 #define JEWELS_LEFT BUTTON_LEFT
117 #define JEWELS_RIGHT BUTTON_RIGHT
118 #define JEWELS_PREV BUTTON_SCROLL_BACK
119 #define JEWELS_NEXT BUTTON_SCROLL_FWD
120 #define JEWELS_SELECT BUTTON_SELECT
121 #define JEWELS_CANCEL (BUTTON_HOME|BUTTON_REPEAT)
123 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
124 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
125 CONFIG_KEYPAD == SANSA_M200_PAD
126 #define JEWELS_UP BUTTON_UP
127 #define JEWELS_DOWN BUTTON_DOWN
128 #define JEWELS_LEFT BUTTON_LEFT
129 #define JEWELS_RIGHT BUTTON_RIGHT
130 #define JEWELS_SELECT BUTTON_SELECT
131 #define JEWELS_CANCEL BUTTON_POWER
133 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
134 #define JEWELS_UP BUTTON_SCROLL_UP
135 #define JEWELS_DOWN BUTTON_SCROLL_DOWN
136 #define JEWELS_LEFT BUTTON_LEFT
137 #define JEWELS_RIGHT BUTTON_RIGHT
138 #define JEWELS_SELECT BUTTON_PLAY
139 #define JEWELS_CANCEL BUTTON_POWER
141 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
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_SELECT BUTTON_SELECT
147 #define JEWELS_MENU BUTTON_MENU
148 #define JEWELS_CANCEL BUTTON_BACK
150 #elif CONFIG_KEYPAD == MROBE100_PAD
151 #define JEWELS_UP BUTTON_UP
152 #define JEWELS_DOWN BUTTON_DOWN
153 #define JEWELS_LEFT BUTTON_LEFT
154 #define JEWELS_RIGHT BUTTON_RIGHT
155 #define JEWELS_SELECT BUTTON_SELECT
156 #define JEWELS_CANCEL BUTTON_POWER
158 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
159 #define JEWELS_UP BUTTON_RC_VOL_UP
160 #define JEWELS_DOWN BUTTON_RC_VOL_DOWN
161 #define JEWELS_LEFT BUTTON_RC_REW
162 #define JEWELS_RIGHT BUTTON_RC_FF
163 #define JEWELS_SELECT BUTTON_RC_PLAY
164 #define JEWELS_CANCEL BUTTON_RC_REC
166 #define JEWELS_RC_CANCEL BUTTON_REC
168 #elif CONFIG_KEYPAD == COWOND2_PAD
169 #define JEWELS_CANCEL BUTTON_POWER
171 #elif CONFIG_KEYPAD == IAUDIO67_PAD
172 #define JEWELS_UP BUTTON_STOP
173 #define JEWELS_DOWN BUTTON_PLAY
174 #define JEWELS_LEFT BUTTON_LEFT
175 #define JEWELS_RIGHT BUTTON_RIGHT
176 #define JEWELS_SELECT BUTTON_MENU
177 #define JEWELS_CANCEL BUTTON_POWER
179 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
180 #define JEWELS_UP BUTTON_UP
181 #define JEWELS_DOWN BUTTON_DOWN
182 #define JEWELS_LEFT BUTTON_LEFT
183 #define JEWELS_RIGHT BUTTON_RIGHT
184 #define JEWELS_SELECT BUTTON_SELECT
185 #define JEWELS_CANCEL BUTTON_BACK
187 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_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
195 #elif CONFIG_KEYPAD == ONDAVX747_PAD || CONFIG_KEYPAD == MROBE500_PAD
196 #define JEWELS_CANCEL BUTTON_POWER
199 #error No keymap defined!
202 #ifdef HAVE_TOUCHSCREEN
204 #define JEWELS_UP BUTTON_TOPMIDDLE
207 #define JEWELS_DOWN BUTTON_BOTTOMMIDDLE
210 #define JEWELS_LEFT BUTTON_MIDLEFT
213 #define JEWELS_RIGHT BUTTON_MIDRIGHT
215 #ifndef JEWELS_SELECT
216 #define JEWELS_SELECT BUTTON_CENTER
218 #ifndef JEWELS_CANCEL
219 #define JEWELS_CANCEL BUTTON_TOPLEFT
223 /* use 30x30 tiles (iPod Video, Gigabeat, Onda VX747) */
224 #if (LCD_HEIGHT == 240) && (LCD_WIDTH == 320) || \
225 ((LCD_HEIGHT == 320) && (LCD_WIDTH == 240)) || \
226 ((LCD_HEIGHT == 400) && (LCD_WIDTH == 240))
227 #define TILE_WIDTH 30
228 #define TILE_HEIGHT 30
230 #define NUM_SCORES 10
232 /* use 22x22 tiles (H300, iPod Color) */
233 #elif ((LCD_HEIGHT == 176) && (LCD_WIDTH == 220)) || \
234 ((LCD_HEIGHT == 220) && (LCD_WIDTH == 176))
235 #define TILE_WIDTH 22
236 #define TILE_HEIGHT 22
238 #define NUM_SCORES 10
240 /* use 16x16 tiles (iPod Nano) */
241 #elif (LCD_HEIGHT == 132) && (LCD_WIDTH == 176)
242 #define TILE_WIDTH 16
243 #define TILE_HEIGHT 16
245 #define NUM_SCORES 10
247 /* use 16x16 tiles (H100, iAudio X5, iPod 3G, iPod 4G grayscale) */
248 #elif (LCD_HEIGHT == 128) && (LCD_WIDTH == 160)
249 #define TILE_WIDTH 16
250 #define TILE_HEIGHT 16
252 #define NUM_SCORES 10
254 /* use 14x14 tiles (H10 5/6 GB) */
255 #elif (LCD_HEIGHT == 128) && (LCD_WIDTH == 128)
256 #define TILE_WIDTH 14
257 #define TILE_HEIGHT 14
259 #define NUM_SCORES 10
261 /* use 13x13 tiles (iPod Mini) */
262 #elif (LCD_HEIGHT == 110) && (LCD_WIDTH == 138)
263 #define TILE_WIDTH 13
264 #define TILE_HEIGHT 13
266 #define NUM_SCORES 10
268 /* use 12x12 tiles (iAudio M3) */
269 #elif (LCD_HEIGHT == 96) && (LCD_WIDTH == 128)
270 #define TILE_WIDTH 12
271 #define TILE_HEIGHT 12
275 /* use 10x10 tiles (Sansa c200) */
276 #elif (LCD_HEIGHT == 80) && (LCD_WIDTH == 132)
277 #define TILE_WIDTH 10
278 #define TILE_HEIGHT 10
282 /* use 10x8 tiles (iFP 700) */
283 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 128)
284 #define TILE_WIDTH 10
285 #define TILE_HEIGHT 8
289 /* use 10x8 tiles (Recorder, Ondio) */
290 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 112)
291 #define TILE_WIDTH 10
292 #define TILE_HEIGHT 8
297 #error JEWELS: Unsupported LCD
301 #define SCORE_FILE PLUGIN_GAMES_DIR "/jewels.score"
302 #define SAVE_FILE PLUGIN_GAMES_DIR "/jewels.save"
304 /* final game return status */
305 #define BJ_QUIT_FROM_GAME 4
311 /* swap directions */
317 /* play board dimension */
321 /* next level threshold */
322 #define LEVEL_PTS 100
324 /* animation frame rate */
333 /* external bitmaps */
334 extern const fb_data jewels
[];
336 /* tile background colors */
337 #ifdef HAVE_LCD_COLOR
338 static const unsigned jewels_bkgd
[2] = {
339 LCD_RGBPACK(104, 63, 63),
340 LCD_RGBPACK(83, 44, 44)
345 * type is the jewel number 0-7
346 * falling if the jewel is falling
347 * delete marks the jewel for deletion
355 /* the game context struct
356 * score is the current level score
357 * segments is the number of cleared segments in the current run
358 * level is the current level
359 * type is the game type (normal or puzzle)
360 * highscores is the list of high scores
361 * resume denotes whether to resume the currently loaded game
362 * dirty denotes whether the high scores are out of sync with the saved file
363 * playboard is the game playing board (first row is hidden)
364 * num_jewels is the number of different jewels to use
366 struct game_context
{
368 unsigned int segments
;
371 unsigned int highscores
[NUM_SCORES
];
374 struct tile playboard
[BJ_HEIGHT
][BJ_WIDTH
];
375 unsigned int num_jewels
;
378 #define MAX_NUM_JEWELS 7
380 #define MAX_PUZZLE_TILES 4
381 #define NUM_PUZZLE_LEVELS 10
389 struct puzzle_level
{
390 unsigned int num_jewels
;
391 unsigned int num_tiles
;
392 struct puzzle_tile tiles
[MAX_PUZZLE_TILES
];
395 #define PUZZLE_TILE_UP 1
396 #define PUZZLE_TILE_DOWN 2
397 #define PUZZLE_TILE_LEFT 4
398 #define PUZZLE_TILE_RIGHT 8
400 struct puzzle_level puzzle_levels
[NUM_PUZZLE_LEVELS
] = {
401 { 5, 2, { {3, 3, PUZZLE_TILE_RIGHT
},
402 {4, 2, PUZZLE_TILE_LEFT
} } },
403 { 5, 2, { {3, 2, PUZZLE_TILE_DOWN
},
404 {3, 4, PUZZLE_TILE_UP
} } },
405 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
406 {3, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
407 {3, 6, PUZZLE_TILE_UP
} } },
408 { 6, 3, { {3, 2, PUZZLE_TILE_RIGHT
},
409 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
410 {5, 4, PUZZLE_TILE_LEFT
} } },
411 { 6, 2, { {3, 4, PUZZLE_TILE_RIGHT
},
412 {4, 2, PUZZLE_TILE_LEFT
} } },
413 { 6, 2, { {3, 2, PUZZLE_TILE_DOWN
},
414 {4, 4, PUZZLE_TILE_UP
} } },
415 { 7, 4, { {3, 2, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
416 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
417 {3, 4, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
418 {4, 4, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
419 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
420 {4, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
421 {3, 6, PUZZLE_TILE_UP
} } },
422 { 7, 3, { {2, 2, PUZZLE_TILE_RIGHT
},
423 {4, 1, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
424 {5, 4, PUZZLE_TILE_LEFT
} } },
425 { 7, 4, { {3, 0, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
426 {5, 0, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
427 {2, 7, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
428 {4, 7, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
431 /*****************************************************************************
432 * jewels_init() initializes jewels data structures.
433 ******************************************************************************/
434 static void jewels_init(struct game_context
* bj
) {
435 /* seed the rand generator */
436 rb
->srand(*rb
->current_tick
);
438 /* check for resumed game */
449 /* clear playing board */
450 rb
->memset(bj
->playboard
, 0, sizeof(bj
->playboard
));
453 /*****************************************************************************
454 * jewels_setcolors() set the foreground and background colors.
455 ******************************************************************************/
456 static inline void jewels_setcolors(void) {
457 #ifdef HAVE_LCD_COLOR
458 rb
->lcd_set_background(LCD_RGBPACK(49, 26, 26));
459 rb
->lcd_set_foreground(LCD_RGBPACK(210, 181, 181));
463 /*****************************************************************************
464 * jewels_drawboard() redraws the entire game board.
465 ******************************************************************************/
466 static void jewels_drawboard(struct game_context
* bj
) {
469 unsigned int tempscore
;
470 char *title
= "Level";
473 tempscore
= (bj
->score
>LEVEL_PTS
? LEVEL_PTS
: bj
->score
);
476 rb
->lcd_clear_display();
478 /* dispay playing board */
479 for(i
=0; i
<BJ_HEIGHT
-1; i
++){
480 for(j
=0; j
<BJ_WIDTH
; j
++){
481 #ifdef HAVE_LCD_COLOR
482 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
483 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
484 TILE_WIDTH
, TILE_HEIGHT
);
485 rb
->lcd_bitmap_transparent_part(jewels
,
486 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
487 TILE_WIDTH
, j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
488 TILE_WIDTH
, TILE_HEIGHT
);
490 rb
->lcd_bitmap_part(jewels
,
491 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
492 TILE_WIDTH
, j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
493 TILE_WIDTH
, TILE_HEIGHT
);
498 #if LCD_WIDTH > LCD_HEIGHT /* horizontal layout */
500 /* draw separator lines */
502 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, LCD_HEIGHT
-1);
503 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, 18);
504 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, LCD_HEIGHT
-10);
506 /* draw progress bar */
507 #ifdef HAVE_LCD_COLOR
508 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
510 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
511 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
512 tempscore
/LEVEL_PTS
),
513 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
514 ((LCD_HEIGHT
-10)-18)*tempscore
/LEVEL_PTS
);
515 #ifdef HAVE_LCD_COLOR
516 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
517 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
518 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
519 tempscore
/LEVEL_PTS
)+1,
520 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
521 ((LCD_HEIGHT
-10)-18)*tempscore
/LEVEL_PTS
-1);
523 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
524 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
525 tempscore
/LEVEL_PTS
),
526 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
527 ((LCD_HEIGHT
-10)-18)*tempscore
/LEVEL_PTS
+1);
531 rb
->lcd_getstringsize(title
, &w
, &h
);
532 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 1, title
);
534 rb
->snprintf(str
, 4, "%d", bj
->level
);
535 rb
->lcd_getstringsize(str
, &w
, &h
);
536 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 10, str
);
538 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
539 rb
->lcd_getstringsize(str
, &w
, &h
);
540 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2,
543 #elif LCD_WIDTH < LCD_HEIGHT /* vertical layout */
545 /* draw separator lines */
547 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
548 rb
->lcd_hline(0, LCD_WIDTH
-1, LCD_HEIGHT
-14);
549 rb
->lcd_vline(LCD_WIDTH
/2, LCD_HEIGHT
-14, LCD_HEIGHT
-1);
551 /* draw progress bar */
552 #ifdef HAVE_LCD_COLOR
553 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
555 rb
->lcd_fillrect(0, (8*TILE_HEIGHT
+YOFS
)
556 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
557 LCD_WIDTH
*tempscore
/LEVEL_PTS
,
558 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
559 #ifdef HAVE_LCD_COLOR
560 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
561 rb
->lcd_drawrect(1, (8*TILE_HEIGHT
+YOFS
)
562 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4+1,
563 LCD_WIDTH
*tempscore
/LEVEL_PTS
-1,
564 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2-2);
566 rb
->lcd_drawrect(0, (8*TILE_HEIGHT
+YOFS
)
567 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
568 LCD_WIDTH
*tempscore
/LEVEL_PTS
+1,
569 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
573 rb
->snprintf(str
, 10, "%s %d", title
, bj
->level
);
574 rb
->lcd_putsxy(1, LCD_HEIGHT
-10, str
);
576 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
577 rb
->lcd_getstringsize(str
, &w
, &h
);
578 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
, LCD_HEIGHT
-10, str
);
580 #else /* square layout */
582 /* draw separator lines */
584 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
585 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, 8*TILE_HEIGHT
+YOFS
);
586 rb
->lcd_vline(LCD_WIDTH
/2, 8*TILE_HEIGHT
+YOFS
, LCD_HEIGHT
-1);
588 /* draw progress bar */
589 #ifdef HAVE_LCD_COLOR
590 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
592 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
593 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
594 *tempscore
/LEVEL_PTS
,
595 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
596 (8*TILE_HEIGHT
+YOFS
)*tempscore
/LEVEL_PTS
);
597 #ifdef HAVE_LCD_COLOR
598 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
599 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
600 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
601 *tempscore
/LEVEL_PTS
+1,
602 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
603 (8*TILE_HEIGHT
+YOFS
)*tempscore
/LEVEL_PTS
-1);
605 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
606 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
607 *tempscore
/LEVEL_PTS
,
608 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
609 (8*TILE_HEIGHT
+YOFS
)*tempscore
/LEVEL_PTS
+1);
613 rb
->snprintf(str
, 10, "%s %d", title
, bj
->level
);
614 rb
->lcd_putsxy(1, LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3, str
);
616 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
617 rb
->lcd_getstringsize(str
, &w
, &h
);
618 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
,
619 LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3, str
);
626 /*****************************************************************************
627 * jewels_putjewels() makes the jewels fall to fill empty spots and adds
628 * new random jewels at the empty spots at the top of each row.
629 ******************************************************************************/
630 static void jewels_putjewels(struct game_context
* bj
){
633 long lasttick
, currenttick
;
635 /* loop to make all the jewels fall */
637 /* mark falling jewels and add new jewels to hidden top row*/
640 for(j
=0; j
<BJ_WIDTH
; j
++) {
641 if(bj
->playboard
[1][j
].type
== 0) {
642 bj
->playboard
[0][j
].type
= rb
->rand()%bj
->num_jewels
+1;
644 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
645 if(!mark
&& bj
->playboard
[i
+1][j
].type
== 0) {
649 if(mark
) bj
->playboard
[i
][j
].falling
= true;
651 /*if(bj->playboard[1][j].falling) {
652 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
653 bj->playboard[0][j].falling = true;
658 /* break if there are no falling jewels */
661 /* animate falling jewels */
662 lasttick
= *rb
->current_tick
;
664 for(k
=1; k
<=8; k
++) {
665 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
666 for(j
=0; j
<BJ_WIDTH
; j
++) {
667 if(bj
->playboard
[i
][j
].falling
&&
668 bj
->playboard
[i
][j
].type
!= 0) {
669 /* clear old position */
670 #ifdef HAVE_LCD_COLOR
672 rb
->lcd_set_foreground(rb
->lcd_get_background());
674 rb
->lcd_set_foreground(jewels_bkgd
[(i
-1+j
)%2]);
676 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
677 TILE_WIDTH
, TILE_HEIGHT
);
678 if(bj
->playboard
[i
+1][j
].type
== 0) {
679 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
680 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
681 TILE_WIDTH
, TILE_HEIGHT
);
684 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
685 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
686 TILE_WIDTH
, TILE_HEIGHT
);
687 if(bj
->playboard
[i
+1][j
].type
== 0) {
688 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
689 TILE_WIDTH
, TILE_HEIGHT
);
691 rb
->lcd_set_drawmode(DRMODE_SOLID
);
694 /* draw new position */
695 #ifdef HAVE_LCD_COLOR
696 rb
->lcd_bitmap_transparent_part(jewels
, 0,
697 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
698 TILE_WIDTH
, j
*TILE_WIDTH
,
699 (i
-1)*TILE_HEIGHT
+YOFS
+
700 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
701 TILE_WIDTH
, TILE_HEIGHT
);
703 rb
->lcd_bitmap_part(jewels
, 0,
704 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
705 TILE_WIDTH
, j
*TILE_WIDTH
,
706 (i
-1)*TILE_HEIGHT
+YOFS
+
707 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
708 TILE_WIDTH
, TILE_HEIGHT
);
714 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
717 /* framerate limiting */
718 currenttick
= *rb
->current_tick
;
719 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
720 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
724 lasttick
= currenttick
;
727 /* shift jewels down */
728 for(j
=0; j
<BJ_WIDTH
; j
++) {
729 for(i
=BJ_HEIGHT
-1; i
>=1; i
--) {
730 if(bj
->playboard
[i
-1][j
].falling
) {
731 bj
->playboard
[i
][j
].type
= bj
->playboard
[i
-1][j
].type
;
736 /* clear out top row */
737 for(j
=0; j
<BJ_WIDTH
; j
++) {
738 bj
->playboard
[0][j
].type
= 0;
741 /* mark everything not falling */
742 for(i
=0; i
<BJ_HEIGHT
; i
++) {
743 for(j
=0; j
<BJ_WIDTH
; j
++) {
744 bj
->playboard
[i
][j
].falling
= false;
750 /*****************************************************************************
751 * jewels_clearjewels() finds all the connected rows and columns and
752 * calculates and returns the points earned.
753 ******************************************************************************/
754 static unsigned int jewels_clearjewels(struct game_context
* bj
) {
757 unsigned int points
= 0;
759 /* check for connected rows */
760 for(i
=1; i
<BJ_HEIGHT
; i
++) {
763 for(j
=0; j
<BJ_WIDTH
; j
++) {
764 if(bj
->playboard
[i
][j
].type
== last
&&
765 bj
->playboard
[i
][j
].type
!= 0 &&
766 bj
->playboard
[i
][j
].type
<= MAX_NUM_JEWELS
) {
771 points
+= bj
->segments
;
772 bj
->playboard
[i
][j
].delete = true;
773 bj
->playboard
[i
][j
-1].delete = true;
774 bj
->playboard
[i
][j
-2].delete = true;
777 bj
->playboard
[i
][j
].delete = true;
781 last
= bj
->playboard
[i
][j
].type
;
786 /* check for connected columns */
787 for(j
=0; j
<BJ_WIDTH
; j
++) {
790 for(i
=1; i
<BJ_HEIGHT
; i
++) {
791 if(bj
->playboard
[i
][j
].type
!= 0 &&
792 bj
->playboard
[i
][j
].type
== last
&&
793 bj
->playboard
[i
][j
].type
<= MAX_NUM_JEWELS
) {
798 points
+= bj
->segments
;
799 bj
->playboard
[i
][j
].delete = true;
800 bj
->playboard
[i
-1][j
].delete = true;
801 bj
->playboard
[i
-2][j
].delete = true;
804 bj
->playboard
[i
][j
].delete = true;
808 last
= bj
->playboard
[i
][j
].type
;
813 /* clear deleted jewels */
814 for(i
=1; i
<BJ_HEIGHT
; i
++) {
815 for(j
=0; j
<BJ_WIDTH
; j
++) {
816 if(bj
->playboard
[i
][j
].delete) {
817 bj
->playboard
[i
][j
].delete = false;
818 bj
->playboard
[i
][j
].type
= 0;
826 /*****************************************************************************
827 * jewels_runboard() runs the board until it settles in a fixed state and
828 * returns points earned.
829 ******************************************************************************/
830 static unsigned int jewels_runboard(struct game_context
* bj
) {
831 unsigned int points
= 0;
836 while((ret
= jewels_clearjewels(bj
)) > 0) {
838 jewels_drawboard(bj
);
839 jewels_putjewels(bj
);
845 /*****************************************************************************
846 * jewels_swapjewels() swaps two jewels as long as it results in points and
847 * returns points earned.
848 ******************************************************************************/
849 static unsigned int jewels_swapjewels(struct game_context
* bj
,
850 int x
, int y
, int direc
) {
852 int horzmod
, vertmod
;
855 unsigned int points
= 0;
856 long lasttick
, currenttick
;
858 /* check for invalid parameters */
859 if(x
< 0 || x
>= BJ_WIDTH
|| y
< 0 || y
>= BJ_HEIGHT
-1 ||
860 direc
< SWAP_UP
|| direc
> SWAP_LEFT
) {
864 /* check for invalid directions */
865 if((x
== 0 && direc
== SWAP_LEFT
) ||
866 (x
== BJ_WIDTH
-1 && direc
== SWAP_RIGHT
) ||
867 (y
== 0 && direc
== SWAP_UP
) ||
868 (y
== BJ_HEIGHT
-2 && direc
== SWAP_DOWN
)) {
872 /* set direction variables */
878 movelen
= TILE_HEIGHT
;
882 movelen
= TILE_WIDTH
;
886 movelen
= TILE_HEIGHT
;
890 movelen
= TILE_WIDTH
;
895 lasttick
= *rb
->current_tick
;
897 /* animate swapping jewels */
898 for(k
=0; k
<=8; k
++) {
899 /* clear old position */
900 #ifdef HAVE_LCD_COLOR
901 rb
->lcd_set_foreground(jewels_bkgd
[(x
+y
)%2]);
902 rb
->lcd_fillrect(x
*TILE_WIDTH
,
904 TILE_WIDTH
, TILE_HEIGHT
);
905 rb
->lcd_set_foreground(jewels_bkgd
[(x
+horzmod
+y
+vertmod
)%2]);
906 rb
->lcd_fillrect((x
+horzmod
)*TILE_WIDTH
,
907 (y
+vertmod
)*TILE_HEIGHT
+YOFS
,
908 TILE_WIDTH
, TILE_HEIGHT
);
910 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
911 rb
->lcd_fillrect(x
*TILE_WIDTH
,
913 TILE_WIDTH
, TILE_HEIGHT
);
914 rb
->lcd_fillrect((x
+horzmod
)*TILE_WIDTH
,
915 (y
+vertmod
)*TILE_HEIGHT
+YOFS
,
916 TILE_WIDTH
, TILE_HEIGHT
);
917 rb
->lcd_set_drawmode(DRMODE_SOLID
);
919 /* draw new position */
920 #ifdef HAVE_LCD_COLOR
921 rb
->lcd_bitmap_transparent_part(jewels
,
922 0, TILE_HEIGHT
*(bj
->playboard
923 [y
+1+vertmod
][x
+horzmod
].type
), TILE_WIDTH
,
924 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
925 ((((movelen
<<10)*k
)/8)>>10),
926 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
927 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
928 TILE_WIDTH
, TILE_HEIGHT
);
929 rb
->lcd_bitmap_transparent_part(jewels
,
930 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
931 TILE_WIDTH
, x
*TILE_WIDTH
+horzmod
*
932 ((((movelen
<<10)*k
)/8)>>10),
933 y
*TILE_HEIGHT
+vertmod
*
934 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
935 TILE_WIDTH
, TILE_HEIGHT
);
937 rb
->lcd_bitmap_part(jewels
,
938 0, TILE_HEIGHT
*(bj
->playboard
939 [y
+1+vertmod
][x
+horzmod
].type
), TILE_WIDTH
,
940 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
941 ((((movelen
<<10)*k
)/8)>>10),
942 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
943 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
944 TILE_WIDTH
, TILE_HEIGHT
);
945 rb
->lcd_set_drawmode(DRMODE_FG
);
946 rb
->lcd_bitmap_part(jewels
,
947 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
948 TILE_WIDTH
, x
*TILE_WIDTH
+horzmod
*
949 ((((movelen
<<10)*k
)/8)>>10),
950 y
*TILE_HEIGHT
+vertmod
*
951 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
952 TILE_WIDTH
, TILE_HEIGHT
);
953 rb
->lcd_set_drawmode(DRMODE_SOLID
);
956 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
959 /* framerate limiting */
960 currenttick
= *rb
->current_tick
;
961 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
962 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
966 lasttick
= currenttick
;
970 int temp
= bj
->playboard
[y
+1][x
].type
;
971 bj
->playboard
[y
+1][x
].type
=
972 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
;
973 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
= temp
;
977 points
= jewels_runboard(bj
);
988 /*****************************************************************************
989 * jewels_movesavail() uses pattern matching to see if there are any
990 * available move left.
991 ******************************************************************************/
992 static bool jewels_movesavail(struct game_context
* bj
) {
997 for(i
=1; i
<BJ_HEIGHT
; i
++) {
998 for(j
=0; j
<BJ_WIDTH
; j
++) {
999 mytype
= bj
->playboard
[i
][j
].type
;
1000 if(mytype
== 0 || mytype
> MAX_NUM_JEWELS
) continue;
1002 /* check horizontal patterns */
1003 if(j
<= BJ_WIDTH
-3) {
1005 if(bj
->playboard
[i
-1][j
+1].type
== mytype
) {
1006 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1007 {moves
= true; break;}
1008 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1009 {moves
= true; break;}
1011 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1012 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1013 {moves
= true; break;}
1017 if(j
<= BJ_WIDTH
-4) {
1018 if(bj
->playboard
[i
][j
+3].type
== mytype
) {
1019 if(bj
->playboard
[i
][j
+1].type
== mytype
)
1020 {moves
= true; break;}
1021 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1022 {moves
= true; break;}
1026 if(i
< BJ_HEIGHT
-1) {
1027 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1028 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1029 {moves
= true; break;}
1031 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1032 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1033 {moves
= true; break;}
1034 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1035 {moves
= true; break;}
1040 /* check vertical patterns */
1041 if(i
<= BJ_HEIGHT
-3) {
1043 if(bj
->playboard
[i
+1][j
-1].type
== mytype
) {
1044 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1045 {moves
= true; break;}
1046 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1047 {moves
= true; break;}
1049 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1050 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1051 {moves
= true; break;}
1055 if(i
<= BJ_HEIGHT
-4) {
1056 if(bj
->playboard
[i
+3][j
].type
== mytype
) {
1057 if(bj
->playboard
[i
+1][j
].type
== mytype
)
1058 {moves
= true; break;}
1059 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1060 {moves
= true; break;}
1064 if(j
< BJ_WIDTH
-1) {
1065 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1066 if(bj
->playboard
[i
+2][j
+1].type
== mytype
)
1067 {moves
= true; break;}
1069 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1070 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1071 {moves
= true; break;}
1072 if (bj
->playboard
[i
+2][j
+1].type
== mytype
)
1073 {moves
= true; break;}
1085 /*****************************************************************************
1086 * jewels_puzzle_is_finished(bj) checks if the puzzle is finished.
1087 ******************************************************************************/
1088 static int jewels_puzzle_is_finished(struct game_context
* bj
) {
1090 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1091 for(j
=0; j
<BJ_WIDTH
; j
++) {
1092 int mytype
= bj
->playboard
[i
][j
].type
;
1093 if(mytype
>MAX_NUM_JEWELS
) {
1094 mytype
-= MAX_NUM_JEWELS
;
1095 if(mytype
&PUZZLE_TILE_UP
) {
1096 if(i
==0 || bj
->playboard
[i
-1][j
].type
<=MAX_NUM_JEWELS
||
1097 !((bj
->playboard
[i
-1][j
].type
-MAX_NUM_JEWELS
)
1101 if(mytype
&PUZZLE_TILE_DOWN
) {
1102 if(i
==BJ_HEIGHT
-1 ||
1103 bj
->playboard
[i
+1][j
].type
<=MAX_NUM_JEWELS
||
1104 !((bj
->playboard
[i
+1][j
].type
-MAX_NUM_JEWELS
)
1108 if(mytype
&PUZZLE_TILE_LEFT
) {
1109 if(j
==0 || bj
->playboard
[i
][j
-1].type
<=MAX_NUM_JEWELS
||
1110 !((bj
->playboard
[i
][j
-1].type
-MAX_NUM_JEWELS
)
1111 &PUZZLE_TILE_RIGHT
))
1114 if(mytype
&PUZZLE_TILE_RIGHT
) {
1116 bj
->playboard
[i
][j
+1].type
<=MAX_NUM_JEWELS
||
1117 !((bj
->playboard
[i
][j
+1].type
-MAX_NUM_JEWELS
)
1127 /*****************************************************************************
1128 * jewels_initlevel() initialises a level.
1129 ******************************************************************************/
1130 static unsigned int jewels_initlevel(struct game_context
* bj
) {
1131 unsigned int points
= 0;
1134 case GAME_TYPE_NORMAL
:
1135 bj
->num_jewels
= MAX_NUM_JEWELS
;
1138 case GAME_TYPE_PUZZLE
:
1141 struct puzzle_tile
*tile
;
1143 bj
->num_jewels
= puzzle_levels
[bj
->level
-1].num_jewels
;
1145 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1146 for(j
=0; j
<BJ_WIDTH
; j
++) {
1147 bj
->playboard
[i
][j
].type
= (rb
->rand()%bj
->num_jewels
)+1;
1148 bj
->playboard
[i
][j
].falling
= false;
1149 bj
->playboard
[i
][j
].delete = false;
1152 jewels_runboard(bj
);
1153 tile
= puzzle_levels
[bj
->level
-1].tiles
;
1154 for(i
=0; i
<puzzle_levels
[bj
->level
-1].num_tiles
; i
++, tile
++) {
1155 bj
->playboard
[tile
->y
+1][tile
->x
].type
= MAX_NUM_JEWELS
1162 jewels_drawboard(bj
);
1164 /* run the play board */
1165 jewels_putjewels(bj
);
1166 points
+= jewels_runboard(bj
);
1170 /*****************************************************************************
1171 * jewels_nextlevel() advances the game to the next level and returns
1173 ******************************************************************************/
1174 static void jewels_nextlevel(struct game_context
* bj
) {
1176 unsigned int points
= 0;
1179 case GAME_TYPE_NORMAL
:
1180 /* roll over score, change and display level */
1181 while(bj
->score
>= LEVEL_PTS
) {
1182 bj
->score
-= LEVEL_PTS
;
1184 rb
->splashf(HZ
*2, "Level %d", bj
->level
);
1185 jewels_drawboard(bj
);
1188 /* randomly clear some jewels */
1189 for(i
=0; i
<16; i
++) {
1193 if(bj
->playboard
[y
][x
].type
!= 0) {
1195 bj
->playboard
[y
][x
].type
= 0;
1200 case GAME_TYPE_PUZZLE
:
1202 if(bj
->level
>NUM_PUZZLE_LEVELS
) {
1203 rb
->splash(HZ
*2, "You win!");
1206 rb
->splashf(HZ
*2, "Level %d", bj
->level
);
1211 points
+= jewels_initlevel(bj
);
1212 bj
->score
+= points
;
1215 /*****************************************************************************
1216 * jewels_recordscore() inserts a high score into the high scores list and
1217 * returns the high score position.
1218 ******************************************************************************/
1219 static int jewels_recordscore(struct game_context
* bj
) {
1222 unsigned int current
, temp
;
1224 /* calculate total score */
1225 current
= (bj
->level
-1)*LEVEL_PTS
+bj
->score
;
1226 if(current
<= 0) return 0;
1228 /* insert the current score into the high scores */
1229 for(i
=0; i
<NUM_SCORES
; i
++) {
1230 if(current
>= bj
->highscores
[i
]) {
1235 temp
= bj
->highscores
[i
];
1236 bj
->highscores
[i
] = current
;
1244 /*****************************************************************************
1245 * jewels_loadscores() loads the high scores saved file.
1246 ******************************************************************************/
1247 static void jewels_loadscores(struct game_context
* bj
) {
1252 /* clear high scores */
1253 rb
->memset(bj
->highscores
, 0, sizeof(bj
->highscores
));
1255 /* open scores file */
1256 fd
= rb
->open(SCORE_FILE
, O_RDONLY
);
1259 /* read in high scores */
1260 if(rb
->read(fd
, bj
->highscores
, sizeof(bj
->highscores
)) <= 0) {
1261 /* scores are bad, reset */
1262 rb
->memset(bj
->highscores
, 0, sizeof(bj
->highscores
));
1268 /*****************************************************************************
1269 * jewels_savescores() saves the high scores saved file.
1270 ******************************************************************************/
1271 static void jewels_savescores(struct game_context
* bj
) {
1274 /* write out the high scores to the save file */
1275 fd
= rb
->open(SCORE_FILE
, O_WRONLY
|O_CREAT
);
1276 rb
->write(fd
, bj
->highscores
, sizeof(bj
->highscores
));
1281 /*****************************************************************************
1282 * jewels_loadgame() loads the saved game and returns load success.
1283 ******************************************************************************/
1284 static bool jewels_loadgame(struct game_context
* bj
) {
1286 bool loaded
= false;
1288 /* open game file */
1289 fd
= rb
->open(SAVE_FILE
, O_RDONLY
);
1290 if(fd
< 0) return loaded
;
1292 /* read in saved game */
1294 if(rb
->read(fd
, &bj
->score
, sizeof(bj
->score
)) <= 0) break;
1295 if(rb
->read(fd
, &bj
->level
, sizeof(bj
->level
)) <= 0) break;
1296 if(rb
->read(fd
, &bj
->type
, sizeof(bj
->type
)) <= 0) break;
1297 if(rb
->read(fd
, bj
->playboard
, sizeof(bj
->playboard
)) <= 0) break;
1305 /* delete saved file */
1306 rb
->remove(SAVE_FILE
);
1310 /*****************************************************************************
1311 * jewels_savegame() saves the current game state.
1312 ******************************************************************************/
1313 static void jewels_savegame(struct game_context
* bj
) {
1316 /* write out the game state to the save file */
1317 fd
= rb
->open(SAVE_FILE
, O_WRONLY
|O_CREAT
);
1318 rb
->write(fd
, &bj
->score
, sizeof(bj
->score
));
1319 rb
->write(fd
, &bj
->level
, sizeof(bj
->level
));
1320 rb
->write(fd
, &bj
->type
, sizeof(bj
->type
));
1321 rb
->write(fd
, bj
->playboard
, sizeof(bj
->playboard
));
1327 /*****************************************************************************
1328 * jewels_callback() is the default event handler callback which is called
1329 * on usb connect and shutdown.
1330 ******************************************************************************/
1331 static void jewels_callback(void* param
) {
1332 struct game_context
* bj
= (struct game_context
*) param
;
1334 rb
->splash(HZ
, "Saving high scores...");
1335 jewels_savescores(bj
);
1339 /*****************************************************************************
1340 * jewels_displayscores() displays the high scores
1341 ******************************************************************************/
1342 static char * scores_get_name(int selected_item
, void * data
,
1343 char * buffer
, size_t buffer_len
)
1345 struct game_context
* bj
= (struct game_context
*)data
;
1346 rb
->snprintf(buffer
, buffer_len
, "#%02d: %d",
1347 selected_item
+1, bj
->highscores
[selected_item
]);
1350 static void jewels_displayscores(struct game_context
* bj
)
1352 struct simplelist_info info
;
1353 rb
->simplelist_info_init(&info
, "High Scores", NUM_SCORES
, (void*)bj
);
1354 info
.hide_selection
= true;
1355 info
.get_name
= scores_get_name
;
1356 rb
->simplelist_show_list(&info
);
1360 /*****************************************************************************
1361 * jewels_main() is the main game subroutine, it returns the final game status.
1362 ******************************************************************************/
1363 static int jewels_main(struct game_context
* bj
) {
1366 struct viewport vp
[NB_SCREENS
];
1369 bool selected
= false;
1371 /* the cursor coordinates */
1374 /* don't resume by default */
1377 /********************
1379 ********************/
1380 MENUITEM_STRINGLIST(main_menu
,"Jewels",NULL
,
1381 "New Game", "Puzzle", "Resume Saved Game",
1382 "High Scores", "Help", "Quit");
1385 rb
->viewport_set_defaults(&vp
[h
], h
);
1386 #if (LCD_DEPTH >= 16) || defined(LCD_REMOTE_DEPTH) && (LCD_REMOTE_DEPTH >= 16)
1387 if (rb
->screens
[h
]->depth
>= 16)
1389 vp
->bg_pattern
= LCD_RGBPACK(49, 26, 26);
1390 vp
->fg_pattern
= LCD_RGBPACK(210, 181, 181);
1397 switch (rb
->do_menu(&main_menu
, NULL
, vp
, true)) {
1400 bj
->type
= GAME_TYPE_NORMAL
;
1405 bj
->type
= GAME_TYPE_PUZZLE
;
1409 if(!jewels_loadgame(bj
)) {
1410 rb
->splash(HZ
*2, "Nothing to resume");
1417 jewels_displayscores(bj
);
1421 /* welcome screen to display key bindings */
1422 rb
->lcd_clear_display();
1423 rb
->snprintf(str
, 5, "%s", "Help");
1424 rb
->lcd_getstringsize(str
, &w
, &h
);
1425 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, 0, str
);
1426 #if CONFIG_KEYPAD == RECORDER_PAD
1427 rb
->lcd_puts(0, 2, "Controls:");
1428 rb
->lcd_puts(0, 3, "Directions = move");
1429 rb
->lcd_puts(0, 4, "PLAY = select");
1430 rb
->lcd_puts(0, 5, "Long PLAY = menu");
1431 rb
->lcd_puts(0, 6, "OFF = cancel");
1432 #elif CONFIG_KEYPAD == ONDIO_PAD
1433 rb
->lcd_puts(0, 2, "Controls:");
1434 rb
->lcd_puts(0, 3, "Directions = move");
1435 rb
->lcd_puts(0, 4, "MENU = select");
1436 rb
->lcd_puts(0, 5, "Long MENU = menu");
1437 rb
->lcd_puts(0, 6, "OFF = cancel");
1438 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
1439 rb
->lcd_puts(0, 2, "Controls:");
1440 rb
->lcd_puts(0, 3, "Directions = move");
1441 rb
->lcd_puts(0, 4, "SELECT = select");
1442 rb
->lcd_puts(0, 5, "Long SELECT = menu");
1443 rb
->lcd_puts(0, 6, "PLAY = cancel");
1444 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
1445 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1446 rb
->lcd_puts(0, 3, "form connected segments");
1447 rb
->lcd_puts(0, 4, "of three or more of the");
1448 rb
->lcd_puts(0, 5, "same type.");
1449 rb
->lcd_puts(0, 7, "Controls:");
1450 rb
->lcd_puts(0, 8, "Directions to move");
1451 rb
->lcd_puts(0, 9, "SELECT to select");
1452 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1453 rb
->lcd_puts(0, 11, "OFF to cancel");
1454 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1455 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1456 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1457 rb
->lcd_puts(0, 3, "form connected segments");
1458 rb
->lcd_puts(0, 4, "of three or more of the");
1459 rb
->lcd_puts(0, 5, "same type.");
1460 rb
->lcd_puts(0, 7, "Controls:");
1461 rb
->lcd_puts(0, 8, "Directions or scroll to move");
1462 rb
->lcd_puts(0, 9, "SELECT to select");
1463 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1464 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
1465 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1466 rb
->lcd_puts(0, 3, "form connected segments");
1467 rb
->lcd_puts(0, 4, "of three or more of the");
1468 rb
->lcd_puts(0, 5, "same type.");
1469 rb
->lcd_puts(0, 7, "Controls:");
1470 rb
->lcd_puts(0, 8, "Directions to move");
1471 rb
->lcd_puts(0, 9, "SELECT to select");
1472 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1473 rb
->lcd_puts(0, 11, "PLAY to cancel");
1474 #elif CONFIG_KEYPAD == GIGABEAT_PAD \
1475 || CONFIG_KEYPAD == MROBE100_PAD
1476 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1477 rb
->lcd_puts(0, 3, "form connected segments");
1478 rb
->lcd_puts(0, 4, "of three or more of the");
1479 rb
->lcd_puts(0, 5, "same type.");
1480 rb
->lcd_puts(0, 7, "Controls:");
1481 rb
->lcd_puts(0, 8, "Directions to move");
1482 rb
->lcd_puts(0, 9, "SELECT to select");
1483 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1484 rb
->lcd_puts(0, 11, "POWER to cancel");
1485 #elif CONFIG_KEYPAD == SANSA_E200_PAD \
1486 || CONFIG_KEYPAD == SANSA_C200_PAD \
1487 || CONFIG_KEYPAD == SANSA_CLIP_PAD \
1488 || CONFIG_KEYPAD == SANSA_FUZE_PAD \
1489 || CONFIG_KEYPAD == SANSA_M200_PAD
1490 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1491 rb
->lcd_puts(0, 3, "form connected segments");
1492 rb
->lcd_puts(0, 4, "of three or more of the");
1493 rb
->lcd_puts(0, 5, "same type.");
1494 rb
->lcd_puts(0, 7, "Controls:");
1495 rb
->lcd_puts(0, 8, "Directions to move");
1496 rb
->lcd_puts(0, 9, "SELECT to select");
1497 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1498 rb
->lcd_puts(0, 11, "POWER to cancel");
1499 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1500 rb
->lcd_puts(0, 2, "Swap pairs of jewels");
1501 rb
->lcd_puts(0, 3, "to form connected");
1502 rb
->lcd_puts(0, 4, "segments of three or ");
1503 rb
->lcd_puts(0, 5, "more of the");
1504 rb
->lcd_puts(0, 6, "same type.");
1505 rb
->lcd_puts(0, 8, "Controls:");
1506 rb
->lcd_puts(0, 9, "Directions or scroll to move");
1507 rb
->lcd_puts(0, 10, "PLAY to select");
1508 rb
->lcd_puts(0, 11, "Long PLAY for menu");
1509 rb
->lcd_puts(0, 12, "POWER to cancel");
1510 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1511 rb
->lcd_puts(0, 2, "Swap pairs of jewels");
1512 rb
->lcd_puts(0, 3, "to form connected");
1513 rb
->lcd_puts(0, 4, "segments of three or ");
1514 rb
->lcd_puts(0, 5, "more of the");
1515 rb
->lcd_puts(0, 6, "same type.");
1516 rb
->lcd_puts(0, 8, "Controls:");
1517 rb
->lcd_puts(0, 9, "Directions or scroll to move");
1518 rb
->lcd_puts(0, 10, "PLAY to select");
1519 rb
->lcd_puts(0, 11, "Long PLAY for menu");
1520 rb
->lcd_puts(0, 12, "REC to cancel");
1521 #elif CONFIG_KEYPAD == COWOND2_PAD
1522 rb
->lcd_puts(0, 11, "POWER to cancel");
1523 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
1524 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1525 rb
->lcd_puts(0, 3, "form connected segments");
1526 rb
->lcd_puts(0, 4, "of three or more of the");
1527 rb
->lcd_puts(0, 5, "same type.");
1528 rb
->lcd_puts(0, 7, "Controls:");
1529 rb
->lcd_puts(0, 8, "Directions to move");
1530 rb
->lcd_puts(0, 9, "SELECT to select");
1531 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1532 rb
->lcd_puts(0, 11, "BACK to cancel");
1533 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
1534 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1535 rb
->lcd_puts(0, 3, "form connected segments");
1536 rb
->lcd_puts(0, 4, "of three or more of the");
1537 rb
->lcd_puts(0, 5, "same type.");
1538 rb
->lcd_puts(0, 7, "Controls:");
1539 rb
->lcd_puts(0, 8, "Directions to move");
1540 rb
->lcd_puts(0, 9, "MIDDLE to select");
1541 rb
->lcd_puts(0, 10, "Long MIDDLE to show menu");
1542 rb
->lcd_puts(0, 11, "BACK to cancel");
1543 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
1544 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1545 rb
->lcd_puts(0, 3, "form connected segments");
1546 rb
->lcd_puts(0, 4, "of three or more of the");
1547 rb
->lcd_puts(0, 5, "same type.");
1548 rb
->lcd_puts(0, 7, "Controls:");
1549 rb
->lcd_puts(0, 8, "Directions to move");
1550 rb
->lcd_puts(0, 9, "SELECT/PLAY to select");
1551 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1552 rb
->lcd_puts(0, 11, "POWER to cancel");
1553 #elif CONFIG_KEYPAD == ONDAVX747_PAD || CONFIG_KEYPAD == MROBE500_PAD
1554 rb
->lcd_puts(0, 11, "POWER to cancel");
1556 #warning: missing help text.
1559 #ifdef HAVE_TOUCHSCREEN
1560 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1561 rb
->lcd_puts(0, 3, "form connected segments");
1562 rb
->lcd_puts(0, 4, "of three or more of the");
1563 rb
->lcd_puts(0, 5, "same type.");
1564 rb
->lcd_puts(0, 7, "Controls:");
1565 rb
->lcd_puts(0, 8, "Directions to move");
1566 rb
->lcd_puts(0, 9, "CENTER to select");
1567 rb
->lcd_puts(0, 10, "Long CENTER to show menu");
1571 button
= rb
->button_get(true);
1572 if(button
!= BUTTON_NONE
&& !(button
&BUTTON_REL
)) break;
1574 rb
->lcd_clear_display();
1580 case MENU_ATTACHED_USB
:
1581 jewels_callback(bj
);
1589 /********************
1591 ********************/
1594 /********************
1596 ********************/
1597 bj
->score
+= jewels_initlevel(bj
);
1598 if (!jewels_movesavail(bj
)) {
1600 case GAME_TYPE_NORMAL
:
1603 case GAME_TYPE_PUZZLE
:
1605 rb
->splash(2*HZ
, "No more moves!");
1606 bj
->score
+= jewels_initlevel(bj
);
1607 } while(!jewels_movesavail(bj
));
1612 /**********************
1614 **********************/
1615 MENUITEM_STRINGLIST(ingame_menu
,"Menu",NULL
,
1616 "Audio Playback", "Resume Game",
1617 "Save Game", "End Game", "Exit Jewels");
1621 bool no_movesavail
= false;
1624 switch (rb
->do_menu(&ingame_menu
, NULL
, vp
, true)) {
1626 playback_control(NULL
);
1635 rb
->splash(HZ
, "Saving game...");
1636 jewels_savegame(bj
);
1643 return BJ_QUIT_FROM_GAME
;
1645 case MENU_ATTACHED_USB
:
1646 jewels_callback(bj
);
1655 /* refresh the board */
1656 jewels_drawboard(bj
);
1658 /* display the cursor */
1660 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
1661 rb
->lcd_fillrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1662 TILE_WIDTH
, TILE_HEIGHT
);
1663 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1665 rb
->lcd_drawrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1666 TILE_WIDTH
, TILE_HEIGHT
);
1668 rb
->lcd_update_rect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1669 TILE_WIDTH
, TILE_HEIGHT
);
1671 /* handle game button presses */
1673 button
= rb
->button_get(true);
1675 case JEWELS_LEFT
: /* move cursor left */
1676 case (JEWELS_LEFT
|BUTTON_REPEAT
):
1678 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_LEFT
);
1680 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1682 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1686 case JEWELS_RIGHT
: /* move cursor right */
1687 case (JEWELS_RIGHT
|BUTTON_REPEAT
):
1689 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_RIGHT
);
1691 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1697 case JEWELS_DOWN
: /* move cursor down */
1698 case (JEWELS_DOWN
|BUTTON_REPEAT
):
1700 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_DOWN
);
1702 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1704 y
= (y
+1)%(BJ_HEIGHT
-1);
1708 case JEWELS_UP
: /* move cursor up */
1709 case (JEWELS_UP
|BUTTON_REPEAT
):
1711 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_UP
);
1713 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1715 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1719 #ifdef JEWELS_SCROLLWHEEL
1720 case JEWELS_PREV
: /* scroll backwards */
1721 case (JEWELS_PREV
|BUTTON_REPEAT
):
1724 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1726 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1730 case JEWELS_NEXT
: /* scroll forwards */
1731 case (JEWELS_NEXT
|BUTTON_REPEAT
):
1733 if(x
== BJ_WIDTH
-1) {
1734 y
= (y
+1)%(BJ_HEIGHT
-1);
1741 case JEWELS_SELECT
: /* toggle selected */
1742 selected
= !selected
;
1748 case (JEWELS_SELECT
|BUTTON_REPEAT
): /* show menu */
1753 #ifdef JEWELS_CANCEL
1754 #ifdef JEWELS_RC_CANCEL
1755 case JEWELS_RC_CANCEL
:
1757 case JEWELS_CANCEL
: /* end game */
1763 if(rb
->default_event_handler_ex(button
, jewels_callback
,
1764 (void*) bj
) == SYS_USB_CONNECTED
)
1769 if (no_movesavail
) {
1771 case GAME_TYPE_NORMAL
:
1774 case GAME_TYPE_PUZZLE
:
1776 rb
->splash(2*HZ
, "No more moves!");
1777 bj
->score
+= jewels_initlevel(bj
);
1778 } while(!jewels_movesavail(bj
));
1784 case GAME_TYPE_NORMAL
:
1785 if(bj
->score
>= LEVEL_PTS
)
1786 jewels_nextlevel(bj
);
1789 case GAME_TYPE_PUZZLE
:
1790 if(jewels_puzzle_is_finished(bj
))
1791 jewels_nextlevel(bj
);
1797 /*****************************************************************************
1798 * plugin entry point.
1799 ******************************************************************************/
1800 enum plugin_status
plugin_start(const void* parameter
) {
1801 struct game_context bj
;
1808 /* end of plugin init */
1810 /* load high scores */
1811 jewels_loadscores(&bj
);
1813 rb
->lcd_setfont(FONT_SYSFIXED
);
1815 rb
->lcd_set_backdrop(NULL
);
1820 switch(jewels_main(&bj
)){
1822 rb
->splash(HZ
*2, "No more moves!");
1823 /* fall through to BJ_END */
1827 if((position
= jewels_recordscore(&bj
))) {
1828 rb
->snprintf(str
, 19, "New high score #%d!", position
);
1829 rb
->splash(HZ
*2, str
);
1835 rb
->lcd_setfont(FONT_UI
);
1836 return PLUGIN_USB_CONNECTED
;
1840 rb
->splash(HZ
, "Saving high scores...");
1841 jewels_savescores(&bj
);
1846 case BJ_QUIT_FROM_GAME
:
1848 if((position
= jewels_recordscore(&bj
))) {
1849 rb
->snprintf(str
, 19, "New high score #%d!", position
);
1850 rb
->splash(HZ
*2, str
);
1854 rb
->splash(HZ
, "Saving high scores...");
1855 jewels_savescores(&bj
);
1865 rb
->lcd_setfont(FONT_UI
);
1869 #endif /* HAVE_LCD_BITMAP */