fixing red:
[Rockbox.git] / apps / plugins / jewels.c
blob0355bf62870f7cea7f1218e7907970d500a59016
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
22 #include "plugin.h"
23 #include "playback_control.h"
25 #ifdef HAVE_LCD_BITMAP
27 PLUGIN_HEADER
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
149 #else
150 #error No keymap defined!
151 #endif
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
158 #define YOFS 0
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
166 #define YOFS 0
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
173 #define YOFS 4
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
180 #define YOFS 0
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
187 #define YOFS 0
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
194 #define YOFS 6
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
201 #define YOFS 0
202 #define NUM_SCORES 9
204 /* use 10x10 tiles (Sansa c200) */
205 #elif (LCD_HEIGHT == 80) && (LCD_WIDTH == 132)
206 #define TILE_WIDTH 10
207 #define TILE_HEIGHT 10
208 #define YOFS 0
209 #define NUM_SCORES 8
211 /* use 10x8 tiles (iFP 700) */
212 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 128)
213 #define TILE_WIDTH 10
214 #define TILE_HEIGHT 8
215 #define YOFS 0
216 #define NUM_SCORES 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
222 #define YOFS 0
223 #define NUM_SCORES 8
225 #else
226 #error JEWELS: Unsupported LCD
227 #endif
229 /* save files */
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
235 #define BJ_END 3
236 #define BJ_USB 2
237 #define BJ_QUIT 1
238 #define BJ_LOSE 0
240 /* swap directions */
241 #define SWAP_UP 0
242 #define SWAP_RIGHT 1
243 #define SWAP_DOWN 2
244 #define SWAP_LEFT 3
246 /* play board dimension */
247 #define BJ_HEIGHT 9
248 #define BJ_WIDTH 8
250 /* next level threshold */
251 #define LEVEL_PTS 100
253 /* animation frame rate */
254 #define MAX_FPS 20
256 /* Game types */
257 enum game_type {
258 GAME_TYPE_NORMAL,
259 GAME_TYPE_PUZZLE
262 /* menu values */
263 #define FONT_HEIGHT 8
264 #define MAX_MITEMS 6
265 #define MENU_WIDTH 100
267 /* menu results */
268 enum menu_result {
269 MRES_NONE,
270 MRES_NEW,
271 MRES_PUZZLE,
272 MRES_SAVE,
273 MRES_RESUME,
274 MRES_SCORES,
275 MRES_HELP,
276 MRES_QUIT,
277 MRES_PLAYBACK,
278 MRES_EXIT
281 /* menu commands */
282 enum menu_cmd {
283 MCMD_NONE,
284 MCMD_NEXT,
285 MCMD_PREV,
286 MCMD_SELECT
289 /* menus */
290 struct jewels_menu {
291 char *title;
292 bool hasframe;
293 int selected;
294 int itemcnt;
295 struct jewels_menuitem {
296 char *text;
297 enum menu_result res;
298 } items[MAX_MITEMS];
299 } bjmenu[] = {
300 {"Jewels", false, 0, 6,
301 {{"New Game", MRES_NEW},
302 {"Puzzle", MRES_PUZZLE},
303 {"Resume Game", MRES_RESUME},
304 {"High Scores", MRES_SCORES},
305 {"Help", MRES_HELP},
306 {"Quit", MRES_QUIT}}},
307 {"Menu", true, 0, 5,
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)
327 #endif
329 /* the tile struct
330 * type is the jewel number 0-7
331 * falling if the jewel is falling
332 * delete marks the jewel for deletion
334 struct tile {
335 int type;
336 bool falling;
337 bool delete;
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 {
352 unsigned int score;
353 unsigned int segments;
354 unsigned int level;
355 unsigned int type;
356 unsigned int highscores[NUM_SCORES];
357 bool resume;
358 bool dirty;
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
368 struct puzzle_tile {
369 int x;
370 int y;
371 int tile_type;
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 */
424 if(bj->resume) {
425 bj->resume = false;
426 return;
429 /* reset scoring */
430 bj->level = 1;
431 bj->score = 0;
432 bj->segments = 0;
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));
445 #endif
448 /*****************************************************************************
449 * jewels_drawboard() redraws the entire game board.
450 ******************************************************************************/
451 static void jewels_drawboard(struct game_context* bj) {
452 int i, j;
453 int w, h;
454 unsigned int tempscore;
455 char *title = "Level";
456 char str[10];
458 tempscore = (bj->score>LEVEL_PTS ? LEVEL_PTS : bj->score);
460 /* clear screen */
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);
474 #else
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);
479 #endif
483 #if LCD_WIDTH > LCD_HEIGHT /* horizontal layout */
485 /* draw separator lines */
486 jewels_setcolors();
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));
494 #endif
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);
507 jewels_setcolors();
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);
513 #endif
515 /* print text */
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,
526 LCD_HEIGHT-8, str);
528 #elif LCD_WIDTH < LCD_HEIGHT /* vertical layout */
530 /* draw separator lines */
531 jewels_setcolors();
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));
539 #endif
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);
550 jewels_setcolors();
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);
555 #endif
557 /* print text */
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 */
568 jewels_setcolors();
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));
576 #endif
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);
589 jewels_setcolors();
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);
595 #endif
597 /* print text */
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);
606 #endif /* layout */
608 rb->lcd_update();
611 /*****************************************************************************
612 * jewels_showmenu() displays the chosen menu after performing the chosen
613 * menu command.
614 ******************************************************************************/
615 static enum menu_result jewels_showmenu(struct jewels_menu* menu,
616 enum menu_cmd cmd) {
617 int i;
618 int w, h;
619 int firstline;
620 int adj;
622 /* handle menu command */
623 switch(cmd) {
624 case MCMD_NEXT:
625 menu->selected = (menu->selected+1)%menu->itemcnt;
626 break;
628 case MCMD_PREV:
629 menu->selected = (menu->selected-1+menu->itemcnt)%menu->itemcnt;
630 break;
632 case MCMD_SELECT:
633 return menu->items[menu->selected].res;
635 default:
636 break;
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);
647 if(menu->hasframe) {
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);
673 return MRES_NONE;
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){
681 int i, j, k;
682 bool mark, done;
683 long lasttick, currenttick;
685 /* loop to make all the jewels fall */
686 while(true) {
687 /* mark falling jewels and add new jewels to hidden top row*/
688 mark = false;
689 done = true;
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) {
696 mark = true;
697 done = false;
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;
705 mark = false;
708 /* break if there are no falling jewels */
709 if(done) break;
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
721 if(i == 0 && YOFS) {
722 rb->lcd_set_foreground(rb->lcd_get_background());
723 } else {
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);
733 #else
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);
742 #endif
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);
752 #else
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);
759 #endif
764 rb->lcd_update_rect(0, 0, TILE_WIDTH*8, LCD_HEIGHT);
765 jewels_setcolors();
767 /* framerate limiting */
768 currenttick = *rb->current_tick;
769 if(currenttick-lasttick < HZ/MAX_FPS) {
770 rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick));
771 } else {
772 rb->yield();
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) {
805 int i, j;
806 int last, run;
807 unsigned int points = 0;
809 /* check for connected rows */
810 for(i=1; i<BJ_HEIGHT; i++) {
811 last = 0;
812 run = 1;
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) {
817 run++;
819 if(run == 3) {
820 bj->segments++;
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;
825 } else if(run > 3) {
826 points++;
827 bj->playboard[i][j].delete = true;
829 } else {
830 run = 1;
831 last = bj->playboard[i][j].type;
836 /* check for connected columns */
837 for(j=0; j<BJ_WIDTH; j++) {
838 last = 0;
839 run = 1;
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) {
844 run++;
846 if(run == 3) {
847 bj->segments++;
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;
852 } else if(run > 3) {
853 points++;
854 bj->playboard[i][j].delete = true;
856 } else {
857 run = 1;
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;
873 return points;
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;
882 unsigned int ret;
884 bj->segments = 0;
886 while((ret = jewels_clearjewels(bj)) > 0) {
887 points += ret;
888 jewels_drawboard(bj);
889 jewels_putjewels(bj);
892 return points;
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) {
901 int k;
902 int horzmod, vertmod;
903 int movelen = 0;
904 bool undo = false;
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) {
911 return 0;
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)) {
919 return 0;
922 /* set direction variables */
923 horzmod = 0;
924 vertmod = 0;
925 switch(direc) {
926 case SWAP_UP:
927 vertmod = -1;
928 movelen = TILE_HEIGHT;
929 break;
930 case SWAP_RIGHT:
931 horzmod = 1;
932 movelen = TILE_WIDTH;
933 break;
934 case SWAP_DOWN:
935 vertmod = 1;
936 movelen = TILE_HEIGHT;
937 break;
938 case SWAP_LEFT:
939 horzmod = -1;
940 movelen = TILE_WIDTH;
941 break;
944 while(true) {
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,
953 y*TILE_HEIGHT+YOFS,
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);
959 #else
960 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
961 rb->lcd_fillrect(x*TILE_WIDTH,
962 y*TILE_HEIGHT+YOFS,
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);
968 #endif
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);
986 #else
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);
1004 #endif
1006 rb->lcd_update_rect(0, 0, TILE_WIDTH*8, LCD_HEIGHT);
1007 jewels_setcolors();
1009 /* framerate limiting */
1010 currenttick = *rb->current_tick;
1011 if(currenttick-lasttick < HZ/MAX_FPS) {
1012 rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick));
1013 } else {
1014 rb->yield();
1016 lasttick = currenttick;
1019 /* swap jewels */
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;
1025 if(undo) break;
1027 points = jewels_runboard(bj);
1028 if(points == 0) {
1029 undo = true;
1030 } else {
1031 break;
1035 return points;
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) {
1043 int i, j;
1044 bool moves = false;
1045 int mytype;
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) {
1054 if(i > 1) {
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) {
1092 if(j > 0) {
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;}
1129 if(moves) break;
1132 return moves;
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) {
1139 unsigned int i, j;
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)
1148 &PUZZLE_TILE_DOWN))
1149 return 0;
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)
1155 &PUZZLE_TILE_UP))
1156 return 0;
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))
1162 return 0;
1164 if(mytype&PUZZLE_TILE_RIGHT) {
1165 if(j==BJ_WIDTH-1 ||
1166 bj->playboard[i][j+1].type<=MAX_NUM_JEWELS ||
1167 !((bj->playboard[i][j+1].type-MAX_NUM_JEWELS)
1168 &PUZZLE_TILE_LEFT))
1169 return 0;
1174 return 1;
1177 /*****************************************************************************
1178 * jewels_initlevel() initialises a level.
1179 ******************************************************************************/
1180 static unsigned int jewels_initlevel(struct game_context* bj) {
1181 unsigned int points = 0;
1183 switch(bj->type) {
1184 case GAME_TYPE_NORMAL:
1185 bj->num_jewels = MAX_NUM_JEWELS;
1186 break;
1188 case GAME_TYPE_PUZZLE:
1190 unsigned int i, j;
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
1206 +tile->tile_type;
1209 break;
1212 jewels_drawboard(bj);
1214 /* run the play board */
1215 jewels_putjewels(bj);
1216 points += jewels_runboard(bj);
1217 return points;
1220 /*****************************************************************************
1221 * jewels_nextlevel() advances the game to the next level and returns
1222 * points earned.
1223 ******************************************************************************/
1224 static unsigned int jewels_nextlevel(struct game_context* bj) {
1225 int i, x, y;
1226 unsigned int points = 0;
1228 switch(bj->type) {
1229 case GAME_TYPE_NORMAL:
1230 /* roll over score, change and display level */
1231 while(bj->score >= LEVEL_PTS) {
1232 bj->score -= LEVEL_PTS;
1233 bj->level++;
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++) {
1240 x = rb->rand()%8;
1241 y = rb->rand()%8;
1243 if(bj->playboard[y][x].type != 0) {
1244 points++;
1245 bj->playboard[y][x].type = 0;
1248 break;
1250 case GAME_TYPE_PUZZLE:
1251 bj->level++;
1252 if(bj->level>NUM_PUZZLE_LEVELS) {
1253 rb->splash(HZ*2, "You win!");
1254 bj->level = 1;
1255 } else {
1256 rb->splash(HZ*2, "Level %d", bj->level);
1258 break;
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) {
1269 int i;
1270 int position = 0;
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]) {
1280 if(!position) {
1281 position = i+1;
1282 bj->dirty = true;
1284 temp = bj->highscores[i];
1285 bj->highscores[i] = current;
1286 current = temp;
1290 return position;
1293 /*****************************************************************************
1294 * jewels_loadscores() loads the high scores saved file.
1295 ******************************************************************************/
1296 static void jewels_loadscores(struct game_context* bj) {
1297 int fd;
1299 bj->dirty = false;
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);
1306 if(fd < 0) return;
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));
1314 rb->close(fd);
1317 /*****************************************************************************
1318 * jewels_savescores() saves the high scores saved file.
1319 ******************************************************************************/
1320 static void jewels_savescores(struct game_context* bj) {
1321 int fd;
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));
1326 rb->close(fd);
1327 bj->dirty = false;
1330 /*****************************************************************************
1331 * jewels_loadgame() loads the saved game and returns load success.
1332 ******************************************************************************/
1333 static bool jewels_loadgame(struct game_context* bj) {
1334 int fd;
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 */
1342 while(true) {
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;
1347 bj->resume = true;
1348 loaded = true;
1349 break;
1352 rb->close(fd);
1354 /* delete saved file */
1355 rb->remove(SAVE_FILE);
1356 return loaded;
1359 /*****************************************************************************
1360 * jewels_savegame() saves the current game state.
1361 ******************************************************************************/
1362 static void jewels_savegame(struct game_context* bj) {
1363 int fd;
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));
1371 rb->close(fd);
1373 bj->resume = true;
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;
1382 if(bj->dirty) {
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) {
1392 int i, j;
1393 int w, h;
1394 int button;
1395 char str[18];
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 */
1403 int x=0, y=0;
1405 /* don't resume by default */
1406 bj->resume = false;
1408 /********************
1409 * menu *
1410 ********************/
1411 rb->lcd_clear_display();
1413 while(!startgame) {
1414 res = jewels_showmenu(&bjmenu[0], cmd);
1415 cmd = MCMD_NONE;
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);
1420 rb->lcd_update();
1422 switch(res) {
1423 case MRES_NEW:
1424 startgame = true;
1425 bj->type = GAME_TYPE_NORMAL;
1426 continue;
1428 case MRES_PUZZLE:
1429 startgame = true;
1430 bj->type = GAME_TYPE_PUZZLE;
1431 continue;
1433 case MRES_RESUME:
1434 if(!jewels_loadgame(bj)) {
1435 rb->splash(HZ*2, "Nothing to resume");
1436 rb->lcd_clear_display();
1437 } else {
1438 startgame = true;
1440 continue;
1442 case MRES_SCORES:
1443 rb->lcd_clear_display();
1445 /* room for a title? */
1446 j = 0;
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);
1451 j = 2;
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);
1460 rb->lcd_update();
1461 while(true) {
1462 button = rb->button_get(true);
1463 if(button != BUTTON_NONE && !(button&BUTTON_REL)) break;
1465 rb->lcd_clear_display();
1466 continue;
1468 case MRES_HELP:
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");
1576 #else
1577 #warning: missing help text.
1578 #endif
1579 rb->lcd_update();
1580 while(true) {
1581 button = rb->button_get(true);
1582 if(button != BUTTON_NONE && !(button&BUTTON_REL)) break;
1584 rb->lcd_clear_display();
1585 continue;
1587 case MRES_QUIT:
1588 return BJ_QUIT;
1590 default:
1591 break;
1594 /* handle menu button presses */
1595 button = rb->button_get(true);
1596 switch(button){
1597 #ifdef JEWELS_SCROLLWHEEL
1598 case JEWELS_PREV:
1599 case (JEWELS_PREV|BUTTON_REPEAT):
1600 #endif
1601 case JEWELS_UP:
1602 case (JEWELS_UP|BUTTON_REPEAT):
1603 cmd = MCMD_PREV;
1604 break;
1606 #ifdef JEWELS_SCROLLWHEEL
1607 case JEWELS_NEXT:
1608 case (JEWELS_NEXT|BUTTON_REPEAT):
1609 #endif
1610 case JEWELS_DOWN:
1611 case (JEWELS_DOWN|BUTTON_REPEAT):
1612 cmd = MCMD_NEXT;
1613 break;
1615 case JEWELS_SELECT:
1616 case JEWELS_RIGHT:
1617 cmd = MCMD_SELECT;
1618 break;
1620 #ifdef JEWELS_CANCEL
1621 #ifdef JEWELS_RC_CANCEL
1622 case JEWELS_RC_CANCEL:
1623 #endif
1624 case JEWELS_CANCEL:
1625 return BJ_QUIT;
1626 #endif
1628 default:
1629 if(rb->default_event_handler_ex(button, jewels_callback,
1630 (void*) bj) == SYS_USB_CONNECTED)
1631 return BJ_USB;
1632 break;
1636 /********************
1637 * init *
1638 ********************/
1639 jewels_init(bj);
1641 /********************
1642 * setup the board *
1643 ********************/
1644 bj->score += jewels_initlevel(bj);
1645 if (!jewels_movesavail(bj)) {
1646 switch(bj->type) {
1647 case GAME_TYPE_NORMAL:
1648 return BJ_LOSE;
1650 case GAME_TYPE_PUZZLE:
1651 do {
1652 rb->splash(2*HZ, "No more moves!");
1653 bj->score += jewels_initlevel(bj);
1654 } while(!jewels_movesavail(bj));
1655 break;
1659 /**********************
1660 * play *
1661 **********************/
1662 while(true) {
1663 int no_movesavail = false;
1665 if(!inmenu) {
1666 /* refresh the board */
1667 jewels_drawboard(bj);
1669 /* display the cursor */
1670 if(selected) {
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);
1675 } else {
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);
1681 } else {
1682 res = jewels_showmenu(&bjmenu[1], cmd);
1683 cmd = MCMD_NONE;
1684 switch(res) {
1685 case MRES_RESUME:
1686 inmenu = false;
1687 selected = false;
1688 continue;
1690 case MRES_PLAYBACK:
1691 playback_control(rb);
1692 rb->lcd_setfont(FONT_SYSFIXED);
1693 inmenu = false;
1694 selected = false;
1695 break;
1697 case MRES_SAVE:
1698 rb->splash(HZ, "Saving game...");
1699 jewels_savegame(bj);
1700 return BJ_END;
1702 case MRES_QUIT:
1703 return BJ_END;
1705 case MRES_EXIT:
1706 return BJ_QUIT_FROM_GAME;
1708 default:
1709 break;
1713 /* handle game button presses */
1714 button = rb->button_get(true);
1715 switch(button){
1716 case JEWELS_LEFT: /* move cursor left */
1717 case (JEWELS_LEFT|BUTTON_REPEAT):
1718 if(!inmenu) {
1719 if(selected) {
1720 bj->score += jewels_swapjewels(bj, x, y, SWAP_LEFT);
1721 selected = false;
1722 if (!jewels_movesavail(bj)) no_movesavail = true;
1723 } else {
1724 x = (x+BJ_WIDTH-1)%BJ_WIDTH;
1727 break;
1729 case JEWELS_RIGHT: /* move cursor right */
1730 case (JEWELS_RIGHT|BUTTON_REPEAT):
1731 if(!inmenu) {
1732 if(selected) {
1733 bj->score += jewels_swapjewels(bj, x, y, SWAP_RIGHT);
1734 selected = false;
1735 if (!jewels_movesavail(bj)) no_movesavail = true;
1736 } else {
1737 x = (x+1)%BJ_WIDTH;
1739 } else {
1740 cmd = MCMD_SELECT;
1742 break;
1744 case JEWELS_DOWN: /* move cursor down */
1745 case (JEWELS_DOWN|BUTTON_REPEAT):
1746 if(!inmenu) {
1747 if(selected) {
1748 bj->score += jewels_swapjewels(bj, x, y, SWAP_DOWN);
1749 selected = false;
1750 if (!jewels_movesavail(bj)) no_movesavail = true;
1751 } else {
1752 y = (y+1)%(BJ_HEIGHT-1);
1754 } else {
1755 cmd = MCMD_NEXT;
1757 break;
1759 case JEWELS_UP: /* move cursor up */
1760 case (JEWELS_UP|BUTTON_REPEAT):
1761 if(!inmenu) {
1762 if(selected) {
1763 bj->score += jewels_swapjewels(bj, x, y, SWAP_UP);
1764 selected = false;
1765 if (!jewels_movesavail(bj)) no_movesavail = true;
1766 } else {
1767 y = (y+(BJ_HEIGHT-1)-1)%(BJ_HEIGHT-1);
1769 } else {
1770 cmd = MCMD_PREV;
1772 break;
1774 #ifdef JEWELS_SCROLLWHEEL
1775 case JEWELS_PREV: /* scroll backwards */
1776 case (JEWELS_PREV|BUTTON_REPEAT):
1777 if(!inmenu) {
1778 if(!selected) {
1779 if(x == 0) {
1780 y = (y+(BJ_HEIGHT-1)-1)%(BJ_HEIGHT-1);
1782 x = (x+BJ_WIDTH-1)%BJ_WIDTH;
1784 } else {
1785 cmd = MCMD_PREV;
1787 break;
1789 case JEWELS_NEXT: /* scroll forwards */
1790 case (JEWELS_NEXT|BUTTON_REPEAT):
1791 if(!inmenu) {
1792 if(!selected) {
1793 if(x == BJ_WIDTH-1) {
1794 y = (y+1)%(BJ_HEIGHT-1);
1796 x = (x+1)%BJ_WIDTH;
1798 } else {
1799 cmd = MCMD_NEXT;
1801 break;
1802 #endif
1804 case JEWELS_SELECT: /* toggle selected */
1805 if(!inmenu) {
1806 selected = !selected;
1807 } else {
1808 cmd = MCMD_SELECT;
1810 break;
1812 case (JEWELS_SELECT|BUTTON_REPEAT): /* show menu */
1813 if(!inmenu) inmenu = true;
1814 break;
1816 #ifdef JEWELS_CANCEL
1817 #ifdef JEWELS_RC_CANCEL
1818 case JEWELS_RC_CANCEL:
1819 #endif
1820 case JEWELS_CANCEL: /* end game */
1821 return BJ_END;
1822 break;
1823 #endif
1825 default:
1826 if(rb->default_event_handler_ex(button, jewels_callback,
1827 (void*) bj) == SYS_USB_CONNECTED)
1828 return BJ_USB;
1829 break;
1832 if (no_movesavail) {
1833 switch(bj->type) {
1834 case GAME_TYPE_NORMAL:
1835 return BJ_LOSE;
1837 case GAME_TYPE_PUZZLE:
1838 do {
1839 rb->splash(2*HZ, "No more moves!");
1840 bj->score += jewels_initlevel(bj);
1841 } while(!jewels_movesavail(bj));
1842 break;
1846 switch(bj->type) {
1847 case GAME_TYPE_NORMAL:
1848 if(bj->score >= LEVEL_PTS) bj->score = jewels_nextlevel(bj);
1849 break;
1851 case GAME_TYPE_PUZZLE:
1852 if(jewels_puzzle_is_finished(bj))
1853 bj->score += jewels_nextlevel(bj);
1854 break;
1859 /*****************************************************************************
1860 * plugin entry point.
1861 ******************************************************************************/
1862 enum plugin_status plugin_start(struct plugin_api* api, void* parameter) {
1863 struct game_context bj;
1864 bool exit = false;
1865 int position;
1866 char str[19];
1868 /* plugin init */
1869 (void)parameter;
1870 rb = api;
1871 /* end of plugin init */
1873 /* load high scores */
1874 jewels_loadscores(&bj);
1876 rb->lcd_setfont(FONT_SYSFIXED);
1877 #if LCD_DEPTH > 1
1878 rb->lcd_set_backdrop(NULL);
1879 #endif
1880 jewels_setcolors();
1882 while(!exit) {
1883 switch(jewels_main(&bj)){
1884 case BJ_LOSE:
1885 rb->splash(HZ*2, "No more moves!");
1886 /* fall through to BJ_END */
1888 case BJ_END:
1889 if(!bj.resume) {
1890 if((position = jewels_recordscore(&bj))) {
1891 rb->snprintf(str, 19, "New high score #%d!", position);
1892 rb->splash(HZ*2, str);
1895 break;
1897 case BJ_USB:
1898 rb->lcd_setfont(FONT_UI);
1899 return PLUGIN_USB_CONNECTED;
1901 case BJ_QUIT:
1902 if(bj.dirty) {
1903 rb->splash(HZ, "Saving high scores...");
1904 jewels_savescores(&bj);
1906 exit = true;
1907 break;
1909 case BJ_QUIT_FROM_GAME:
1910 if(!bj.resume) {
1911 if((position = jewels_recordscore(&bj))) {
1912 rb->snprintf(str, 19, "New high score #%d!", position);
1913 rb->splash(HZ*2, str);
1916 if(bj.dirty) {
1917 rb->splash(HZ, "Saving high scores...");
1918 jewels_savescores(&bj);
1920 exit = true;
1921 break;
1923 default:
1924 break;
1928 rb->lcd_setfont(FONT_UI);
1929 return PLUGIN_OK;
1932 #endif /* HAVE_LCD_BITMAP */