Fix red in bootloaders
[maemo-rb.git] / apps / plugins / jewels.c
blobae69e0ade5d45376e8c893cfa13b8b9c84dad73e
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 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
24 #include "plugin.h"
25 #include "lib/playback_control.h"
27 #ifdef HAVE_LCD_BITMAP
29 PLUGIN_HEADER
31 /* button definitions */
32 #if CONFIG_KEYPAD == RECORDER_PAD
33 #define JEWELS_UP BUTTON_UP
34 #define JEWELS_DOWN BUTTON_DOWN
35 #define JEWELS_LEFT BUTTON_LEFT
36 #define JEWELS_RIGHT BUTTON_RIGHT
37 #define JEWELS_SELECT BUTTON_PLAY
38 #define JEWELS_CANCEL BUTTON_OFF
40 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
41 #define JEWELS_UP BUTTON_UP
42 #define JEWELS_DOWN BUTTON_DOWN
43 #define JEWELS_LEFT BUTTON_LEFT
44 #define JEWELS_RIGHT BUTTON_RIGHT
45 #define JEWELS_SELECT BUTTON_SELECT
46 #define JEWELS_CANCEL BUTTON_OFF
48 #elif CONFIG_KEYPAD == ONDIO_PAD
49 #define JEWELS_UP BUTTON_UP
50 #define JEWELS_DOWN BUTTON_DOWN
51 #define JEWELS_LEFT BUTTON_LEFT
52 #define JEWELS_RIGHT BUTTON_RIGHT
53 #define JEWELS_SELECT BUTTON_MENU
54 #define JEWELS_CANCEL BUTTON_OFF
56 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
57 #define JEWELS_UP BUTTON_UP
58 #define JEWELS_DOWN BUTTON_DOWN
59 #define JEWELS_LEFT BUTTON_LEFT
60 #define JEWELS_RIGHT BUTTON_RIGHT
61 #define JEWELS_SELECT BUTTON_SELECT
62 #define JEWELS_MENU BUTTON_MODE
63 #define JEWELS_CANCEL BUTTON_OFF
64 #define JEWELS_RC_CANCEL BUTTON_RC_STOP
66 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
67 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
68 #define JEWELS_SCROLLWHEEL
69 #define JEWELS_UP BUTTON_MENU
70 #define JEWELS_DOWN BUTTON_PLAY
71 #define JEWELS_LEFT BUTTON_LEFT
72 #define JEWELS_RIGHT BUTTON_RIGHT
73 #define JEWELS_PREV BUTTON_SCROLL_BACK
74 #define JEWELS_NEXT BUTTON_SCROLL_FWD
75 #define JEWELS_SELECT BUTTON_SELECT
77 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
78 #define JEWELS_UP BUTTON_UP
79 #define JEWELS_DOWN BUTTON_DOWN
80 #define JEWELS_LEFT BUTTON_LEFT
81 #define JEWELS_RIGHT BUTTON_RIGHT
82 #define JEWELS_SELECT BUTTON_SELECT
83 #define JEWELS_CANCEL BUTTON_PLAY
85 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
86 #define JEWELS_UP BUTTON_UP
87 #define JEWELS_DOWN BUTTON_DOWN
88 #define JEWELS_LEFT BUTTON_LEFT
89 #define JEWELS_RIGHT BUTTON_RIGHT
90 #define JEWELS_SELECT BUTTON_SELECT
91 #define JEWELS_CANCEL BUTTON_POWER
93 #elif CONFIG_KEYPAD == GIGABEAT_PAD
94 #define JEWELS_UP BUTTON_UP
95 #define JEWELS_DOWN BUTTON_DOWN
96 #define JEWELS_LEFT BUTTON_LEFT
97 #define JEWELS_RIGHT BUTTON_RIGHT
98 #define JEWELS_SELECT BUTTON_SELECT
99 #define JEWELS_CANCEL BUTTON_POWER
101 #elif CONFIG_KEYPAD == SANSA_E200_PAD
102 #define JEWELS_SCROLLWHEEL
103 #define JEWELS_UP BUTTON_UP
104 #define JEWELS_DOWN BUTTON_DOWN
105 #define JEWELS_LEFT BUTTON_LEFT
106 #define JEWELS_RIGHT BUTTON_RIGHT
107 #define JEWELS_PREV BUTTON_SCROLL_BACK
108 #define JEWELS_NEXT BUTTON_SCROLL_FWD
109 #define JEWELS_SELECT BUTTON_SELECT
110 #define JEWELS_CANCEL BUTTON_POWER
112 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
113 #define JEWELS_SCROLLWHEEL
114 #define JEWELS_UP BUTTON_UP
115 #define JEWELS_DOWN BUTTON_DOWN
116 #define JEWELS_LEFT BUTTON_LEFT
117 #define JEWELS_RIGHT BUTTON_RIGHT
118 #define JEWELS_PREV BUTTON_SCROLL_BACK
119 #define JEWELS_NEXT BUTTON_SCROLL_FWD
120 #define JEWELS_SELECT BUTTON_SELECT
121 #define JEWELS_CANCEL (BUTTON_HOME|BUTTON_REPEAT)
123 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
124 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
125 CONFIG_KEYPAD == SANSA_M200_PAD
126 #define JEWELS_UP BUTTON_UP
127 #define JEWELS_DOWN BUTTON_DOWN
128 #define JEWELS_LEFT BUTTON_LEFT
129 #define JEWELS_RIGHT BUTTON_RIGHT
130 #define JEWELS_SELECT BUTTON_SELECT
131 #define JEWELS_CANCEL BUTTON_POWER
133 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
134 #define JEWELS_UP BUTTON_SCROLL_UP
135 #define JEWELS_DOWN BUTTON_SCROLL_DOWN
136 #define JEWELS_LEFT BUTTON_LEFT
137 #define JEWELS_RIGHT BUTTON_RIGHT
138 #define JEWELS_SELECT BUTTON_PLAY
139 #define JEWELS_CANCEL BUTTON_POWER
141 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
142 #define JEWELS_UP BUTTON_UP
143 #define JEWELS_DOWN BUTTON_DOWN
144 #define JEWELS_LEFT BUTTON_LEFT
145 #define JEWELS_RIGHT BUTTON_RIGHT
146 #define JEWELS_SELECT BUTTON_SELECT
147 #define JEWELS_MENU BUTTON_MENU
148 #define JEWELS_CANCEL BUTTON_BACK
150 #elif CONFIG_KEYPAD == MROBE100_PAD
151 #define JEWELS_UP BUTTON_UP
152 #define JEWELS_DOWN BUTTON_DOWN
153 #define JEWELS_LEFT BUTTON_LEFT
154 #define JEWELS_RIGHT BUTTON_RIGHT
155 #define JEWELS_SELECT BUTTON_SELECT
156 #define JEWELS_CANCEL BUTTON_POWER
158 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
159 #define JEWELS_UP BUTTON_RC_VOL_UP
160 #define JEWELS_DOWN BUTTON_RC_VOL_DOWN
161 #define JEWELS_LEFT BUTTON_RC_REW
162 #define JEWELS_RIGHT BUTTON_RC_FF
163 #define JEWELS_SELECT BUTTON_RC_PLAY
164 #define JEWELS_CANCEL BUTTON_RC_REC
166 #define JEWELS_RC_CANCEL BUTTON_REC
168 #elif CONFIG_KEYPAD == COWOND2_PAD
169 #define JEWELS_CANCEL BUTTON_POWER
171 #elif CONFIG_KEYPAD == IAUDIO67_PAD
172 #define JEWELS_UP BUTTON_STOP
173 #define JEWELS_DOWN BUTTON_PLAY
174 #define JEWELS_LEFT BUTTON_LEFT
175 #define JEWELS_RIGHT BUTTON_RIGHT
176 #define JEWELS_SELECT BUTTON_MENU
177 #define JEWELS_CANCEL BUTTON_POWER
179 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
180 #define JEWELS_UP BUTTON_UP
181 #define JEWELS_DOWN BUTTON_DOWN
182 #define JEWELS_LEFT BUTTON_LEFT
183 #define JEWELS_RIGHT BUTTON_RIGHT
184 #define JEWELS_SELECT BUTTON_SELECT
185 #define JEWELS_CANCEL BUTTON_BACK
187 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
188 #define JEWELS_UP BUTTON_UP
189 #define JEWELS_DOWN BUTTON_DOWN
190 #define JEWELS_LEFT BUTTON_LEFT
191 #define JEWELS_RIGHT BUTTON_RIGHT
192 #define JEWELS_SELECT BUTTON_SELECT
193 #define JEWELS_CANCEL BUTTON_POWER
195 #elif CONFIG_KEYPAD == ONDAVX747_PAD || CONFIG_KEYPAD == MROBE500_PAD
196 #define JEWELS_CANCEL BUTTON_POWER
198 #else
199 #error No keymap defined!
200 #endif
202 #ifdef HAVE_TOUCHSCREEN
203 #ifndef JEWELS_UP
204 #define JEWELS_UP BUTTON_TOPMIDDLE
205 #endif
206 #ifndef JEWELS_DOWN
207 #define JEWELS_DOWN BUTTON_BOTTOMMIDDLE
208 #endif
209 #ifndef JEWELS_LEFT
210 #define JEWELS_LEFT BUTTON_MIDLEFT
211 #endif
212 #ifndef JEWELS_RIGHT
213 #define JEWELS_RIGHT BUTTON_MIDRIGHT
214 #endif
215 #ifndef JEWELS_SELECT
216 #define JEWELS_SELECT BUTTON_CENTER
217 #endif
218 #ifndef JEWELS_CANCEL
219 #define JEWELS_CANCEL BUTTON_TOPLEFT
220 #endif
221 #endif
223 /* use 30x30 tiles (iPod Video, Gigabeat, Onda VX747) */
224 #if (LCD_HEIGHT == 240) && (LCD_WIDTH == 320) || \
225 ((LCD_HEIGHT == 320) && (LCD_WIDTH == 240)) || \
226 ((LCD_HEIGHT == 400) && (LCD_WIDTH == 240))
227 #define TILE_WIDTH 30
228 #define TILE_HEIGHT 30
229 #define YOFS 0
230 #define NUM_SCORES 10
232 /* use 22x22 tiles (H300, iPod Color) */
233 #elif ((LCD_HEIGHT == 176) && (LCD_WIDTH == 220)) || \
234 ((LCD_HEIGHT == 220) && (LCD_WIDTH == 176))
235 #define TILE_WIDTH 22
236 #define TILE_HEIGHT 22
237 #define YOFS 0
238 #define NUM_SCORES 10
240 /* use 16x16 tiles (iPod Nano) */
241 #elif (LCD_HEIGHT == 132) && (LCD_WIDTH == 176)
242 #define TILE_WIDTH 16
243 #define TILE_HEIGHT 16
244 #define YOFS 4
245 #define NUM_SCORES 10
247 /* use 16x16 tiles (H100, iAudio X5, iPod 3G, iPod 4G grayscale) */
248 #elif (LCD_HEIGHT == 128) && (LCD_WIDTH == 160)
249 #define TILE_WIDTH 16
250 #define TILE_HEIGHT 16
251 #define YOFS 0
252 #define NUM_SCORES 10
254 /* use 14x14 tiles (H10 5/6 GB) */
255 #elif (LCD_HEIGHT == 128) && (LCD_WIDTH == 128)
256 #define TILE_WIDTH 14
257 #define TILE_HEIGHT 14
258 #define YOFS 0
259 #define NUM_SCORES 10
261 /* use 13x13 tiles (iPod Mini) */
262 #elif (LCD_HEIGHT == 110) && (LCD_WIDTH == 138)
263 #define TILE_WIDTH 13
264 #define TILE_HEIGHT 13
265 #define YOFS 6
266 #define NUM_SCORES 10
268 /* use 12x12 tiles (iAudio M3) */
269 #elif (LCD_HEIGHT == 96) && (LCD_WIDTH == 128)
270 #define TILE_WIDTH 12
271 #define TILE_HEIGHT 12
272 #define YOFS 0
273 #define NUM_SCORES 9
275 /* use 10x10 tiles (Sansa c200) */
276 #elif (LCD_HEIGHT == 80) && (LCD_WIDTH == 132)
277 #define TILE_WIDTH 10
278 #define TILE_HEIGHT 10
279 #define YOFS 0
280 #define NUM_SCORES 8
282 /* use 10x8 tiles (iFP 700) */
283 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 128)
284 #define TILE_WIDTH 10
285 #define TILE_HEIGHT 8
286 #define YOFS 0
287 #define NUM_SCORES 8
289 /* use 10x8 tiles (Recorder, Ondio) */
290 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 112)
291 #define TILE_WIDTH 10
292 #define TILE_HEIGHT 8
293 #define YOFS 0
294 #define NUM_SCORES 8
296 #else
297 #error JEWELS: Unsupported LCD
298 #endif
300 /* save files */
301 #define SCORE_FILE PLUGIN_GAMES_DIR "/jewels.score"
302 #define SAVE_FILE PLUGIN_GAMES_DIR "/jewels.save"
304 /* final game return status */
305 #define BJ_QUIT_FROM_GAME 4
306 #define BJ_END 3
307 #define BJ_USB 2
308 #define BJ_QUIT 1
309 #define BJ_LOSE 0
311 /* swap directions */
312 #define SWAP_UP 0
313 #define SWAP_RIGHT 1
314 #define SWAP_DOWN 2
315 #define SWAP_LEFT 3
317 /* play board dimension */
318 #define BJ_HEIGHT 9
319 #define BJ_WIDTH 8
321 /* next level threshold */
322 #define LEVEL_PTS 100
324 /* animation frame rate */
325 #define MAX_FPS 20
327 /* Game types */
328 enum game_type {
329 GAME_TYPE_NORMAL,
330 GAME_TYPE_PUZZLE
333 /* external bitmaps */
334 extern const fb_data jewels[];
336 /* tile background colors */
337 #ifdef HAVE_LCD_COLOR
338 static const unsigned jewels_bkgd[2] = {
339 LCD_RGBPACK(104, 63, 63),
340 LCD_RGBPACK(83, 44, 44)
342 #endif
344 /* the tile struct
345 * type is the jewel number 0-7
346 * falling if the jewel is falling
347 * delete marks the jewel for deletion
349 struct tile {
350 int type;
351 bool falling;
352 bool delete;
355 /* the game context struct
356 * score is the current level score
357 * segments is the number of cleared segments in the current run
358 * level is the current level
359 * type is the game type (normal or puzzle)
360 * highscores is the list of high scores
361 * resume denotes whether to resume the currently loaded game
362 * dirty denotes whether the high scores are out of sync with the saved file
363 * playboard is the game playing board (first row is hidden)
364 * num_jewels is the number of different jewels to use
366 struct game_context {
367 unsigned int score;
368 unsigned int segments;
369 unsigned int level;
370 unsigned int type;
371 unsigned int highscores[NUM_SCORES];
372 bool resume;
373 bool dirty;
374 struct tile playboard[BJ_HEIGHT][BJ_WIDTH];
375 unsigned int num_jewels;
378 #define MAX_NUM_JEWELS 7
380 #define MAX_PUZZLE_TILES 4
381 #define NUM_PUZZLE_LEVELS 10
383 struct puzzle_tile {
384 int x;
385 int y;
386 int tile_type;
389 struct puzzle_level {
390 unsigned int num_jewels;
391 unsigned int num_tiles;
392 struct puzzle_tile tiles[MAX_PUZZLE_TILES];
395 #define PUZZLE_TILE_UP 1
396 #define PUZZLE_TILE_DOWN 2
397 #define PUZZLE_TILE_LEFT 4
398 #define PUZZLE_TILE_RIGHT 8
400 struct puzzle_level puzzle_levels[NUM_PUZZLE_LEVELS] = {
401 { 5, 2, { {3, 3, PUZZLE_TILE_RIGHT},
402 {4, 2, PUZZLE_TILE_LEFT} } },
403 { 5, 2, { {3, 2, PUZZLE_TILE_DOWN},
404 {3, 4, PUZZLE_TILE_UP} } },
405 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN},
406 {3, 4, PUZZLE_TILE_UP|PUZZLE_TILE_DOWN},
407 {3, 6, PUZZLE_TILE_UP} } },
408 { 6, 3, { {3, 2, PUZZLE_TILE_RIGHT},
409 {4, 3, PUZZLE_TILE_LEFT|PUZZLE_TILE_RIGHT},
410 {5, 4, PUZZLE_TILE_LEFT} } },
411 { 6, 2, { {3, 4, PUZZLE_TILE_RIGHT},
412 {4, 2, PUZZLE_TILE_LEFT} } },
413 { 6, 2, { {3, 2, PUZZLE_TILE_DOWN},
414 {4, 4, PUZZLE_TILE_UP} } },
415 { 7, 4, { {3, 2, PUZZLE_TILE_RIGHT|PUZZLE_TILE_DOWN},
416 {4, 3, PUZZLE_TILE_LEFT|PUZZLE_TILE_DOWN},
417 {3, 4, PUZZLE_TILE_RIGHT|PUZZLE_TILE_UP},
418 {4, 4, PUZZLE_TILE_LEFT|PUZZLE_TILE_UP} } },
419 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN},
420 {4, 4, PUZZLE_TILE_UP|PUZZLE_TILE_DOWN},
421 {3, 6, PUZZLE_TILE_UP} } },
422 { 7, 3, { {2, 2, PUZZLE_TILE_RIGHT},
423 {4, 1, PUZZLE_TILE_LEFT|PUZZLE_TILE_RIGHT},
424 {5, 4, PUZZLE_TILE_LEFT} } },
425 { 7, 4, { {3, 0, PUZZLE_TILE_RIGHT|PUZZLE_TILE_DOWN},
426 {5, 0, PUZZLE_TILE_LEFT|PUZZLE_TILE_DOWN},
427 {2, 7, PUZZLE_TILE_RIGHT|PUZZLE_TILE_UP},
428 {4, 7, PUZZLE_TILE_LEFT|PUZZLE_TILE_UP} } },
431 /*****************************************************************************
432 * jewels_init() initializes jewels data structures.
433 ******************************************************************************/
434 static void jewels_init(struct game_context* bj) {
435 /* seed the rand generator */
436 rb->srand(*rb->current_tick);
438 /* check for resumed game */
439 if(bj->resume) {
440 bj->resume = false;
441 return;
444 /* reset scoring */
445 bj->level = 1;
446 bj->score = 0;
447 bj->segments = 0;
449 /* clear playing board */
450 rb->memset(bj->playboard, 0, sizeof(bj->playboard));
453 /*****************************************************************************
454 * jewels_setcolors() set the foreground and background colors.
455 ******************************************************************************/
456 static inline void jewels_setcolors(void) {
457 #ifdef HAVE_LCD_COLOR
458 rb->lcd_set_background(LCD_RGBPACK(49, 26, 26));
459 rb->lcd_set_foreground(LCD_RGBPACK(210, 181, 181));
460 #endif
463 /*****************************************************************************
464 * jewels_drawboard() redraws the entire game board.
465 ******************************************************************************/
466 static void jewels_drawboard(struct game_context* bj) {
467 int i, j;
468 int w, h;
469 unsigned int tempscore;
470 char *title = "Level";
471 char str[10];
473 tempscore = (bj->score>LEVEL_PTS ? LEVEL_PTS : bj->score);
475 /* clear screen */
476 rb->lcd_clear_display();
478 /* dispay playing board */
479 for(i=0; i<BJ_HEIGHT-1; i++){
480 for(j=0; j<BJ_WIDTH; j++){
481 #ifdef HAVE_LCD_COLOR
482 rb->lcd_set_foreground(jewels_bkgd[(i+j)%2]);
483 rb->lcd_fillrect(j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
484 TILE_WIDTH, TILE_HEIGHT);
485 rb->lcd_bitmap_transparent_part(jewels,
486 0, TILE_HEIGHT*(bj->playboard[i+1][j].type),
487 TILE_WIDTH, j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
488 TILE_WIDTH, TILE_HEIGHT);
489 #else
490 rb->lcd_bitmap_part(jewels,
491 0, TILE_HEIGHT*(bj->playboard[i+1][j].type),
492 TILE_WIDTH, j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
493 TILE_WIDTH, TILE_HEIGHT);
494 #endif
498 #if LCD_WIDTH > LCD_HEIGHT /* horizontal layout */
500 /* draw separator lines */
501 jewels_setcolors();
502 rb->lcd_vline(BJ_WIDTH*TILE_WIDTH, 0, LCD_HEIGHT-1);
503 rb->lcd_hline(BJ_WIDTH*TILE_WIDTH, LCD_WIDTH-1, 18);
504 rb->lcd_hline(BJ_WIDTH*TILE_WIDTH, LCD_WIDTH-1, LCD_HEIGHT-10);
506 /* draw progress bar */
507 #ifdef HAVE_LCD_COLOR
508 rb->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
509 #endif
510 rb->lcd_fillrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
511 (LCD_HEIGHT-10)-(((LCD_HEIGHT-10)-18)*
512 tempscore/LEVEL_PTS),
513 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
514 ((LCD_HEIGHT-10)-18)*tempscore/LEVEL_PTS);
515 #ifdef HAVE_LCD_COLOR
516 rb->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
517 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4+1,
518 (LCD_HEIGHT-10)-(((LCD_HEIGHT-10)-18)*
519 tempscore/LEVEL_PTS)+1,
520 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-2,
521 ((LCD_HEIGHT-10)-18)*tempscore/LEVEL_PTS-1);
522 jewels_setcolors();
523 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
524 (LCD_HEIGHT-10)-(((LCD_HEIGHT-10)-18)*
525 tempscore/LEVEL_PTS),
526 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
527 ((LCD_HEIGHT-10)-18)*tempscore/LEVEL_PTS+1);
528 #endif
530 /* print text */
531 rb->lcd_getstringsize(title, &w, &h);
532 rb->lcd_putsxy(LCD_WIDTH-(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-w/2, 1, title);
534 rb->snprintf(str, 4, "%d", bj->level);
535 rb->lcd_getstringsize(str, &w, &h);
536 rb->lcd_putsxy(LCD_WIDTH-(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-w/2, 10, str);
538 rb->snprintf(str, 6, "%d", (bj->level-1)*LEVEL_PTS+bj->score);
539 rb->lcd_getstringsize(str, &w, &h);
540 rb->lcd_putsxy(LCD_WIDTH-(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-w/2,
541 LCD_HEIGHT-8, str);
543 #elif LCD_WIDTH < LCD_HEIGHT /* vertical layout */
545 /* draw separator lines */
546 jewels_setcolors();
547 rb->lcd_hline(0, LCD_WIDTH-1, 8*TILE_HEIGHT+YOFS);
548 rb->lcd_hline(0, LCD_WIDTH-1, LCD_HEIGHT-14);
549 rb->lcd_vline(LCD_WIDTH/2, LCD_HEIGHT-14, LCD_HEIGHT-1);
551 /* draw progress bar */
552 #ifdef HAVE_LCD_COLOR
553 rb->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
554 #endif
555 rb->lcd_fillrect(0, (8*TILE_HEIGHT+YOFS)
556 +(LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/4,
557 LCD_WIDTH*tempscore/LEVEL_PTS,
558 (LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/2);
559 #ifdef HAVE_LCD_COLOR
560 rb->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
561 rb->lcd_drawrect(1, (8*TILE_HEIGHT+YOFS)
562 +(LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/4+1,
563 LCD_WIDTH*tempscore/LEVEL_PTS-1,
564 (LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/2-2);
565 jewels_setcolors();
566 rb->lcd_drawrect(0, (8*TILE_HEIGHT+YOFS)
567 +(LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/4,
568 LCD_WIDTH*tempscore/LEVEL_PTS+1,
569 (LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/2);
570 #endif
572 /* print text */
573 rb->snprintf(str, 10, "%s %d", title, bj->level);
574 rb->lcd_putsxy(1, LCD_HEIGHT-10, str);
576 rb->snprintf(str, 6, "%d", (bj->level-1)*LEVEL_PTS+bj->score);
577 rb->lcd_getstringsize(str, &w, &h);
578 rb->lcd_putsxy((LCD_WIDTH-2)-w, LCD_HEIGHT-10, str);
580 #else /* square layout */
582 /* draw separator lines */
583 jewels_setcolors();
584 rb->lcd_hline(0, LCD_WIDTH-1, 8*TILE_HEIGHT+YOFS);
585 rb->lcd_vline(BJ_WIDTH*TILE_WIDTH, 0, 8*TILE_HEIGHT+YOFS);
586 rb->lcd_vline(LCD_WIDTH/2, 8*TILE_HEIGHT+YOFS, LCD_HEIGHT-1);
588 /* draw progress bar */
589 #ifdef HAVE_LCD_COLOR
590 rb->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
591 #endif
592 rb->lcd_fillrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
593 (8*TILE_HEIGHT+YOFS)-(8*TILE_HEIGHT+YOFS)
594 *tempscore/LEVEL_PTS,
595 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
596 (8*TILE_HEIGHT+YOFS)*tempscore/LEVEL_PTS);
597 #ifdef HAVE_LCD_COLOR
598 rb->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
599 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4+1,
600 (8*TILE_HEIGHT+YOFS)-(8*TILE_HEIGHT+YOFS)
601 *tempscore/LEVEL_PTS+1,
602 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-2,
603 (8*TILE_HEIGHT+YOFS)*tempscore/LEVEL_PTS-1);
604 jewels_setcolors();
605 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
606 (8*TILE_HEIGHT+YOFS)-(8*TILE_HEIGHT+YOFS)
607 *tempscore/LEVEL_PTS,
608 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
609 (8*TILE_HEIGHT+YOFS)*tempscore/LEVEL_PTS+1);
610 #endif
612 /* print text */
613 rb->snprintf(str, 10, "%s %d", title, bj->level);
614 rb->lcd_putsxy(1, LCD_HEIGHT-(LCD_HEIGHT-(8*TILE_HEIGHT+YOFS))/2-3, str);
616 rb->snprintf(str, 6, "%d", (bj->level-1)*LEVEL_PTS+bj->score);
617 rb->lcd_getstringsize(str, &w, &h);
618 rb->lcd_putsxy((LCD_WIDTH-2)-w,
619 LCD_HEIGHT-(LCD_HEIGHT-(8*TILE_HEIGHT+YOFS))/2-3, str);
621 #endif /* layout */
623 rb->lcd_update();
626 /*****************************************************************************
627 * jewels_putjewels() makes the jewels fall to fill empty spots and adds
628 * new random jewels at the empty spots at the top of each row.
629 ******************************************************************************/
630 static void jewels_putjewels(struct game_context* bj){
631 int i, j, k;
632 bool mark, done;
633 long lasttick, currenttick;
635 /* loop to make all the jewels fall */
636 while(true) {
637 /* mark falling jewels and add new jewels to hidden top row*/
638 mark = false;
639 done = true;
640 for(j=0; j<BJ_WIDTH; j++) {
641 if(bj->playboard[1][j].type == 0) {
642 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
644 for(i=BJ_HEIGHT-2; i>=0; i--) {
645 if(!mark && bj->playboard[i+1][j].type == 0) {
646 mark = true;
647 done = false;
649 if(mark) bj->playboard[i][j].falling = true;
651 /*if(bj->playboard[1][j].falling) {
652 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
653 bj->playboard[0][j].falling = true;
655 mark = false;
658 /* break if there are no falling jewels */
659 if(done) break;
661 /* animate falling jewels */
662 lasttick = *rb->current_tick;
664 for(k=1; k<=8; k++) {
665 for(i=BJ_HEIGHT-2; i>=0; i--) {
666 for(j=0; j<BJ_WIDTH; j++) {
667 if(bj->playboard[i][j].falling &&
668 bj->playboard[i][j].type != 0) {
669 /* clear old position */
670 #ifdef HAVE_LCD_COLOR
671 if(i == 0 && YOFS) {
672 rb->lcd_set_foreground(rb->lcd_get_background());
673 } else {
674 rb->lcd_set_foreground(jewels_bkgd[(i-1+j)%2]);
676 rb->lcd_fillrect(j*TILE_WIDTH, (i-1)*TILE_HEIGHT+YOFS,
677 TILE_WIDTH, TILE_HEIGHT);
678 if(bj->playboard[i+1][j].type == 0) {
679 rb->lcd_set_foreground(jewels_bkgd[(i+j)%2]);
680 rb->lcd_fillrect(j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
681 TILE_WIDTH, TILE_HEIGHT);
683 #else
684 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
685 rb->lcd_fillrect(j*TILE_WIDTH, (i-1)*TILE_HEIGHT+YOFS,
686 TILE_WIDTH, TILE_HEIGHT);
687 if(bj->playboard[i+1][j].type == 0) {
688 rb->lcd_fillrect(j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
689 TILE_WIDTH, TILE_HEIGHT);
691 rb->lcd_set_drawmode(DRMODE_SOLID);
692 #endif
694 /* draw new position */
695 #ifdef HAVE_LCD_COLOR
696 rb->lcd_bitmap_transparent_part(jewels, 0,
697 TILE_HEIGHT*(bj->playboard[i][j].type),
698 TILE_WIDTH, j*TILE_WIDTH,
699 (i-1)*TILE_HEIGHT+YOFS+
700 ((((TILE_HEIGHT<<10)*k)/8)>>10),
701 TILE_WIDTH, TILE_HEIGHT);
702 #else
703 rb->lcd_bitmap_part(jewels, 0,
704 TILE_HEIGHT*(bj->playboard[i][j].type),
705 TILE_WIDTH, j*TILE_WIDTH,
706 (i-1)*TILE_HEIGHT+YOFS+
707 ((((TILE_HEIGHT<<10)*k)/8)>>10),
708 TILE_WIDTH, TILE_HEIGHT);
709 #endif
714 rb->lcd_update_rect(0, 0, TILE_WIDTH*8, LCD_HEIGHT);
715 jewels_setcolors();
717 /* framerate limiting */
718 currenttick = *rb->current_tick;
719 if(currenttick-lasttick < HZ/MAX_FPS) {
720 rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick));
721 } else {
722 rb->yield();
724 lasttick = currenttick;
727 /* shift jewels down */
728 for(j=0; j<BJ_WIDTH; j++) {
729 for(i=BJ_HEIGHT-1; i>=1; i--) {
730 if(bj->playboard[i-1][j].falling) {
731 bj->playboard[i][j].type = bj->playboard[i-1][j].type;
736 /* clear out top row */
737 for(j=0; j<BJ_WIDTH; j++) {
738 bj->playboard[0][j].type = 0;
741 /* mark everything not falling */
742 for(i=0; i<BJ_HEIGHT; i++) {
743 for(j=0; j<BJ_WIDTH; j++) {
744 bj->playboard[i][j].falling = false;
750 /*****************************************************************************
751 * jewels_clearjewels() finds all the connected rows and columns and
752 * calculates and returns the points earned.
753 ******************************************************************************/
754 static unsigned int jewels_clearjewels(struct game_context* bj) {
755 int i, j;
756 int last, run;
757 unsigned int points = 0;
759 /* check for connected rows */
760 for(i=1; i<BJ_HEIGHT; i++) {
761 last = 0;
762 run = 1;
763 for(j=0; j<BJ_WIDTH; j++) {
764 if(bj->playboard[i][j].type == last &&
765 bj->playboard[i][j].type != 0 &&
766 bj->playboard[i][j].type <= MAX_NUM_JEWELS) {
767 run++;
769 if(run == 3) {
770 bj->segments++;
771 points += bj->segments;
772 bj->playboard[i][j].delete = true;
773 bj->playboard[i][j-1].delete = true;
774 bj->playboard[i][j-2].delete = true;
775 } else if(run > 3) {
776 points++;
777 bj->playboard[i][j].delete = true;
779 } else {
780 run = 1;
781 last = bj->playboard[i][j].type;
786 /* check for connected columns */
787 for(j=0; j<BJ_WIDTH; j++) {
788 last = 0;
789 run = 1;
790 for(i=1; i<BJ_HEIGHT; i++) {
791 if(bj->playboard[i][j].type != 0 &&
792 bj->playboard[i][j].type == last &&
793 bj->playboard[i][j].type <= MAX_NUM_JEWELS) {
794 run++;
796 if(run == 3) {
797 bj->segments++;
798 points += bj->segments;
799 bj->playboard[i][j].delete = true;
800 bj->playboard[i-1][j].delete = true;
801 bj->playboard[i-2][j].delete = true;
802 } else if(run > 3) {
803 points++;
804 bj->playboard[i][j].delete = true;
806 } else {
807 run = 1;
808 last = bj->playboard[i][j].type;
813 /* clear deleted jewels */
814 for(i=1; i<BJ_HEIGHT; i++) {
815 for(j=0; j<BJ_WIDTH; j++) {
816 if(bj->playboard[i][j].delete) {
817 bj->playboard[i][j].delete = false;
818 bj->playboard[i][j].type = 0;
823 return points;
826 /*****************************************************************************
827 * jewels_runboard() runs the board until it settles in a fixed state and
828 * returns points earned.
829 ******************************************************************************/
830 static unsigned int jewels_runboard(struct game_context* bj) {
831 unsigned int points = 0;
832 unsigned int ret;
834 bj->segments = 0;
836 while((ret = jewels_clearjewels(bj)) > 0) {
837 points += ret;
838 jewels_drawboard(bj);
839 jewels_putjewels(bj);
842 return points;
845 /*****************************************************************************
846 * jewels_swapjewels() swaps two jewels as long as it results in points and
847 * returns points earned.
848 ******************************************************************************/
849 static unsigned int jewels_swapjewels(struct game_context* bj,
850 int x, int y, int direc) {
851 int k;
852 int horzmod, vertmod;
853 int movelen = 0;
854 bool undo = false;
855 unsigned int points = 0;
856 long lasttick, currenttick;
858 /* check for invalid parameters */
859 if(x < 0 || x >= BJ_WIDTH || y < 0 || y >= BJ_HEIGHT-1 ||
860 direc < SWAP_UP || direc > SWAP_LEFT) {
861 return 0;
864 /* check for invalid directions */
865 if((x == 0 && direc == SWAP_LEFT) ||
866 (x == BJ_WIDTH-1 && direc == SWAP_RIGHT) ||
867 (y == 0 && direc == SWAP_UP) ||
868 (y == BJ_HEIGHT-2 && direc == SWAP_DOWN)) {
869 return 0;
872 /* set direction variables */
873 horzmod = 0;
874 vertmod = 0;
875 switch(direc) {
876 case SWAP_UP:
877 vertmod = -1;
878 movelen = TILE_HEIGHT;
879 break;
880 case SWAP_RIGHT:
881 horzmod = 1;
882 movelen = TILE_WIDTH;
883 break;
884 case SWAP_DOWN:
885 vertmod = 1;
886 movelen = TILE_HEIGHT;
887 break;
888 case SWAP_LEFT:
889 horzmod = -1;
890 movelen = TILE_WIDTH;
891 break;
894 while(true) {
895 lasttick = *rb->current_tick;
897 /* animate swapping jewels */
898 for(k=0; k<=8; k++) {
899 /* clear old position */
900 #ifdef HAVE_LCD_COLOR
901 rb->lcd_set_foreground(jewels_bkgd[(x+y)%2]);
902 rb->lcd_fillrect(x*TILE_WIDTH,
903 y*TILE_HEIGHT+YOFS,
904 TILE_WIDTH, TILE_HEIGHT);
905 rb->lcd_set_foreground(jewels_bkgd[(x+horzmod+y+vertmod)%2]);
906 rb->lcd_fillrect((x+horzmod)*TILE_WIDTH,
907 (y+vertmod)*TILE_HEIGHT+YOFS,
908 TILE_WIDTH, TILE_HEIGHT);
909 #else
910 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
911 rb->lcd_fillrect(x*TILE_WIDTH,
912 y*TILE_HEIGHT+YOFS,
913 TILE_WIDTH, TILE_HEIGHT);
914 rb->lcd_fillrect((x+horzmod)*TILE_WIDTH,
915 (y+vertmod)*TILE_HEIGHT+YOFS,
916 TILE_WIDTH, TILE_HEIGHT);
917 rb->lcd_set_drawmode(DRMODE_SOLID);
918 #endif
919 /* draw new position */
920 #ifdef HAVE_LCD_COLOR
921 rb->lcd_bitmap_transparent_part(jewels,
922 0, TILE_HEIGHT*(bj->playboard
923 [y+1+vertmod][x+horzmod].type), TILE_WIDTH,
924 (x+horzmod)*TILE_WIDTH-horzmod*
925 ((((movelen<<10)*k)/8)>>10),
926 (y+vertmod)*TILE_HEIGHT-vertmod*
927 ((((movelen<<10)*k)/8)>>10)+YOFS,
928 TILE_WIDTH, TILE_HEIGHT);
929 rb->lcd_bitmap_transparent_part(jewels,
930 0, TILE_HEIGHT*(bj->playboard[y+1][x].type),
931 TILE_WIDTH, x*TILE_WIDTH+horzmod*
932 ((((movelen<<10)*k)/8)>>10),
933 y*TILE_HEIGHT+vertmod*
934 ((((movelen<<10)*k)/8)>>10)+YOFS,
935 TILE_WIDTH, TILE_HEIGHT);
936 #else
937 rb->lcd_bitmap_part(jewels,
938 0, TILE_HEIGHT*(bj->playboard
939 [y+1+vertmod][x+horzmod].type), TILE_WIDTH,
940 (x+horzmod)*TILE_WIDTH-horzmod*
941 ((((movelen<<10)*k)/8)>>10),
942 (y+vertmod)*TILE_HEIGHT-vertmod*
943 ((((movelen<<10)*k)/8)>>10)+YOFS,
944 TILE_WIDTH, TILE_HEIGHT);
945 rb->lcd_set_drawmode(DRMODE_FG);
946 rb->lcd_bitmap_part(jewels,
947 0, TILE_HEIGHT*(bj->playboard[y+1][x].type),
948 TILE_WIDTH, x*TILE_WIDTH+horzmod*
949 ((((movelen<<10)*k)/8)>>10),
950 y*TILE_HEIGHT+vertmod*
951 ((((movelen<<10)*k)/8)>>10)+YOFS,
952 TILE_WIDTH, TILE_HEIGHT);
953 rb->lcd_set_drawmode(DRMODE_SOLID);
954 #endif
956 rb->lcd_update_rect(0, 0, TILE_WIDTH*8, LCD_HEIGHT);
957 jewels_setcolors();
959 /* framerate limiting */
960 currenttick = *rb->current_tick;
961 if(currenttick-lasttick < HZ/MAX_FPS) {
962 rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick));
963 } else {
964 rb->yield();
966 lasttick = currenttick;
969 /* swap jewels */
970 int temp = bj->playboard[y+1][x].type;
971 bj->playboard[y+1][x].type =
972 bj->playboard[y+1+vertmod][x+horzmod].type;
973 bj->playboard[y+1+vertmod][x+horzmod].type = temp;
975 if(undo) break;
977 points = jewels_runboard(bj);
978 if(points == 0) {
979 undo = true;
980 } else {
981 break;
985 return points;
988 /*****************************************************************************
989 * jewels_movesavail() uses pattern matching to see if there are any
990 * available move left.
991 ******************************************************************************/
992 static bool jewels_movesavail(struct game_context* bj) {
993 int i, j;
994 bool moves = false;
995 int mytype;
997 for(i=1; i<BJ_HEIGHT; i++) {
998 for(j=0; j<BJ_WIDTH; j++) {
999 mytype = bj->playboard[i][j].type;
1000 if(mytype == 0 || mytype > MAX_NUM_JEWELS) continue;
1002 /* check horizontal patterns */
1003 if(j <= BJ_WIDTH-3) {
1004 if(i > 1) {
1005 if(bj->playboard[i-1][j+1].type == mytype) {
1006 if(bj->playboard[i-1][j+2].type == mytype)
1007 {moves = true; break;}
1008 if(bj->playboard[i][j+2].type == mytype)
1009 {moves = true; break;}
1011 if(bj->playboard[i][j+1].type == mytype) {
1012 if(bj->playboard[i-1][j+2].type == mytype)
1013 {moves = true; break;}
1017 if(j <= BJ_WIDTH-4) {
1018 if(bj->playboard[i][j+3].type == mytype) {
1019 if(bj->playboard[i][j+1].type == mytype)
1020 {moves = true; break;}
1021 if(bj->playboard[i][j+2].type == mytype)
1022 {moves = true; break;}
1026 if(i < BJ_HEIGHT-1) {
1027 if(bj->playboard[i][j+1].type == mytype) {
1028 if(bj->playboard[i+1][j+2].type == mytype)
1029 {moves = true; break;}
1031 if(bj->playboard[i+1][j+1].type == mytype) {
1032 if(bj->playboard[i][j+2].type == mytype)
1033 {moves = true; break;}
1034 if(bj->playboard[i+1][j+2].type == mytype)
1035 {moves = true; break;}
1040 /* check vertical patterns */
1041 if(i <= BJ_HEIGHT-3) {
1042 if(j > 0) {
1043 if(bj->playboard[i+1][j-1].type == mytype) {
1044 if(bj->playboard[i+2][j-1].type == mytype)
1045 {moves = true; break;}
1046 if(bj->playboard[i+2][j].type == mytype)
1047 {moves = true; break;}
1049 if(bj->playboard[i+1][j].type == mytype) {
1050 if(bj->playboard[i+2][j-1].type == mytype)
1051 {moves = true; break;}
1055 if(i <= BJ_HEIGHT-4) {
1056 if(bj->playboard[i+3][j].type == mytype) {
1057 if(bj->playboard[i+1][j].type == mytype)
1058 {moves = true; break;}
1059 if(bj->playboard[i+2][j].type == mytype)
1060 {moves = true; break;}
1064 if(j < BJ_WIDTH-1) {
1065 if(bj->playboard[i+1][j].type == mytype) {
1066 if(bj->playboard[i+2][j+1].type == mytype)
1067 {moves = true; break;}
1069 if(bj->playboard[i+1][j+1].type == mytype) {
1070 if(bj->playboard[i+2][j].type == mytype)
1071 {moves = true; break;}
1072 if (bj->playboard[i+2][j+1].type == mytype)
1073 {moves = true; break;}
1079 if(moves) break;
1082 return moves;
1085 /*****************************************************************************
1086 * jewels_puzzle_is_finished(bj) checks if the puzzle is finished.
1087 ******************************************************************************/
1088 static int jewels_puzzle_is_finished(struct game_context* bj) {
1089 unsigned int i, j;
1090 for(i=0; i<BJ_HEIGHT; i++) {
1091 for(j=0; j<BJ_WIDTH; j++) {
1092 int mytype = bj->playboard[i][j].type;
1093 if(mytype>MAX_NUM_JEWELS) {
1094 mytype -= MAX_NUM_JEWELS;
1095 if(mytype&PUZZLE_TILE_UP) {
1096 if(i==0 || bj->playboard[i-1][j].type<=MAX_NUM_JEWELS ||
1097 !((bj->playboard[i-1][j].type-MAX_NUM_JEWELS)
1098 &PUZZLE_TILE_DOWN))
1099 return 0;
1101 if(mytype&PUZZLE_TILE_DOWN) {
1102 if(i==BJ_HEIGHT-1 ||
1103 bj->playboard[i+1][j].type<=MAX_NUM_JEWELS ||
1104 !((bj->playboard[i+1][j].type-MAX_NUM_JEWELS)
1105 &PUZZLE_TILE_UP))
1106 return 0;
1108 if(mytype&PUZZLE_TILE_LEFT) {
1109 if(j==0 || bj->playboard[i][j-1].type<=MAX_NUM_JEWELS ||
1110 !((bj->playboard[i][j-1].type-MAX_NUM_JEWELS)
1111 &PUZZLE_TILE_RIGHT))
1112 return 0;
1114 if(mytype&PUZZLE_TILE_RIGHT) {
1115 if(j==BJ_WIDTH-1 ||
1116 bj->playboard[i][j+1].type<=MAX_NUM_JEWELS ||
1117 !((bj->playboard[i][j+1].type-MAX_NUM_JEWELS)
1118 &PUZZLE_TILE_LEFT))
1119 return 0;
1124 return 1;
1127 /*****************************************************************************
1128 * jewels_initlevel() initialises a level.
1129 ******************************************************************************/
1130 static unsigned int jewels_initlevel(struct game_context* bj) {
1131 unsigned int points = 0;
1133 switch(bj->type) {
1134 case GAME_TYPE_NORMAL:
1135 bj->num_jewels = MAX_NUM_JEWELS;
1136 break;
1138 case GAME_TYPE_PUZZLE:
1140 unsigned int i, j;
1141 struct puzzle_tile *tile;
1143 bj->num_jewels = puzzle_levels[bj->level-1].num_jewels;
1145 for(i=0; i<BJ_HEIGHT; i++) {
1146 for(j=0; j<BJ_WIDTH; j++) {
1147 bj->playboard[i][j].type = (rb->rand()%bj->num_jewels)+1;
1148 bj->playboard[i][j].falling = false;
1149 bj->playboard[i][j].delete = false;
1152 jewels_runboard(bj);
1153 tile = puzzle_levels[bj->level-1].tiles;
1154 for(i=0; i<puzzle_levels[bj->level-1].num_tiles; i++, tile++) {
1155 bj->playboard[tile->y+1][tile->x].type = MAX_NUM_JEWELS
1156 +tile->tile_type;
1159 break;
1162 jewels_drawboard(bj);
1164 /* run the play board */
1165 jewels_putjewels(bj);
1166 points += jewels_runboard(bj);
1167 return points;
1170 /*****************************************************************************
1171 * jewels_nextlevel() advances the game to the next level and returns
1172 * points earned.
1173 ******************************************************************************/
1174 static void jewels_nextlevel(struct game_context* bj) {
1175 int i, x, y;
1176 unsigned int points = 0;
1178 switch(bj->type) {
1179 case GAME_TYPE_NORMAL:
1180 /* roll over score, change and display level */
1181 while(bj->score >= LEVEL_PTS) {
1182 bj->score -= LEVEL_PTS;
1183 bj->level++;
1184 rb->splashf(HZ*2, "Level %d", bj->level);
1185 jewels_drawboard(bj);
1188 /* randomly clear some jewels */
1189 for(i=0; i<16; i++) {
1190 x = rb->rand()%8;
1191 y = rb->rand()%8;
1193 if(bj->playboard[y][x].type != 0) {
1194 points++;
1195 bj->playboard[y][x].type = 0;
1198 break;
1200 case GAME_TYPE_PUZZLE:
1201 bj->level++;
1202 if(bj->level>NUM_PUZZLE_LEVELS) {
1203 rb->splash(HZ*2, "You win!");
1204 bj->level = 1;
1205 } else {
1206 rb->splashf(HZ*2, "Level %d", bj->level);
1208 break;
1211 points += jewels_initlevel(bj);
1212 bj->score += points;
1215 /*****************************************************************************
1216 * jewels_recordscore() inserts a high score into the high scores list and
1217 * returns the high score position.
1218 ******************************************************************************/
1219 static int jewels_recordscore(struct game_context* bj) {
1220 int i;
1221 int position = 0;
1222 unsigned int current, temp;
1224 /* calculate total score */
1225 current = (bj->level-1)*LEVEL_PTS+bj->score;
1226 if(current <= 0) return 0;
1228 /* insert the current score into the high scores */
1229 for(i=0; i<NUM_SCORES; i++) {
1230 if(current >= bj->highscores[i]) {
1231 if(!position) {
1232 position = i+1;
1233 bj->dirty = true;
1235 temp = bj->highscores[i];
1236 bj->highscores[i] = current;
1237 current = temp;
1241 return position;
1244 /*****************************************************************************
1245 * jewels_loadscores() loads the high scores saved file.
1246 ******************************************************************************/
1247 static void jewels_loadscores(struct game_context* bj) {
1248 int fd;
1250 bj->dirty = false;
1252 /* clear high scores */
1253 rb->memset(bj->highscores, 0, sizeof(bj->highscores));
1255 /* open scores file */
1256 fd = rb->open(SCORE_FILE, O_RDONLY);
1257 if(fd < 0) return;
1259 /* read in high scores */
1260 if(rb->read(fd, bj->highscores, sizeof(bj->highscores)) <= 0) {
1261 /* scores are bad, reset */
1262 rb->memset(bj->highscores, 0, sizeof(bj->highscores));
1265 rb->close(fd);
1268 /*****************************************************************************
1269 * jewels_savescores() saves the high scores saved file.
1270 ******************************************************************************/
1271 static void jewels_savescores(struct game_context* bj) {
1272 int fd;
1274 /* write out the high scores to the save file */
1275 fd = rb->open(SCORE_FILE, O_WRONLY|O_CREAT);
1276 rb->write(fd, bj->highscores, sizeof(bj->highscores));
1277 rb->close(fd);
1278 bj->dirty = false;
1281 /*****************************************************************************
1282 * jewels_loadgame() loads the saved game and returns load success.
1283 ******************************************************************************/
1284 static bool jewels_loadgame(struct game_context* bj) {
1285 int fd;
1286 bool loaded = false;
1288 /* open game file */
1289 fd = rb->open(SAVE_FILE, O_RDONLY);
1290 if(fd < 0) return loaded;
1292 /* read in saved game */
1293 while(true) {
1294 if(rb->read(fd, &bj->score, sizeof(bj->score)) <= 0) break;
1295 if(rb->read(fd, &bj->level, sizeof(bj->level)) <= 0) break;
1296 if(rb->read(fd, &bj->type, sizeof(bj->type)) <= 0) break;
1297 if(rb->read(fd, bj->playboard, sizeof(bj->playboard)) <= 0) break;
1298 bj->resume = true;
1299 loaded = true;
1300 break;
1303 rb->close(fd);
1305 /* delete saved file */
1306 rb->remove(SAVE_FILE);
1307 return loaded;
1310 /*****************************************************************************
1311 * jewels_savegame() saves the current game state.
1312 ******************************************************************************/
1313 static void jewels_savegame(struct game_context* bj) {
1314 int fd;
1316 /* write out the game state to the save file */
1317 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
1318 rb->write(fd, &bj->score, sizeof(bj->score));
1319 rb->write(fd, &bj->level, sizeof(bj->level));
1320 rb->write(fd, &bj->type, sizeof(bj->type));
1321 rb->write(fd, bj->playboard, sizeof(bj->playboard));
1322 rb->close(fd);
1324 bj->resume = true;
1327 /*****************************************************************************
1328 * jewels_callback() is the default event handler callback which is called
1329 * on usb connect and shutdown.
1330 ******************************************************************************/
1331 static void jewels_callback(void* param) {
1332 struct game_context* bj = (struct game_context*) param;
1333 if(bj->dirty) {
1334 rb->splash(HZ, "Saving high scores...");
1335 jewels_savescores(bj);
1339 /*****************************************************************************
1340 * jewels_displayscores() displays the high scores
1341 ******************************************************************************/
1342 static char * scores_get_name(int selected_item, void * data,
1343 char * buffer, size_t buffer_len)
1345 struct game_context* bj = (struct game_context*)data;
1346 rb->snprintf(buffer, buffer_len, "#%02d: %d",
1347 selected_item+1, bj->highscores[selected_item]);
1348 return buffer;
1350 static void jewels_displayscores(struct game_context* bj)
1352 struct simplelist_info info;
1353 rb->simplelist_info_init(&info, "High Scores", NUM_SCORES, (void*)bj);
1354 info.hide_selection = true;
1355 info.get_name = scores_get_name;
1356 rb->simplelist_show_list(&info);
1360 /*****************************************************************************
1361 * jewels_main() is the main game subroutine, it returns the final game status.
1362 ******************************************************************************/
1363 static int jewels_main(struct game_context* bj) {
1364 int w, h;
1365 int button;
1366 struct viewport vp[NB_SCREENS];
1367 char str[18];
1368 bool inmenu = true;
1369 bool selected = false;
1371 /* the cursor coordinates */
1372 int x=0, y=0;
1374 /* don't resume by default */
1375 bj->resume = false;
1377 /********************
1378 * menu *
1379 ********************/
1380 MENUITEM_STRINGLIST(main_menu,"Jewels",NULL,
1381 "New Game", "Puzzle", "Resume Saved Game",
1382 "High Scores", "Help", "Quit");
1383 FOR_NB_SCREENS(h)
1385 rb->viewport_set_defaults(&vp[h], h);
1386 #if (LCD_DEPTH >= 16) || defined(LCD_REMOTE_DEPTH) && (LCD_REMOTE_DEPTH >= 16)
1387 if (rb->screens[h]->depth >= 16)
1389 vp->bg_pattern = LCD_RGBPACK(49, 26, 26);
1390 vp->fg_pattern = LCD_RGBPACK(210, 181, 181);
1392 #endif
1395 while(inmenu) {
1397 switch (rb->do_menu(&main_menu, NULL, vp, true)) {
1398 case 0:
1399 inmenu = false;
1400 bj->type = GAME_TYPE_NORMAL;
1401 break;
1403 case 1:
1404 inmenu = false;
1405 bj->type = GAME_TYPE_PUZZLE;
1406 break;
1408 case 2:
1409 if(!jewels_loadgame(bj)) {
1410 rb->splash(HZ*2, "Nothing to resume");
1411 } else {
1412 inmenu = false;
1414 break;
1416 case 3:
1417 jewels_displayscores(bj);
1418 break;
1420 case 4:
1421 /* welcome screen to display key bindings */
1422 rb->lcd_clear_display();
1423 rb->snprintf(str, 5, "%s", "Help");
1424 rb->lcd_getstringsize(str, &w, &h);
1425 rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, str);
1426 #if CONFIG_KEYPAD == RECORDER_PAD
1427 rb->lcd_puts(0, 2, "Controls:");
1428 rb->lcd_puts(0, 3, "Directions = move");
1429 rb->lcd_puts(0, 4, "PLAY = select");
1430 rb->lcd_puts(0, 5, "Long PLAY = menu");
1431 rb->lcd_puts(0, 6, "OFF = cancel");
1432 #elif CONFIG_KEYPAD == ONDIO_PAD
1433 rb->lcd_puts(0, 2, "Controls:");
1434 rb->lcd_puts(0, 3, "Directions = move");
1435 rb->lcd_puts(0, 4, "MENU = select");
1436 rb->lcd_puts(0, 5, "Long MENU = menu");
1437 rb->lcd_puts(0, 6, "OFF = cancel");
1438 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
1439 rb->lcd_puts(0, 2, "Controls:");
1440 rb->lcd_puts(0, 3, "Directions = move");
1441 rb->lcd_puts(0, 4, "SELECT = select");
1442 rb->lcd_puts(0, 5, "Long SELECT = menu");
1443 rb->lcd_puts(0, 6, "PLAY = cancel");
1444 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
1445 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1446 rb->lcd_puts(0, 3, "form connected segments");
1447 rb->lcd_puts(0, 4, "of three or more of the");
1448 rb->lcd_puts(0, 5, "same type.");
1449 rb->lcd_puts(0, 7, "Controls:");
1450 rb->lcd_puts(0, 8, "Directions to move");
1451 rb->lcd_puts(0, 9, "SELECT to select");
1452 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1453 rb->lcd_puts(0, 11, "OFF to cancel");
1454 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1455 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1456 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1457 rb->lcd_puts(0, 3, "form connected segments");
1458 rb->lcd_puts(0, 4, "of three or more of the");
1459 rb->lcd_puts(0, 5, "same type.");
1460 rb->lcd_puts(0, 7, "Controls:");
1461 rb->lcd_puts(0, 8, "Directions or scroll to move");
1462 rb->lcd_puts(0, 9, "SELECT to select");
1463 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1464 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
1465 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1466 rb->lcd_puts(0, 3, "form connected segments");
1467 rb->lcd_puts(0, 4, "of three or more of the");
1468 rb->lcd_puts(0, 5, "same type.");
1469 rb->lcd_puts(0, 7, "Controls:");
1470 rb->lcd_puts(0, 8, "Directions to move");
1471 rb->lcd_puts(0, 9, "SELECT to select");
1472 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1473 rb->lcd_puts(0, 11, "PLAY to cancel");
1474 #elif CONFIG_KEYPAD == GIGABEAT_PAD \
1475 || CONFIG_KEYPAD == MROBE100_PAD
1476 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1477 rb->lcd_puts(0, 3, "form connected segments");
1478 rb->lcd_puts(0, 4, "of three or more of the");
1479 rb->lcd_puts(0, 5, "same type.");
1480 rb->lcd_puts(0, 7, "Controls:");
1481 rb->lcd_puts(0, 8, "Directions to move");
1482 rb->lcd_puts(0, 9, "SELECT to select");
1483 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1484 rb->lcd_puts(0, 11, "POWER to cancel");
1485 #elif CONFIG_KEYPAD == SANSA_E200_PAD \
1486 || CONFIG_KEYPAD == SANSA_C200_PAD \
1487 || CONFIG_KEYPAD == SANSA_CLIP_PAD \
1488 || CONFIG_KEYPAD == SANSA_FUZE_PAD \
1489 || CONFIG_KEYPAD == SANSA_M200_PAD
1490 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1491 rb->lcd_puts(0, 3, "form connected segments");
1492 rb->lcd_puts(0, 4, "of three or more of the");
1493 rb->lcd_puts(0, 5, "same type.");
1494 rb->lcd_puts(0, 7, "Controls:");
1495 rb->lcd_puts(0, 8, "Directions to move");
1496 rb->lcd_puts(0, 9, "SELECT to select");
1497 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1498 rb->lcd_puts(0, 11, "POWER to cancel");
1499 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1500 rb->lcd_puts(0, 2, "Swap pairs of jewels");
1501 rb->lcd_puts(0, 3, "to form connected");
1502 rb->lcd_puts(0, 4, "segments of three or ");
1503 rb->lcd_puts(0, 5, "more of the");
1504 rb->lcd_puts(0, 6, "same type.");
1505 rb->lcd_puts(0, 8, "Controls:");
1506 rb->lcd_puts(0, 9, "Directions or scroll to move");
1507 rb->lcd_puts(0, 10, "PLAY to select");
1508 rb->lcd_puts(0, 11, "Long PLAY for menu");
1509 rb->lcd_puts(0, 12, "POWER to cancel");
1510 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1511 rb->lcd_puts(0, 2, "Swap pairs of jewels");
1512 rb->lcd_puts(0, 3, "to form connected");
1513 rb->lcd_puts(0, 4, "segments of three or ");
1514 rb->lcd_puts(0, 5, "more of the");
1515 rb->lcd_puts(0, 6, "same type.");
1516 rb->lcd_puts(0, 8, "Controls:");
1517 rb->lcd_puts(0, 9, "Directions or scroll to move");
1518 rb->lcd_puts(0, 10, "PLAY to select");
1519 rb->lcd_puts(0, 11, "Long PLAY for menu");
1520 rb->lcd_puts(0, 12, "REC to cancel");
1521 #elif CONFIG_KEYPAD == COWOND2_PAD
1522 rb->lcd_puts(0, 11, "POWER to cancel");
1523 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
1524 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1525 rb->lcd_puts(0, 3, "form connected segments");
1526 rb->lcd_puts(0, 4, "of three or more of the");
1527 rb->lcd_puts(0, 5, "same type.");
1528 rb->lcd_puts(0, 7, "Controls:");
1529 rb->lcd_puts(0, 8, "Directions to move");
1530 rb->lcd_puts(0, 9, "SELECT to select");
1531 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1532 rb->lcd_puts(0, 11, "BACK to cancel");
1533 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
1534 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1535 rb->lcd_puts(0, 3, "form connected segments");
1536 rb->lcd_puts(0, 4, "of three or more of the");
1537 rb->lcd_puts(0, 5, "same type.");
1538 rb->lcd_puts(0, 7, "Controls:");
1539 rb->lcd_puts(0, 8, "Directions to move");
1540 rb->lcd_puts(0, 9, "MIDDLE to select");
1541 rb->lcd_puts(0, 10, "Long MIDDLE to show menu");
1542 rb->lcd_puts(0, 11, "BACK to cancel");
1543 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
1544 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1545 rb->lcd_puts(0, 3, "form connected segments");
1546 rb->lcd_puts(0, 4, "of three or more of the");
1547 rb->lcd_puts(0, 5, "same type.");
1548 rb->lcd_puts(0, 7, "Controls:");
1549 rb->lcd_puts(0, 8, "Directions to move");
1550 rb->lcd_puts(0, 9, "SELECT/PLAY to select");
1551 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1552 rb->lcd_puts(0, 11, "POWER to cancel");
1553 #elif CONFIG_KEYPAD == ONDAVX747_PAD || CONFIG_KEYPAD == MROBE500_PAD
1554 rb->lcd_puts(0, 11, "POWER to cancel");
1555 #else
1556 #warning: missing help text.
1557 #endif
1559 #ifdef HAVE_TOUCHSCREEN
1560 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1561 rb->lcd_puts(0, 3, "form connected segments");
1562 rb->lcd_puts(0, 4, "of three or more of the");
1563 rb->lcd_puts(0, 5, "same type.");
1564 rb->lcd_puts(0, 7, "Controls:");
1565 rb->lcd_puts(0, 8, "Directions to move");
1566 rb->lcd_puts(0, 9, "CENTER to select");
1567 rb->lcd_puts(0, 10, "Long CENTER to show menu");
1568 #endif
1569 rb->lcd_update();
1570 while(true) {
1571 button = rb->button_get(true);
1572 if(button != BUTTON_NONE && !(button&BUTTON_REL)) break;
1574 rb->lcd_clear_display();
1575 break;
1577 case 5:
1578 return BJ_QUIT;
1580 case MENU_ATTACHED_USB:
1581 jewels_callback(bj);
1582 return BJ_USB;
1584 default:
1585 return BJ_QUIT;
1589 /********************
1590 * init *
1591 ********************/
1592 jewels_init(bj);
1594 /********************
1595 * setup the board *
1596 ********************/
1597 bj->score += jewels_initlevel(bj);
1598 if (!jewels_movesavail(bj)) {
1599 switch(bj->type) {
1600 case GAME_TYPE_NORMAL:
1601 return BJ_LOSE;
1603 case GAME_TYPE_PUZZLE:
1604 do {
1605 rb->splash(2*HZ, "No more moves!");
1606 bj->score += jewels_initlevel(bj);
1607 } while(!jewels_movesavail(bj));
1608 break;
1612 /**********************
1613 * play *
1614 **********************/
1615 MENUITEM_STRINGLIST(ingame_menu,"Menu",NULL,
1616 "Audio Playback", "Resume Game",
1617 "Save Game", "End Game", "Exit Jewels");
1619 selected = false;
1620 while(true) {
1621 bool no_movesavail = false;
1623 while(inmenu) {
1624 switch (rb->do_menu(&ingame_menu, NULL, vp, true)) {
1625 case 0:
1626 playback_control(NULL);
1627 inmenu = false;
1628 break;
1630 case 1:
1631 inmenu = false;
1632 break;
1634 case 2:
1635 rb->splash(HZ, "Saving game...");
1636 jewels_savegame(bj);
1637 return BJ_END;
1639 case 3:
1640 return BJ_END;
1642 case 4:
1643 return BJ_QUIT_FROM_GAME;
1645 case MENU_ATTACHED_USB:
1646 jewels_callback(bj);
1647 return BJ_USB;
1649 default:
1650 inmenu = false;
1651 break;
1655 /* refresh the board */
1656 jewels_drawboard(bj);
1658 /* display the cursor */
1659 if(selected) {
1660 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1661 rb->lcd_fillrect(x*TILE_WIDTH, y*TILE_HEIGHT+YOFS,
1662 TILE_WIDTH, TILE_HEIGHT);
1663 rb->lcd_set_drawmode(DRMODE_SOLID);
1664 } else {
1665 rb->lcd_drawrect(x*TILE_WIDTH, y*TILE_HEIGHT+YOFS,
1666 TILE_WIDTH, TILE_HEIGHT);
1668 rb->lcd_update_rect(x*TILE_WIDTH, y*TILE_HEIGHT+YOFS,
1669 TILE_WIDTH, TILE_HEIGHT);
1671 /* handle game button presses */
1672 rb->yield();
1673 button = rb->button_get(true);
1674 switch(button){
1675 case JEWELS_LEFT: /* move cursor left */
1676 case (JEWELS_LEFT|BUTTON_REPEAT):
1677 if(selected) {
1678 bj->score += jewels_swapjewels(bj, x, y, SWAP_LEFT);
1679 selected = false;
1680 if (!jewels_movesavail(bj)) no_movesavail = true;
1681 } else {
1682 x = (x+BJ_WIDTH-1)%BJ_WIDTH;
1684 break;
1686 case JEWELS_RIGHT: /* move cursor right */
1687 case (JEWELS_RIGHT|BUTTON_REPEAT):
1688 if(selected) {
1689 bj->score += jewels_swapjewels(bj, x, y, SWAP_RIGHT);
1690 selected = false;
1691 if (!jewels_movesavail(bj)) no_movesavail = true;
1692 } else {
1693 x = (x+1)%BJ_WIDTH;
1695 break;
1697 case JEWELS_DOWN: /* move cursor down */
1698 case (JEWELS_DOWN|BUTTON_REPEAT):
1699 if(selected) {
1700 bj->score += jewels_swapjewels(bj, x, y, SWAP_DOWN);
1701 selected = false;
1702 if (!jewels_movesavail(bj)) no_movesavail = true;
1703 } else {
1704 y = (y+1)%(BJ_HEIGHT-1);
1706 break;
1708 case JEWELS_UP: /* move cursor up */
1709 case (JEWELS_UP|BUTTON_REPEAT):
1710 if(selected) {
1711 bj->score += jewels_swapjewels(bj, x, y, SWAP_UP);
1712 selected = false;
1713 if (!jewels_movesavail(bj)) no_movesavail = true;
1714 } else {
1715 y = (y+(BJ_HEIGHT-1)-1)%(BJ_HEIGHT-1);
1717 break;
1719 #ifdef JEWELS_SCROLLWHEEL
1720 case JEWELS_PREV: /* scroll backwards */
1721 case (JEWELS_PREV|BUTTON_REPEAT):
1722 if(!selected) {
1723 if(x == 0) {
1724 y = (y+(BJ_HEIGHT-1)-1)%(BJ_HEIGHT-1);
1726 x = (x+BJ_WIDTH-1)%BJ_WIDTH;
1728 break;
1730 case JEWELS_NEXT: /* scroll forwards */
1731 case (JEWELS_NEXT|BUTTON_REPEAT):
1732 if(!selected) {
1733 if(x == BJ_WIDTH-1) {
1734 y = (y+1)%(BJ_HEIGHT-1);
1736 x = (x+1)%BJ_WIDTH;
1738 break;
1739 #endif
1741 case JEWELS_SELECT: /* toggle selected */
1742 selected = !selected;
1743 break;
1745 #ifdef JEWELS_MENU
1746 case JEWELS_MENU:
1747 #endif
1748 case (JEWELS_SELECT|BUTTON_REPEAT): /* show menu */
1749 inmenu = true;
1750 selected = false;
1751 break;
1753 #ifdef JEWELS_CANCEL
1754 #ifdef JEWELS_RC_CANCEL
1755 case JEWELS_RC_CANCEL:
1756 #endif
1757 case JEWELS_CANCEL: /* end game */
1758 return BJ_END;
1759 break;
1760 #endif
1762 default:
1763 if(rb->default_event_handler_ex(button, jewels_callback,
1764 (void*) bj) == SYS_USB_CONNECTED)
1765 return BJ_USB;
1766 break;
1769 if (no_movesavail) {
1770 switch(bj->type) {
1771 case GAME_TYPE_NORMAL:
1772 return BJ_LOSE;
1774 case GAME_TYPE_PUZZLE:
1775 do {
1776 rb->splash(2*HZ, "No more moves!");
1777 bj->score += jewels_initlevel(bj);
1778 } while(!jewels_movesavail(bj));
1779 break;
1783 switch(bj->type) {
1784 case GAME_TYPE_NORMAL:
1785 if(bj->score >= LEVEL_PTS)
1786 jewels_nextlevel(bj);
1787 break;
1789 case GAME_TYPE_PUZZLE:
1790 if(jewels_puzzle_is_finished(bj))
1791 jewels_nextlevel(bj);
1792 break;
1797 /*****************************************************************************
1798 * plugin entry point.
1799 ******************************************************************************/
1800 enum plugin_status plugin_start(const void* parameter) {
1801 struct game_context bj;
1802 bool exit = false;
1803 int position;
1804 char str[19];
1806 /* plugin init */
1807 (void)parameter;
1808 /* end of plugin init */
1810 /* load high scores */
1811 jewels_loadscores(&bj);
1813 rb->lcd_setfont(FONT_SYSFIXED);
1814 #if LCD_DEPTH > 1
1815 rb->lcd_set_backdrop(NULL);
1816 #endif
1817 jewels_setcolors();
1819 while(!exit) {
1820 switch(jewels_main(&bj)){
1821 case BJ_LOSE:
1822 rb->splash(HZ*2, "No more moves!");
1823 /* fall through to BJ_END */
1825 case BJ_END:
1826 if(!bj.resume) {
1827 if((position = jewels_recordscore(&bj))) {
1828 rb->snprintf(str, 19, "New high score #%d!", position);
1829 rb->splash(HZ*2, str);
1832 break;
1834 case BJ_USB:
1835 rb->lcd_setfont(FONT_UI);
1836 return PLUGIN_USB_CONNECTED;
1838 case BJ_QUIT:
1839 if(bj.dirty) {
1840 rb->splash(HZ, "Saving high scores...");
1841 jewels_savescores(&bj);
1843 exit = true;
1844 break;
1846 case BJ_QUIT_FROM_GAME:
1847 if(!bj.resume) {
1848 if((position = jewels_recordscore(&bj))) {
1849 rb->snprintf(str, 19, "New high score #%d!", position);
1850 rb->splash(HZ*2, str);
1853 if(bj.dirty) {
1854 rb->splash(HZ, "Saving high scores...");
1855 jewels_savescores(&bj);
1857 exit = true;
1858 break;
1860 default:
1861 break;
1865 rb->lcd_setfont(FONT_UI);
1866 return PLUGIN_OK;
1869 #endif /* HAVE_LCD_BITMAP */