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 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
23 #include "playback_control.h"
25 #ifdef HAVE_LCD_BITMAP
29 /* button definitions */
30 #if CONFIG_KEYPAD == RECORDER_PAD
31 #define JEWELS_UP BUTTON_UP
32 #define JEWELS_DOWN BUTTON_DOWN
33 #define JEWELS_LEFT BUTTON_LEFT
34 #define JEWELS_RIGHT BUTTON_RIGHT
35 #define JEWELS_SELECT BUTTON_PLAY
36 #define JEWELS_CANCEL BUTTON_OFF
38 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
39 #define JEWELS_UP BUTTON_UP
40 #define JEWELS_DOWN BUTTON_DOWN
41 #define JEWELS_LEFT BUTTON_LEFT
42 #define JEWELS_RIGHT BUTTON_RIGHT
43 #define JEWELS_SELECT BUTTON_SELECT
44 #define JEWELS_CANCEL BUTTON_OFF
46 #elif CONFIG_KEYPAD == ONDIO_PAD
47 #define JEWELS_UP BUTTON_UP
48 #define JEWELS_DOWN BUTTON_DOWN
49 #define JEWELS_LEFT BUTTON_LEFT
50 #define JEWELS_RIGHT BUTTON_RIGHT
51 #define JEWELS_SELECT BUTTON_MENU
52 #define JEWELS_CANCEL BUTTON_OFF
54 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_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_SELECT
60 #define JEWELS_CANCEL BUTTON_OFF
61 #define JEWELS_RC_CANCEL BUTTON_RC_STOP
63 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
64 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
65 #define JEWELS_SCROLLWHEEL
66 #define JEWELS_UP BUTTON_MENU
67 #define JEWELS_DOWN BUTTON_PLAY
68 #define JEWELS_LEFT BUTTON_LEFT
69 #define JEWELS_RIGHT BUTTON_RIGHT
70 #define JEWELS_PREV BUTTON_SCROLL_BACK
71 #define JEWELS_NEXT BUTTON_SCROLL_FWD
72 #define JEWELS_SELECT BUTTON_SELECT
74 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
75 #define JEWELS_UP BUTTON_UP
76 #define JEWELS_DOWN BUTTON_DOWN
77 #define JEWELS_LEFT BUTTON_LEFT
78 #define JEWELS_RIGHT BUTTON_RIGHT
79 #define JEWELS_SELECT BUTTON_SELECT
80 #define JEWELS_CANCEL BUTTON_PLAY
82 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
83 #define JEWELS_UP BUTTON_UP
84 #define JEWELS_DOWN BUTTON_DOWN
85 #define JEWELS_LEFT BUTTON_LEFT
86 #define JEWELS_RIGHT BUTTON_RIGHT
87 #define JEWELS_SELECT BUTTON_SELECT
88 #define JEWELS_CANCEL BUTTON_POWER
90 #elif CONFIG_KEYPAD == GIGABEAT_PAD
91 #define JEWELS_UP BUTTON_UP
92 #define JEWELS_DOWN BUTTON_DOWN
93 #define JEWELS_LEFT BUTTON_LEFT
94 #define JEWELS_RIGHT BUTTON_RIGHT
95 #define JEWELS_SELECT BUTTON_SELECT
96 #define JEWELS_CANCEL BUTTON_POWER
98 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
99 (CONFIG_KEYPAD == SANSA_C200_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_POWER
107 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
108 #define JEWELS_UP BUTTON_SCROLL_UP
109 #define JEWELS_DOWN BUTTON_SCROLL_DOWN
110 #define JEWELS_LEFT BUTTON_LEFT
111 #define JEWELS_RIGHT BUTTON_RIGHT
112 #define JEWELS_SELECT BUTTON_PLAY
113 #define JEWELS_CANCEL BUTTON_POWER
115 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
116 #define JEWELS_UP BUTTON_UP
117 #define JEWELS_DOWN BUTTON_DOWN
118 #define JEWELS_LEFT BUTTON_LEFT
119 #define JEWELS_RIGHT BUTTON_RIGHT
120 #define JEWELS_SELECT BUTTON_SELECT
121 #define JEWELS_CANCEL BUTTON_BACK
123 #elif CONFIG_KEYPAD == MROBE100_PAD
124 #define JEWELS_UP BUTTON_UP
125 #define JEWELS_DOWN BUTTON_DOWN
126 #define JEWELS_LEFT BUTTON_LEFT
127 #define JEWELS_RIGHT BUTTON_RIGHT
128 #define JEWELS_SELECT BUTTON_SELECT
129 #define JEWELS_CANCEL BUTTON_POWER
131 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
132 #define JEWELS_UP BUTTON_RC_VOL_UP
133 #define JEWELS_DOWN BUTTON_RC_VOL_DOWN
134 #define JEWELS_LEFT BUTTON_RC_REW
135 #define JEWELS_RIGHT BUTTON_RC_FF
136 #define JEWELS_SELECT BUTTON_RC_PLAY
137 #define JEWELS_CANCEL BUTTON_RC_REC
139 #define JEWELS_RC_CANCEL BUTTON_REC
141 #elif CONFIG_KEYPAD == COWOND2_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_CANCEL BUTTON_POWER
150 #error No keymap defined!
153 /* use 30x30 tiles (iPod Video, Gigabeat) */
154 #if (LCD_HEIGHT == 240) && (LCD_WIDTH == 320) || \
155 ((LCD_HEIGHT == 320) && (LCD_WIDTH == 240))
156 #define TILE_WIDTH 30
157 #define TILE_HEIGHT 30
159 #define NUM_SCORES 10
161 /* use 22x22 tiles (H300, iPod Color) */
162 #elif ((LCD_HEIGHT == 176) && (LCD_WIDTH == 220)) || \
163 ((LCD_HEIGHT == 220) && (LCD_WIDTH == 176))
164 #define TILE_WIDTH 22
165 #define TILE_HEIGHT 22
167 #define NUM_SCORES 10
169 /* use 16x16 tiles (iPod Nano) */
170 #elif (LCD_HEIGHT == 132) && (LCD_WIDTH == 176)
171 #define TILE_WIDTH 16
172 #define TILE_HEIGHT 16
174 #define NUM_SCORES 10
176 /* use 16x16 tiles (H100, iAudio X5, iPod 3G, iPod 4G grayscale) */
177 #elif (LCD_HEIGHT == 128) && (LCD_WIDTH == 160)
178 #define TILE_WIDTH 16
179 #define TILE_HEIGHT 16
181 #define NUM_SCORES 10
183 /* use 14x14 tiles (H10 5/6 GB) */
184 #elif (LCD_HEIGHT == 128) && (LCD_WIDTH == 128)
185 #define TILE_WIDTH 14
186 #define TILE_HEIGHT 14
188 #define NUM_SCORES 10
190 /* use 13x13 tiles (iPod Mini) */
191 #elif (LCD_HEIGHT == 110) && (LCD_WIDTH == 138)
192 #define TILE_WIDTH 13
193 #define TILE_HEIGHT 13
195 #define NUM_SCORES 10
197 /* use 12x12 tiles (iAudio M3) */
198 #elif (LCD_HEIGHT == 96) && (LCD_WIDTH == 128)
199 #define TILE_WIDTH 12
200 #define TILE_HEIGHT 12
204 /* use 10x10 tiles (Sansa c200) */
205 #elif (LCD_HEIGHT == 80) && (LCD_WIDTH == 132)
206 #define TILE_WIDTH 10
207 #define TILE_HEIGHT 10
211 /* use 10x8 tiles (iFP 700) */
212 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 128)
213 #define TILE_WIDTH 10
214 #define TILE_HEIGHT 8
218 /* use 10x8 tiles (Recorder, Ondio) */
219 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 112)
220 #define TILE_WIDTH 10
221 #define TILE_HEIGHT 8
226 #error JEWELS: Unsupported LCD
230 #define SCORE_FILE PLUGIN_GAMES_DIR "/jewels.score"
231 #define SAVE_FILE PLUGIN_GAMES_DIR "/jewels.save"
233 /* final game return status */
234 #define BJ_QUIT_FROM_GAME 4
240 /* swap directions */
246 /* play board dimension */
250 /* next level threshold */
251 #define LEVEL_PTS 100
253 /* animation frame rate */
263 #define FONT_HEIGHT 8
265 #define MENU_WIDTH 100
295 struct jewels_menuitem
{
297 enum menu_result res
;
300 {"Jewels", false, 0, 6,
301 {{"New Game", MRES_NEW
},
302 {"Puzzle", MRES_PUZZLE
},
303 {"Resume Game", MRES_RESUME
},
304 {"High Scores", MRES_SCORES
},
306 {"Quit", MRES_QUIT
}}},
308 {{"Audio Playback", MRES_PLAYBACK
},
309 {"Resume Game", MRES_RESUME
},
310 {"Save Game", MRES_SAVE
},
311 {"End Game", MRES_QUIT
},
312 {"Exit Jewels", MRES_EXIT
}}}
315 /* global rockbox api */
316 static struct plugin_api
* rb
;
318 /* external bitmaps */
319 extern const fb_data jewels
[];
321 /* tile background colors */
322 #ifdef HAVE_LCD_COLOR
323 static const unsigned jewels_bkgd
[2] = {
324 LCD_RGBPACK(104, 63, 63),
325 LCD_RGBPACK(83, 44, 44)
330 * type is the jewel number 0-7
331 * falling if the jewel is falling
332 * delete marks the jewel for deletion
340 /* the game context struct
341 * score is the current level score
342 * segments is the number of cleared segments in the current run
343 * level is the current level
344 * type is the game type (normal or puzzle)
345 * highscores is the list of high scores
346 * resume denotes whether to resume the currently loaded game
347 * dirty denotes whether the high scores are out of sync with the saved file
348 * playboard is the game playing board (first row is hidden)
349 * num_jewels is the number of different jewels to use
351 struct game_context
{
353 unsigned int segments
;
356 unsigned int highscores
[NUM_SCORES
];
359 struct tile playboard
[BJ_HEIGHT
][BJ_WIDTH
];
360 unsigned int num_jewels
;
363 #define MAX_NUM_JEWELS 7
365 #define MAX_PUZZLE_TILES 4
366 #define NUM_PUZZLE_LEVELS 10
374 struct puzzle_level
{
375 unsigned int num_jewels
;
376 unsigned int num_tiles
;
377 struct puzzle_tile tiles
[MAX_PUZZLE_TILES
];
380 #define PUZZLE_TILE_UP 1
381 #define PUZZLE_TILE_DOWN 2
382 #define PUZZLE_TILE_LEFT 4
383 #define PUZZLE_TILE_RIGHT 8
385 struct puzzle_level puzzle_levels
[NUM_PUZZLE_LEVELS
] = {
386 { 5, 2, { {3, 3, PUZZLE_TILE_RIGHT
},
387 {4, 2, PUZZLE_TILE_LEFT
} } },
388 { 5, 2, { {3, 2, PUZZLE_TILE_DOWN
},
389 {3, 4, PUZZLE_TILE_UP
} } },
390 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
391 {3, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
392 {3, 6, PUZZLE_TILE_UP
} } },
393 { 6, 3, { {3, 2, PUZZLE_TILE_RIGHT
},
394 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
395 {5, 4, PUZZLE_TILE_LEFT
} } },
396 { 6, 2, { {3, 4, PUZZLE_TILE_RIGHT
},
397 {4, 2, PUZZLE_TILE_LEFT
} } },
398 { 6, 2, { {3, 2, PUZZLE_TILE_DOWN
},
399 {4, 4, PUZZLE_TILE_UP
} } },
400 { 7, 4, { {3, 2, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
401 {4, 3, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
402 {3, 4, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
403 {4, 4, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
404 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN
},
405 {4, 4, PUZZLE_TILE_UP
|PUZZLE_TILE_DOWN
},
406 {3, 6, PUZZLE_TILE_UP
} } },
407 { 7, 3, { {2, 2, PUZZLE_TILE_RIGHT
},
408 {4, 1, PUZZLE_TILE_LEFT
|PUZZLE_TILE_RIGHT
},
409 {5, 4, PUZZLE_TILE_LEFT
} } },
410 { 7, 4, { {3, 0, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_DOWN
},
411 {5, 0, PUZZLE_TILE_LEFT
|PUZZLE_TILE_DOWN
},
412 {2, 7, PUZZLE_TILE_RIGHT
|PUZZLE_TILE_UP
},
413 {4, 7, PUZZLE_TILE_LEFT
|PUZZLE_TILE_UP
} } },
416 /*****************************************************************************
417 * jewels_init() initializes jewels data structures.
418 ******************************************************************************/
419 static void jewels_init(struct game_context
* bj
) {
420 /* seed the rand generator */
421 rb
->srand(*rb
->current_tick
);
423 /* check for resumed game */
434 /* clear playing board */
435 rb
->memset(bj
->playboard
, 0, sizeof(bj
->playboard
));
438 /*****************************************************************************
439 * jewels_setcolors() set the foreground and background colors.
440 ******************************************************************************/
441 static inline void jewels_setcolors(void) {
442 #ifdef HAVE_LCD_COLOR
443 rb
->lcd_set_background(LCD_RGBPACK(49, 26, 26));
444 rb
->lcd_set_foreground(LCD_RGBPACK(210, 181, 181));
448 /*****************************************************************************
449 * jewels_drawboard() redraws the entire game board.
450 ******************************************************************************/
451 static void jewels_drawboard(struct game_context
* bj
) {
454 unsigned int tempscore
;
455 char *title
= "Level";
458 tempscore
= (bj
->score
>LEVEL_PTS
? LEVEL_PTS
: bj
->score
);
461 rb
->lcd_clear_display();
463 /* dispay playing board */
464 for(i
=0; i
<BJ_HEIGHT
-1; i
++){
465 for(j
=0; j
<BJ_WIDTH
; j
++){
466 #ifdef HAVE_LCD_COLOR
467 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
468 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
469 TILE_WIDTH
, TILE_HEIGHT
);
470 rb
->lcd_bitmap_transparent_part(jewels
,
471 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
472 TILE_WIDTH
, j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
473 TILE_WIDTH
, TILE_HEIGHT
);
475 rb
->lcd_bitmap_part(jewels
,
476 0, TILE_HEIGHT
*(bj
->playboard
[i
+1][j
].type
),
477 TILE_WIDTH
, j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
478 TILE_WIDTH
, TILE_HEIGHT
);
483 #if LCD_WIDTH > LCD_HEIGHT /* horizontal layout */
485 /* draw separator lines */
487 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, LCD_HEIGHT
-1);
488 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, 18);
489 rb
->lcd_hline(BJ_WIDTH
*TILE_WIDTH
, LCD_WIDTH
-1, LCD_HEIGHT
-10);
491 /* draw progress bar */
492 #ifdef HAVE_LCD_COLOR
493 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
495 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
496 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
497 tempscore
/LEVEL_PTS
),
498 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
499 ((LCD_HEIGHT
-10)-18)*tempscore
/LEVEL_PTS
);
500 #ifdef HAVE_LCD_COLOR
501 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
502 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
503 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
504 tempscore
/LEVEL_PTS
)+1,
505 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
506 ((LCD_HEIGHT
-10)-18)*tempscore
/LEVEL_PTS
-1);
508 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
509 (LCD_HEIGHT
-10)-(((LCD_HEIGHT
-10)-18)*
510 tempscore
/LEVEL_PTS
),
511 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
512 ((LCD_HEIGHT
-10)-18)*tempscore
/LEVEL_PTS
+1);
516 rb
->lcd_getstringsize(title
, &w
, &h
);
517 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 1, title
);
519 rb
->snprintf(str
, 4, "%d", bj
->level
);
520 rb
->lcd_getstringsize(str
, &w
, &h
);
521 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2, 10, str
);
523 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
524 rb
->lcd_getstringsize(str
, &w
, &h
);
525 rb
->lcd_putsxy(LCD_WIDTH
-(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-w
/2,
528 #elif LCD_WIDTH < LCD_HEIGHT /* vertical layout */
530 /* draw separator lines */
532 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
533 rb
->lcd_hline(0, LCD_WIDTH
-1, LCD_HEIGHT
-14);
534 rb
->lcd_vline(LCD_WIDTH
/2, LCD_HEIGHT
-14, LCD_HEIGHT
-1);
536 /* draw progress bar */
537 #ifdef HAVE_LCD_COLOR
538 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
540 rb
->lcd_fillrect(0, (8*TILE_HEIGHT
+YOFS
)
541 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
542 LCD_WIDTH
*tempscore
/LEVEL_PTS
,
543 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
544 #ifdef HAVE_LCD_COLOR
545 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
546 rb
->lcd_drawrect(1, (8*TILE_HEIGHT
+YOFS
)
547 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4+1,
548 LCD_WIDTH
*tempscore
/LEVEL_PTS
-1,
549 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2-2);
551 rb
->lcd_drawrect(0, (8*TILE_HEIGHT
+YOFS
)
552 +(LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/4,
553 LCD_WIDTH
*tempscore
/LEVEL_PTS
+1,
554 (LCD_HEIGHT
-14-(8*TILE_HEIGHT
+YOFS
))/2);
558 rb
->snprintf(str
, 10, "%s %d", title
, bj
->level
);
559 rb
->lcd_putsxy(1, LCD_HEIGHT
-10, str
);
561 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
562 rb
->lcd_getstringsize(str
, &w
, &h
);
563 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
, LCD_HEIGHT
-10, str
);
565 #else /* square layout */
567 /* draw separator lines */
569 rb
->lcd_hline(0, LCD_WIDTH
-1, 8*TILE_HEIGHT
+YOFS
);
570 rb
->lcd_vline(BJ_WIDTH
*TILE_WIDTH
, 0, 8*TILE_HEIGHT
+YOFS
);
571 rb
->lcd_vline(LCD_WIDTH
/2, 8*TILE_HEIGHT
+YOFS
, LCD_HEIGHT
-1);
573 /* draw progress bar */
574 #ifdef HAVE_LCD_COLOR
575 rb
->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
577 rb
->lcd_fillrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
578 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
579 *tempscore
/LEVEL_PTS
,
580 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
581 (8*TILE_HEIGHT
+YOFS
)*tempscore
/LEVEL_PTS
);
582 #ifdef HAVE_LCD_COLOR
583 rb
->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
584 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4+1,
585 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
586 *tempscore
/LEVEL_PTS
+1,
587 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2-2,
588 (8*TILE_HEIGHT
+YOFS
)*tempscore
/LEVEL_PTS
-1);
590 rb
->lcd_drawrect(BJ_WIDTH
*TILE_WIDTH
+(LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/4,
591 (8*TILE_HEIGHT
+YOFS
)-(8*TILE_HEIGHT
+YOFS
)
592 *tempscore
/LEVEL_PTS
,
593 (LCD_WIDTH
-BJ_WIDTH
*TILE_WIDTH
)/2,
594 (8*TILE_HEIGHT
+YOFS
)*tempscore
/LEVEL_PTS
+1);
598 rb
->snprintf(str
, 10, "%s %d", title
, bj
->level
);
599 rb
->lcd_putsxy(1, LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3, str
);
601 rb
->snprintf(str
, 6, "%d", (bj
->level
-1)*LEVEL_PTS
+bj
->score
);
602 rb
->lcd_getstringsize(str
, &w
, &h
);
603 rb
->lcd_putsxy((LCD_WIDTH
-2)-w
,
604 LCD_HEIGHT
-(LCD_HEIGHT
-(8*TILE_HEIGHT
+YOFS
))/2-3, str
);
611 /*****************************************************************************
612 * jewels_showmenu() displays the chosen menu after performing the chosen
614 ******************************************************************************/
615 static enum menu_result
jewels_showmenu(struct jewels_menu
* menu
,
622 /* handle menu command */
625 menu
->selected
= (menu
->selected
+1)%menu
->itemcnt
;
629 menu
->selected
= (menu
->selected
-1+menu
->itemcnt
)%menu
->itemcnt
;
633 return menu
->items
[menu
->selected
].res
;
639 /* clear menu area */
640 firstline
= (LCD_HEIGHT
/FONT_HEIGHT
-(menu
->itemcnt
+3))/2;
642 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
643 rb
->lcd_fillrect((LCD_WIDTH
-MENU_WIDTH
)/2, firstline
*FONT_HEIGHT
,
644 MENU_WIDTH
, (menu
->itemcnt
+3)*FONT_HEIGHT
);
645 rb
->lcd_set_drawmode(DRMODE_SOLID
);
648 rb
->lcd_drawrect((LCD_WIDTH
-MENU_WIDTH
)/2-1, firstline
*FONT_HEIGHT
-1,
649 MENU_WIDTH
+2, (menu
->itemcnt
+3)*FONT_HEIGHT
+2);
650 rb
->lcd_hline((LCD_WIDTH
-MENU_WIDTH
)/2-1,
651 (LCD_WIDTH
-MENU_WIDTH
)/2-1+MENU_WIDTH
+2,
652 (firstline
+1)*FONT_HEIGHT
);
655 /* draw menu items */
656 rb
->lcd_getstringsize(menu
->title
, &w
, &h
);
657 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, firstline
*FONT_HEIGHT
, menu
->title
);
659 for(i
=0; i
<menu
->itemcnt
; i
++) {
660 if(i
== menu
->selected
) {
661 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
663 rb
->lcd_putsxy((LCD_WIDTH
-MENU_WIDTH
)/2, (firstline
+i
+2)*FONT_HEIGHT
,
664 menu
->items
[i
].text
);
665 if(i
== menu
->selected
) {
666 rb
->lcd_set_drawmode(DRMODE_SOLID
);
670 adj
= (firstline
== 0 ? 0 : 1);
671 rb
->lcd_update_rect((LCD_WIDTH
-MENU_WIDTH
)/2-1, firstline
*FONT_HEIGHT
-adj
,
672 MENU_WIDTH
+2, (menu
->itemcnt
+3)*FONT_HEIGHT
+2*adj
);
676 /*****************************************************************************
677 * jewels_putjewels() makes the jewels fall to fill empty spots and adds
678 * new random jewels at the empty spots at the top of each row.
679 ******************************************************************************/
680 static void jewels_putjewels(struct game_context
* bj
){
683 long lasttick
, currenttick
;
685 /* loop to make all the jewels fall */
687 /* mark falling jewels and add new jewels to hidden top row*/
690 for(j
=0; j
<BJ_WIDTH
; j
++) {
691 if(bj
->playboard
[1][j
].type
== 0) {
692 bj
->playboard
[0][j
].type
= rb
->rand()%bj
->num_jewels
+1;
694 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
695 if(!mark
&& bj
->playboard
[i
+1][j
].type
== 0) {
699 if(mark
) bj
->playboard
[i
][j
].falling
= true;
701 /*if(bj->playboard[1][j].falling) {
702 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
703 bj->playboard[0][j].falling = true;
708 /* break if there are no falling jewels */
711 /* animate falling jewels */
712 lasttick
= *rb
->current_tick
;
714 for(k
=1; k
<=8; k
++) {
715 for(i
=BJ_HEIGHT
-2; i
>=0; i
--) {
716 for(j
=0; j
<BJ_WIDTH
; j
++) {
717 if(bj
->playboard
[i
][j
].falling
&&
718 bj
->playboard
[i
][j
].type
!= 0) {
719 /* clear old position */
720 #ifdef HAVE_LCD_COLOR
722 rb
->lcd_set_foreground(rb
->lcd_get_background());
724 rb
->lcd_set_foreground(jewels_bkgd
[(i
-1+j
)%2]);
726 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
727 TILE_WIDTH
, TILE_HEIGHT
);
728 if(bj
->playboard
[i
+1][j
].type
== 0) {
729 rb
->lcd_set_foreground(jewels_bkgd
[(i
+j
)%2]);
730 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
731 TILE_WIDTH
, TILE_HEIGHT
);
734 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
735 rb
->lcd_fillrect(j
*TILE_WIDTH
, (i
-1)*TILE_HEIGHT
+YOFS
,
736 TILE_WIDTH
, TILE_HEIGHT
);
737 if(bj
->playboard
[i
+1][j
].type
== 0) {
738 rb
->lcd_fillrect(j
*TILE_WIDTH
, i
*TILE_HEIGHT
+YOFS
,
739 TILE_WIDTH
, TILE_HEIGHT
);
741 rb
->lcd_set_drawmode(DRMODE_SOLID
);
744 /* draw new position */
745 #ifdef HAVE_LCD_COLOR
746 rb
->lcd_bitmap_transparent_part(jewels
, 0,
747 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
748 TILE_WIDTH
, j
*TILE_WIDTH
,
749 (i
-1)*TILE_HEIGHT
+YOFS
+
750 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
751 TILE_WIDTH
, TILE_HEIGHT
);
753 rb
->lcd_bitmap_part(jewels
, 0,
754 TILE_HEIGHT
*(bj
->playboard
[i
][j
].type
),
755 TILE_WIDTH
, j
*TILE_WIDTH
,
756 (i
-1)*TILE_HEIGHT
+YOFS
+
757 ((((TILE_HEIGHT
<<10)*k
)/8)>>10),
758 TILE_WIDTH
, TILE_HEIGHT
);
764 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
767 /* framerate limiting */
768 currenttick
= *rb
->current_tick
;
769 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
770 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
774 lasttick
= currenttick
;
777 /* shift jewels down */
778 for(j
=0; j
<BJ_WIDTH
; j
++) {
779 for(i
=BJ_HEIGHT
-1; i
>=1; i
--) {
780 if(bj
->playboard
[i
-1][j
].falling
) {
781 bj
->playboard
[i
][j
].type
= bj
->playboard
[i
-1][j
].type
;
786 /* clear out top row */
787 for(j
=0; j
<BJ_WIDTH
; j
++) {
788 bj
->playboard
[0][j
].type
= 0;
791 /* mark everything not falling */
792 for(i
=0; i
<BJ_HEIGHT
; i
++) {
793 for(j
=0; j
<BJ_WIDTH
; j
++) {
794 bj
->playboard
[i
][j
].falling
= false;
800 /*****************************************************************************
801 * jewels_clearjewels() finds all the connected rows and columns and
802 * calculates and returns the points earned.
803 ******************************************************************************/
804 static unsigned int jewels_clearjewels(struct game_context
* bj
) {
807 unsigned int points
= 0;
809 /* check for connected rows */
810 for(i
=1; i
<BJ_HEIGHT
; i
++) {
813 for(j
=0; j
<BJ_WIDTH
; j
++) {
814 if(bj
->playboard
[i
][j
].type
== last
&&
815 bj
->playboard
[i
][j
].type
!= 0 &&
816 bj
->playboard
[i
][j
].type
<= MAX_NUM_JEWELS
) {
821 points
+= bj
->segments
;
822 bj
->playboard
[i
][j
].delete = true;
823 bj
->playboard
[i
][j
-1].delete = true;
824 bj
->playboard
[i
][j
-2].delete = true;
827 bj
->playboard
[i
][j
].delete = true;
831 last
= bj
->playboard
[i
][j
].type
;
836 /* check for connected columns */
837 for(j
=0; j
<BJ_WIDTH
; j
++) {
840 for(i
=1; i
<BJ_HEIGHT
; i
++) {
841 if(bj
->playboard
[i
][j
].type
!= 0 &&
842 bj
->playboard
[i
][j
].type
== last
&&
843 bj
->playboard
[i
][j
].type
<= MAX_NUM_JEWELS
) {
848 points
+= bj
->segments
;
849 bj
->playboard
[i
][j
].delete = true;
850 bj
->playboard
[i
-1][j
].delete = true;
851 bj
->playboard
[i
-2][j
].delete = true;
854 bj
->playboard
[i
][j
].delete = true;
858 last
= bj
->playboard
[i
][j
].type
;
863 /* clear deleted jewels */
864 for(i
=1; i
<BJ_HEIGHT
; i
++) {
865 for(j
=0; j
<BJ_WIDTH
; j
++) {
866 if(bj
->playboard
[i
][j
].delete) {
867 bj
->playboard
[i
][j
].delete = false;
868 bj
->playboard
[i
][j
].type
= 0;
876 /*****************************************************************************
877 * jewels_runboard() runs the board until it settles in a fixed state and
878 * returns points earned.
879 ******************************************************************************/
880 static unsigned int jewels_runboard(struct game_context
* bj
) {
881 unsigned int points
= 0;
886 while((ret
= jewels_clearjewels(bj
)) > 0) {
888 jewels_drawboard(bj
);
889 jewels_putjewels(bj
);
895 /*****************************************************************************
896 * jewels_swapjewels() swaps two jewels as long as it results in points and
897 * returns points earned.
898 ******************************************************************************/
899 static unsigned int jewels_swapjewels(struct game_context
* bj
,
900 int x
, int y
, int direc
) {
902 int horzmod
, vertmod
;
905 unsigned int points
= 0;
906 long lasttick
, currenttick
;
908 /* check for invalid parameters */
909 if(x
< 0 || x
>= BJ_WIDTH
|| y
< 0 || y
>= BJ_HEIGHT
-1 ||
910 direc
< SWAP_UP
|| direc
> SWAP_LEFT
) {
914 /* check for invalid directions */
915 if((x
== 0 && direc
== SWAP_LEFT
) ||
916 (x
== BJ_WIDTH
-1 && direc
== SWAP_RIGHT
) ||
917 (y
== 0 && direc
== SWAP_UP
) ||
918 (y
== BJ_HEIGHT
-2 && direc
== SWAP_DOWN
)) {
922 /* set direction variables */
928 movelen
= TILE_HEIGHT
;
932 movelen
= TILE_WIDTH
;
936 movelen
= TILE_HEIGHT
;
940 movelen
= TILE_WIDTH
;
945 lasttick
= *rb
->current_tick
;
947 /* animate swapping jewels */
948 for(k
=0; k
<=8; k
++) {
949 /* clear old position */
950 #ifdef HAVE_LCD_COLOR
951 rb
->lcd_set_foreground(jewels_bkgd
[(x
+y
)%2]);
952 rb
->lcd_fillrect(x
*TILE_WIDTH
,
954 TILE_WIDTH
, TILE_HEIGHT
);
955 rb
->lcd_set_foreground(jewels_bkgd
[(x
+horzmod
+y
+vertmod
)%2]);
956 rb
->lcd_fillrect((x
+horzmod
)*TILE_WIDTH
,
957 (y
+vertmod
)*TILE_HEIGHT
+YOFS
,
958 TILE_WIDTH
, TILE_HEIGHT
);
960 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
961 rb
->lcd_fillrect(x
*TILE_WIDTH
,
963 TILE_WIDTH
, TILE_HEIGHT
);
964 rb
->lcd_fillrect((x
+horzmod
)*TILE_WIDTH
,
965 (y
+vertmod
)*TILE_HEIGHT
+YOFS
,
966 TILE_WIDTH
, TILE_HEIGHT
);
967 rb
->lcd_set_drawmode(DRMODE_SOLID
);
969 /* draw new position */
970 #ifdef HAVE_LCD_COLOR
971 rb
->lcd_bitmap_transparent_part(jewels
,
972 0, TILE_HEIGHT
*(bj
->playboard
973 [y
+1+vertmod
][x
+horzmod
].type
), TILE_WIDTH
,
974 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
975 ((((movelen
<<10)*k
)/8)>>10),
976 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
977 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
978 TILE_WIDTH
, TILE_HEIGHT
);
979 rb
->lcd_bitmap_transparent_part(jewels
,
980 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
981 TILE_WIDTH
, x
*TILE_WIDTH
+horzmod
*
982 ((((movelen
<<10)*k
)/8)>>10),
983 y
*TILE_HEIGHT
+vertmod
*
984 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
985 TILE_WIDTH
, TILE_HEIGHT
);
987 rb
->lcd_bitmap_part(jewels
,
988 0, TILE_HEIGHT
*(bj
->playboard
989 [y
+1+vertmod
][x
+horzmod
].type
), TILE_WIDTH
,
990 (x
+horzmod
)*TILE_WIDTH
-horzmod
*
991 ((((movelen
<<10)*k
)/8)>>10),
992 (y
+vertmod
)*TILE_HEIGHT
-vertmod
*
993 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
994 TILE_WIDTH
, TILE_HEIGHT
);
995 rb
->lcd_set_drawmode(DRMODE_FG
);
996 rb
->lcd_bitmap_part(jewels
,
997 0, TILE_HEIGHT
*(bj
->playboard
[y
+1][x
].type
),
998 TILE_WIDTH
, x
*TILE_WIDTH
+horzmod
*
999 ((((movelen
<<10)*k
)/8)>>10),
1000 y
*TILE_HEIGHT
+vertmod
*
1001 ((((movelen
<<10)*k
)/8)>>10)+YOFS
,
1002 TILE_WIDTH
, TILE_HEIGHT
);
1003 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1006 rb
->lcd_update_rect(0, 0, TILE_WIDTH
*8, LCD_HEIGHT
);
1009 /* framerate limiting */
1010 currenttick
= *rb
->current_tick
;
1011 if(currenttick
-lasttick
< HZ
/MAX_FPS
) {
1012 rb
->sleep((HZ
/MAX_FPS
)-(currenttick
-lasttick
));
1016 lasttick
= currenttick
;
1020 int temp
= bj
->playboard
[y
+1][x
].type
;
1021 bj
->playboard
[y
+1][x
].type
=
1022 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
;
1023 bj
->playboard
[y
+1+vertmod
][x
+horzmod
].type
= temp
;
1027 points
= jewels_runboard(bj
);
1038 /*****************************************************************************
1039 * jewels_movesavail() uses pattern matching to see if there are any
1040 * available move left.
1041 ******************************************************************************/
1042 static bool jewels_movesavail(struct game_context
* bj
) {
1047 for(i
=1; i
<BJ_HEIGHT
; i
++) {
1048 for(j
=0; j
<BJ_WIDTH
; j
++) {
1049 mytype
= bj
->playboard
[i
][j
].type
;
1050 if(mytype
== 0 || mytype
> MAX_NUM_JEWELS
) continue;
1052 /* check horizontal patterns */
1053 if(j
<= BJ_WIDTH
-3) {
1055 if(bj
->playboard
[i
-1][j
+1].type
== mytype
) {
1056 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1057 {moves
= true; break;}
1058 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1059 {moves
= true; break;}
1061 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1062 if(bj
->playboard
[i
-1][j
+2].type
== mytype
)
1063 {moves
= true; break;}
1067 if(j
<= BJ_WIDTH
-4) {
1068 if(bj
->playboard
[i
][j
+3].type
== mytype
) {
1069 if(bj
->playboard
[i
][j
+1].type
== mytype
)
1070 {moves
= true; break;}
1071 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1072 {moves
= true; break;}
1076 if(i
< BJ_HEIGHT
-1) {
1077 if(bj
->playboard
[i
][j
+1].type
== mytype
) {
1078 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1079 {moves
= true; break;}
1081 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1082 if(bj
->playboard
[i
][j
+2].type
== mytype
)
1083 {moves
= true; break;}
1084 if(bj
->playboard
[i
+1][j
+2].type
== mytype
)
1085 {moves
= true; break;}
1090 /* check vertical patterns */
1091 if(i
<= BJ_HEIGHT
-3) {
1093 if(bj
->playboard
[i
+1][j
-1].type
== mytype
) {
1094 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1095 {moves
= true; break;}
1096 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1097 {moves
= true; break;}
1099 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1100 if(bj
->playboard
[i
+2][j
-1].type
== mytype
)
1101 {moves
= true; break;}
1105 if(i
<= BJ_HEIGHT
-4) {
1106 if(bj
->playboard
[i
+3][j
].type
== mytype
) {
1107 if(bj
->playboard
[i
+1][j
].type
== mytype
)
1108 {moves
= true; break;}
1109 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1110 {moves
= true; break;}
1114 if(j
< BJ_WIDTH
-1) {
1115 if(bj
->playboard
[i
+1][j
].type
== mytype
) {
1116 if(bj
->playboard
[i
+2][j
+1].type
== mytype
)
1117 {moves
= true; break;}
1119 if(bj
->playboard
[i
+1][j
+1].type
== mytype
) {
1120 if(bj
->playboard
[i
+2][j
].type
== mytype
)
1121 {moves
= true; break;}
1122 if (bj
->playboard
[i
+2][j
+1].type
== mytype
)
1123 {moves
= true; break;}
1135 /*****************************************************************************
1136 * jewels_puzzle_is_finished(bj) checks if the puzzle is finished.
1137 ******************************************************************************/
1138 static int jewels_puzzle_is_finished(struct game_context
* bj
) {
1140 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1141 for(j
=0; j
<BJ_WIDTH
; j
++) {
1142 int mytype
= bj
->playboard
[i
][j
].type
;
1143 if(mytype
>MAX_NUM_JEWELS
) {
1144 mytype
-= MAX_NUM_JEWELS
;
1145 if(mytype
&PUZZLE_TILE_UP
) {
1146 if(i
==0 || bj
->playboard
[i
-1][j
].type
<=MAX_NUM_JEWELS
||
1147 !((bj
->playboard
[i
-1][j
].type
-MAX_NUM_JEWELS
)
1151 if(mytype
&PUZZLE_TILE_DOWN
) {
1152 if(i
==BJ_HEIGHT
-1 ||
1153 bj
->playboard
[i
+1][j
].type
<=MAX_NUM_JEWELS
||
1154 !((bj
->playboard
[i
+1][j
].type
-MAX_NUM_JEWELS
)
1158 if(mytype
&PUZZLE_TILE_LEFT
) {
1159 if(j
==0 || bj
->playboard
[i
][j
-1].type
<=MAX_NUM_JEWELS
||
1160 !((bj
->playboard
[i
][j
-1].type
-MAX_NUM_JEWELS
)
1161 &PUZZLE_TILE_RIGHT
))
1164 if(mytype
&PUZZLE_TILE_RIGHT
) {
1166 bj
->playboard
[i
][j
+1].type
<=MAX_NUM_JEWELS
||
1167 !((bj
->playboard
[i
][j
+1].type
-MAX_NUM_JEWELS
)
1177 /*****************************************************************************
1178 * jewels_initlevel() initialises a level.
1179 ******************************************************************************/
1180 static unsigned int jewels_initlevel(struct game_context
* bj
) {
1181 unsigned int points
= 0;
1184 case GAME_TYPE_NORMAL
:
1185 bj
->num_jewels
= MAX_NUM_JEWELS
;
1188 case GAME_TYPE_PUZZLE
:
1191 struct puzzle_tile
*tile
;
1193 bj
->num_jewels
= puzzle_levels
[bj
->level
-1].num_jewels
;
1195 for(i
=0; i
<BJ_HEIGHT
; i
++) {
1196 for(j
=0; j
<BJ_WIDTH
; j
++) {
1197 bj
->playboard
[i
][j
].type
= (rb
->rand()%bj
->num_jewels
)+1;
1198 bj
->playboard
[i
][j
].falling
= false;
1199 bj
->playboard
[i
][j
].delete = false;
1202 jewels_runboard(bj
);
1203 tile
= puzzle_levels
[bj
->level
-1].tiles
;
1204 for(i
=0; i
<puzzle_levels
[bj
->level
-1].num_tiles
; i
++, tile
++) {
1205 bj
->playboard
[tile
->y
+1][tile
->x
].type
= MAX_NUM_JEWELS
1212 jewels_drawboard(bj
);
1214 /* run the play board */
1215 jewels_putjewels(bj
);
1216 points
+= jewels_runboard(bj
);
1220 /*****************************************************************************
1221 * jewels_nextlevel() advances the game to the next level and returns
1223 ******************************************************************************/
1224 static unsigned int jewels_nextlevel(struct game_context
* bj
) {
1226 unsigned int points
= 0;
1229 case GAME_TYPE_NORMAL
:
1230 /* roll over score, change and display level */
1231 while(bj
->score
>= LEVEL_PTS
) {
1232 bj
->score
-= LEVEL_PTS
;
1234 rb
->splash(HZ
*2, "Level %d", bj
->level
);
1235 jewels_drawboard(bj
);
1238 /* randomly clear some jewels */
1239 for(i
=0; i
<16; i
++) {
1243 if(bj
->playboard
[y
][x
].type
!= 0) {
1245 bj
->playboard
[y
][x
].type
= 0;
1250 case GAME_TYPE_PUZZLE
:
1252 if(bj
->level
>NUM_PUZZLE_LEVELS
) {
1253 rb
->splash(HZ
*2, "You win!");
1256 rb
->splash(HZ
*2, "Level %d", bj
->level
);
1261 return jewels_initlevel(bj
);
1264 /*****************************************************************************
1265 * jewels_recordscore() inserts a high score into the high scores list and
1266 * returns the high score position.
1267 ******************************************************************************/
1268 static int jewels_recordscore(struct game_context
* bj
) {
1271 unsigned int current
, temp
;
1273 /* calculate total score */
1274 current
= (bj
->level
-1)*LEVEL_PTS
+bj
->score
;
1275 if(current
<= 0) return 0;
1277 /* insert the current score into the high scores */
1278 for(i
=0; i
<NUM_SCORES
; i
++) {
1279 if(current
>= bj
->highscores
[i
]) {
1284 temp
= bj
->highscores
[i
];
1285 bj
->highscores
[i
] = current
;
1293 /*****************************************************************************
1294 * jewels_loadscores() loads the high scores saved file.
1295 ******************************************************************************/
1296 static void jewels_loadscores(struct game_context
* bj
) {
1301 /* clear high scores */
1302 rb
->memset(bj
->highscores
, 0, sizeof(bj
->highscores
));
1304 /* open scores file */
1305 fd
= rb
->open(SCORE_FILE
, O_RDONLY
);
1308 /* read in high scores */
1309 if(rb
->read(fd
, bj
->highscores
, sizeof(bj
->highscores
)) <= 0) {
1310 /* scores are bad, reset */
1311 rb
->memset(bj
->highscores
, 0, sizeof(bj
->highscores
));
1317 /*****************************************************************************
1318 * jewels_savescores() saves the high scores saved file.
1319 ******************************************************************************/
1320 static void jewels_savescores(struct game_context
* bj
) {
1323 /* write out the high scores to the save file */
1324 fd
= rb
->open(SCORE_FILE
, O_WRONLY
|O_CREAT
);
1325 rb
->write(fd
, bj
->highscores
, sizeof(bj
->highscores
));
1330 /*****************************************************************************
1331 * jewels_loadgame() loads the saved game and returns load success.
1332 ******************************************************************************/
1333 static bool jewels_loadgame(struct game_context
* bj
) {
1335 bool loaded
= false;
1337 /* open game file */
1338 fd
= rb
->open(SAVE_FILE
, O_RDONLY
);
1339 if(fd
< 0) return loaded
;
1341 /* read in saved game */
1343 if(rb
->read(fd
, &bj
->score
, sizeof(bj
->score
)) <= 0) break;
1344 if(rb
->read(fd
, &bj
->level
, sizeof(bj
->level
)) <= 0) break;
1345 if(rb
->read(fd
, &bj
->type
, sizeof(bj
->type
)) <= 0) break;
1346 if(rb
->read(fd
, bj
->playboard
, sizeof(bj
->playboard
)) <= 0) break;
1354 /* delete saved file */
1355 rb
->remove(SAVE_FILE
);
1359 /*****************************************************************************
1360 * jewels_savegame() saves the current game state.
1361 ******************************************************************************/
1362 static void jewels_savegame(struct game_context
* bj
) {
1365 /* write out the game state to the save file */
1366 fd
= rb
->open(SAVE_FILE
, O_WRONLY
|O_CREAT
);
1367 rb
->write(fd
, &bj
->score
, sizeof(bj
->score
));
1368 rb
->write(fd
, &bj
->level
, sizeof(bj
->level
));
1369 rb
->write(fd
, &bj
->type
, sizeof(bj
->type
));
1370 rb
->write(fd
, bj
->playboard
, sizeof(bj
->playboard
));
1376 /*****************************************************************************
1377 * jewels_callback() is the default event handler callback which is called
1378 * on usb connect and shutdown.
1379 ******************************************************************************/
1380 static void jewels_callback(void* param
) {
1381 struct game_context
* bj
= (struct game_context
*) param
;
1383 rb
->splash(HZ
, "Saving high scores...");
1384 jewels_savescores(bj
);
1388 /*****************************************************************************
1389 * jewels_main() is the main game subroutine, it returns the final game status.
1390 ******************************************************************************/
1391 static int jewels_main(struct game_context
* bj
) {
1396 bool startgame
= false;
1397 bool inmenu
= false;
1398 bool selected
= false;
1399 enum menu_cmd cmd
= MCMD_NONE
;
1400 enum menu_result res
;
1402 /* the cursor coordinates */
1405 /* don't resume by default */
1408 /********************
1410 ********************/
1411 rb
->lcd_clear_display();
1414 res
= jewels_showmenu(&bjmenu
[0], cmd
);
1417 rb
->snprintf(str
, 18, "High Score: %d", bj
->highscores
[0]);
1418 rb
->lcd_getstringsize(str
, &w
, &h
);
1419 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, LCD_HEIGHT
-8, str
);
1425 bj
->type
= GAME_TYPE_NORMAL
;
1430 bj
->type
= GAME_TYPE_PUZZLE
;
1434 if(!jewels_loadgame(bj
)) {
1435 rb
->splash(HZ
*2, "Nothing to resume");
1436 rb
->lcd_clear_display();
1443 rb
->lcd_clear_display();
1445 /* room for a title? */
1447 if(LCD_HEIGHT
-NUM_SCORES
*8 >= 8) {
1448 rb
->snprintf(str
, 12, "%s", "High Scores");
1449 rb
->lcd_getstringsize(str
, &w
, &h
);
1450 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, 0, str
);
1454 /* print high scores */
1455 for(i
=0; i
<NUM_SCORES
; i
++) {
1456 rb
->snprintf(str
, 11, "#%02d: %d", i
+1, bj
->highscores
[i
]);
1457 rb
->lcd_puts(0, i
+j
, str
);
1462 button
= rb
->button_get(true);
1463 if(button
!= BUTTON_NONE
&& !(button
&BUTTON_REL
)) break;
1465 rb
->lcd_clear_display();
1469 /* welcome screen to display key bindings */
1470 rb
->lcd_clear_display();
1471 rb
->snprintf(str
, 5, "%s", "Help");
1472 rb
->lcd_getstringsize(str
, &w
, &h
);
1473 rb
->lcd_putsxy((LCD_WIDTH
-w
)/2, 0, str
);
1474 #if CONFIG_KEYPAD == RECORDER_PAD
1475 rb
->lcd_puts(0, 2, "Controls:");
1476 rb
->lcd_puts(0, 3, "Directions = move");
1477 rb
->lcd_puts(0, 4, "PLAY = select");
1478 rb
->lcd_puts(0, 5, "Long PLAY = menu");
1479 rb
->lcd_puts(0, 6, "OFF = cancel");
1480 #elif CONFIG_KEYPAD == ONDIO_PAD
1481 rb
->lcd_puts(0, 2, "Controls:");
1482 rb
->lcd_puts(0, 3, "Directions = move");
1483 rb
->lcd_puts(0, 4, "MENU = select");
1484 rb
->lcd_puts(0, 5, "Long MENU = menu");
1485 rb
->lcd_puts(0, 6, "OFF = cancel");
1486 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
1487 rb
->lcd_puts(0, 2, "Controls:");
1488 rb
->lcd_puts(0, 3, "Directions = move");
1489 rb
->lcd_puts(0, 4, "SELECT = select");
1490 rb
->lcd_puts(0, 5, "Long SELECT = menu");
1491 rb
->lcd_puts(0, 6, "PLAY = cancel");
1492 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
1493 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1494 rb
->lcd_puts(0, 3, "form connected segments");
1495 rb
->lcd_puts(0, 4, "of three or more of the");
1496 rb
->lcd_puts(0, 5, "same type.");
1497 rb
->lcd_puts(0, 7, "Controls:");
1498 rb
->lcd_puts(0, 8, "Directions to move");
1499 rb
->lcd_puts(0, 9, "SELECT to select");
1500 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1501 rb
->lcd_puts(0, 11, "OFF to cancel");
1502 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1503 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1504 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1505 rb
->lcd_puts(0, 3, "form connected segments");
1506 rb
->lcd_puts(0, 4, "of three or more of the");
1507 rb
->lcd_puts(0, 5, "same type.");
1508 rb
->lcd_puts(0, 7, "Controls:");
1509 rb
->lcd_puts(0, 8, "Directions or scroll to move");
1510 rb
->lcd_puts(0, 9, "SELECT to select");
1511 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1512 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
1513 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1514 rb
->lcd_puts(0, 3, "form connected segments");
1515 rb
->lcd_puts(0, 4, "of three or more of the");
1516 rb
->lcd_puts(0, 5, "same type.");
1517 rb
->lcd_puts(0, 7, "Controls:");
1518 rb
->lcd_puts(0, 8, "Directions to move");
1519 rb
->lcd_puts(0, 9, "SELECT to select");
1520 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1521 rb
->lcd_puts(0, 11, "PLAY to cancel");
1522 #elif CONFIG_KEYPAD == GIGABEAT_PAD \
1523 || CONFIG_KEYPAD == MROBE100_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, "POWER to cancel");
1533 #elif CONFIG_KEYPAD == SANSA_E200_PAD \
1534 || CONFIG_KEYPAD == SANSA_C200_PAD
1535 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1536 rb
->lcd_puts(0, 3, "form connected segments");
1537 rb
->lcd_puts(0, 4, "of three or more of the");
1538 rb
->lcd_puts(0, 5, "same type.");
1539 rb
->lcd_puts(0, 7, "Controls:");
1540 rb
->lcd_puts(0, 8, "Directions to move");
1541 rb
->lcd_puts(0, 9, "SELECT to select");
1542 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1543 rb
->lcd_puts(0, 11, "POWER to cancel");
1544 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1545 rb
->lcd_puts(0, 2, "Swap pairs of jewels");
1546 rb
->lcd_puts(0, 3, "to form connected");
1547 rb
->lcd_puts(0, 4, "segments of three or ");
1548 rb
->lcd_puts(0, 5, "more of the");
1549 rb
->lcd_puts(0, 6, "same type.");
1550 rb
->lcd_puts(0, 8, "Controls:");
1551 rb
->lcd_puts(0, 9, "Directions or scroll to move");
1552 rb
->lcd_puts(0, 10, "PLAY to select");
1553 rb
->lcd_puts(0, 11, "Long PLAY for menu");
1554 rb
->lcd_puts(0, 12, "POWER to cancel");
1555 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1556 rb
->lcd_puts(0, 2, "Swap pairs of jewels");
1557 rb
->lcd_puts(0, 3, "to form connected");
1558 rb
->lcd_puts(0, 4, "segments of three or ");
1559 rb
->lcd_puts(0, 5, "more of the");
1560 rb
->lcd_puts(0, 6, "same type.");
1561 rb
->lcd_puts(0, 8, "Controls:");
1562 rb
->lcd_puts(0, 9, "Directions or scroll to move");
1563 rb
->lcd_puts(0, 10, "PLAY to select");
1564 rb
->lcd_puts(0, 11, "Long PLAY for menu");
1565 rb
->lcd_puts(0, 12, "REC to cancel");
1566 #elif CONFIG_KEYPAD == COWOND2_PAD
1567 rb
->lcd_puts(0, 2, "Swap pairs of jewels to");
1568 rb
->lcd_puts(0, 3, "form connected segments");
1569 rb
->lcd_puts(0, 4, "of three or more of the");
1570 rb
->lcd_puts(0, 5, "same type.");
1571 rb
->lcd_puts(0, 7, "Controls:");
1572 rb
->lcd_puts(0, 8, "Directions to move");
1573 rb
->lcd_puts(0, 9, "SELECT to select");
1574 rb
->lcd_puts(0, 10, "Long SELECT to show menu");
1575 rb
->lcd_puts(0, 11, "POWER to cancel");
1577 #warning: missing help text.
1581 button
= rb
->button_get(true);
1582 if(button
!= BUTTON_NONE
&& !(button
&BUTTON_REL
)) break;
1584 rb
->lcd_clear_display();
1594 /* handle menu button presses */
1595 button
= rb
->button_get(true);
1597 #ifdef JEWELS_SCROLLWHEEL
1599 case (JEWELS_PREV
|BUTTON_REPEAT
):
1602 case (JEWELS_UP
|BUTTON_REPEAT
):
1606 #ifdef JEWELS_SCROLLWHEEL
1608 case (JEWELS_NEXT
|BUTTON_REPEAT
):
1611 case (JEWELS_DOWN
|BUTTON_REPEAT
):
1620 #ifdef JEWELS_CANCEL
1621 #ifdef JEWELS_RC_CANCEL
1622 case JEWELS_RC_CANCEL
:
1629 if(rb
->default_event_handler_ex(button
, jewels_callback
,
1630 (void*) bj
) == SYS_USB_CONNECTED
)
1636 /********************
1638 ********************/
1641 /********************
1643 ********************/
1644 bj
->score
+= jewels_initlevel(bj
);
1645 if (!jewels_movesavail(bj
)) {
1647 case GAME_TYPE_NORMAL
:
1650 case GAME_TYPE_PUZZLE
:
1652 rb
->splash(2*HZ
, "No more moves!");
1653 bj
->score
+= jewels_initlevel(bj
);
1654 } while(!jewels_movesavail(bj
));
1659 /**********************
1661 **********************/
1663 int no_movesavail
= false;
1666 /* refresh the board */
1667 jewels_drawboard(bj
);
1669 /* display the cursor */
1671 rb
->lcd_set_drawmode(DRMODE_COMPLEMENT
);
1672 rb
->lcd_fillrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1673 TILE_WIDTH
, TILE_HEIGHT
);
1674 rb
->lcd_set_drawmode(DRMODE_SOLID
);
1676 rb
->lcd_drawrect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1677 TILE_WIDTH
, TILE_HEIGHT
);
1679 rb
->lcd_update_rect(x
*TILE_WIDTH
, y
*TILE_HEIGHT
+YOFS
,
1680 TILE_WIDTH
, TILE_HEIGHT
);
1682 res
= jewels_showmenu(&bjmenu
[1], cmd
);
1691 playback_control(rb
);
1692 rb
->lcd_setfont(FONT_SYSFIXED
);
1698 rb
->splash(HZ
, "Saving game...");
1699 jewels_savegame(bj
);
1706 return BJ_QUIT_FROM_GAME
;
1713 /* handle game button presses */
1714 button
= rb
->button_get(true);
1716 case JEWELS_LEFT
: /* move cursor left */
1717 case (JEWELS_LEFT
|BUTTON_REPEAT
):
1720 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_LEFT
);
1722 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1724 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1729 case JEWELS_RIGHT
: /* move cursor right */
1730 case (JEWELS_RIGHT
|BUTTON_REPEAT
):
1733 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_RIGHT
);
1735 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1744 case JEWELS_DOWN
: /* move cursor down */
1745 case (JEWELS_DOWN
|BUTTON_REPEAT
):
1748 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_DOWN
);
1750 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1752 y
= (y
+1)%(BJ_HEIGHT
-1);
1759 case JEWELS_UP
: /* move cursor up */
1760 case (JEWELS_UP
|BUTTON_REPEAT
):
1763 bj
->score
+= jewels_swapjewels(bj
, x
, y
, SWAP_UP
);
1765 if (!jewels_movesavail(bj
)) no_movesavail
= true;
1767 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1774 #ifdef JEWELS_SCROLLWHEEL
1775 case JEWELS_PREV
: /* scroll backwards */
1776 case (JEWELS_PREV
|BUTTON_REPEAT
):
1780 y
= (y
+(BJ_HEIGHT
-1)-1)%(BJ_HEIGHT
-1);
1782 x
= (x
+BJ_WIDTH
-1)%BJ_WIDTH
;
1789 case JEWELS_NEXT
: /* scroll forwards */
1790 case (JEWELS_NEXT
|BUTTON_REPEAT
):
1793 if(x
== BJ_WIDTH
-1) {
1794 y
= (y
+1)%(BJ_HEIGHT
-1);
1804 case JEWELS_SELECT
: /* toggle selected */
1806 selected
= !selected
;
1812 case (JEWELS_SELECT
|BUTTON_REPEAT
): /* show menu */
1813 if(!inmenu
) inmenu
= true;
1816 #ifdef JEWELS_CANCEL
1817 #ifdef JEWELS_RC_CANCEL
1818 case JEWELS_RC_CANCEL
:
1820 case JEWELS_CANCEL
: /* end game */
1826 if(rb
->default_event_handler_ex(button
, jewels_callback
,
1827 (void*) bj
) == SYS_USB_CONNECTED
)
1832 if (no_movesavail
) {
1834 case GAME_TYPE_NORMAL
:
1837 case GAME_TYPE_PUZZLE
:
1839 rb
->splash(2*HZ
, "No more moves!");
1840 bj
->score
+= jewels_initlevel(bj
);
1841 } while(!jewels_movesavail(bj
));
1847 case GAME_TYPE_NORMAL
:
1848 if(bj
->score
>= LEVEL_PTS
) bj
->score
= jewels_nextlevel(bj
);
1851 case GAME_TYPE_PUZZLE
:
1852 if(jewels_puzzle_is_finished(bj
))
1853 bj
->score
+= jewels_nextlevel(bj
);
1859 /*****************************************************************************
1860 * plugin entry point.
1861 ******************************************************************************/
1862 enum plugin_status
plugin_start(struct plugin_api
* api
, void* parameter
) {
1863 struct game_context bj
;
1871 /* end of plugin init */
1873 /* load high scores */
1874 jewels_loadscores(&bj
);
1876 rb
->lcd_setfont(FONT_SYSFIXED
);
1878 rb
->lcd_set_backdrop(NULL
);
1883 switch(jewels_main(&bj
)){
1885 rb
->splash(HZ
*2, "No more moves!");
1886 /* fall through to BJ_END */
1890 if((position
= jewels_recordscore(&bj
))) {
1891 rb
->snprintf(str
, 19, "New high score #%d!", position
);
1892 rb
->splash(HZ
*2, str
);
1898 rb
->lcd_setfont(FONT_UI
);
1899 return PLUGIN_USB_CONNECTED
;
1903 rb
->splash(HZ
, "Saving high scores...");
1904 jewels_savescores(&bj
);
1909 case BJ_QUIT_FROM_GAME
:
1911 if((position
= jewels_recordscore(&bj
))) {
1912 rb
->snprintf(str
, 19, "New high score #%d!", position
);
1913 rb
->splash(HZ
*2, str
);
1917 rb
->splash(HZ
, "Saving high scores...");
1918 jewels_savescores(&bj
);
1928 rb
->lcd_setfont(FONT_UI
);
1932 #endif /* HAVE_LCD_BITMAP */