Minor corrections to the .colours file editing; added .colours to the list of support...
[kugel-rb.git] / apps / plugins / jewels.c
blob00839af48dac2a748314bd6cd83e26a30ffb9b0a
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_CANCEL BUTTON_OFF
63 #define JEWELS_RC_CANCEL BUTTON_RC_STOP
65 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
66 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
67 #define JEWELS_SCROLLWHEEL
68 #define JEWELS_UP BUTTON_MENU
69 #define JEWELS_DOWN BUTTON_PLAY
70 #define JEWELS_LEFT BUTTON_LEFT
71 #define JEWELS_RIGHT BUTTON_RIGHT
72 #define JEWELS_PREV BUTTON_SCROLL_BACK
73 #define JEWELS_NEXT BUTTON_SCROLL_FWD
74 #define JEWELS_SELECT BUTTON_SELECT
76 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
77 #define JEWELS_UP BUTTON_UP
78 #define JEWELS_DOWN BUTTON_DOWN
79 #define JEWELS_LEFT BUTTON_LEFT
80 #define JEWELS_RIGHT BUTTON_RIGHT
81 #define JEWELS_SELECT BUTTON_SELECT
82 #define JEWELS_CANCEL BUTTON_PLAY
84 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
85 #define JEWELS_UP BUTTON_UP
86 #define JEWELS_DOWN BUTTON_DOWN
87 #define JEWELS_LEFT BUTTON_LEFT
88 #define JEWELS_RIGHT BUTTON_RIGHT
89 #define JEWELS_SELECT BUTTON_SELECT
90 #define JEWELS_CANCEL BUTTON_POWER
92 #elif CONFIG_KEYPAD == GIGABEAT_PAD
93 #define JEWELS_UP BUTTON_UP
94 #define JEWELS_DOWN BUTTON_DOWN
95 #define JEWELS_LEFT BUTTON_LEFT
96 #define JEWELS_RIGHT BUTTON_RIGHT
97 #define JEWELS_SELECT BUTTON_SELECT
98 #define JEWELS_CANCEL BUTTON_POWER
100 #elif CONFIG_KEYPAD == SANSA_E200_PAD || \
101 (CONFIG_KEYPAD == SANSA_FUZE_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_C200_PAD || \
113 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
114 CONFIG_KEYPAD == SANSA_M200_PAD
115 #define JEWELS_UP BUTTON_UP
116 #define JEWELS_DOWN BUTTON_DOWN
117 #define JEWELS_LEFT BUTTON_LEFT
118 #define JEWELS_RIGHT BUTTON_RIGHT
119 #define JEWELS_SELECT BUTTON_SELECT
120 #define JEWELS_CANCEL BUTTON_POWER
122 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
123 #define JEWELS_UP BUTTON_SCROLL_UP
124 #define JEWELS_DOWN BUTTON_SCROLL_DOWN
125 #define JEWELS_LEFT BUTTON_LEFT
126 #define JEWELS_RIGHT BUTTON_RIGHT
127 #define JEWELS_SELECT BUTTON_PLAY
128 #define JEWELS_CANCEL BUTTON_POWER
130 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
131 #define JEWELS_UP BUTTON_UP
132 #define JEWELS_DOWN BUTTON_DOWN
133 #define JEWELS_LEFT BUTTON_LEFT
134 #define JEWELS_RIGHT BUTTON_RIGHT
135 #define JEWELS_SELECT BUTTON_SELECT
136 #define JEWELS_CANCEL BUTTON_BACK
138 #elif CONFIG_KEYPAD == MROBE100_PAD
139 #define JEWELS_UP BUTTON_UP
140 #define JEWELS_DOWN BUTTON_DOWN
141 #define JEWELS_LEFT BUTTON_LEFT
142 #define JEWELS_RIGHT BUTTON_RIGHT
143 #define JEWELS_SELECT BUTTON_SELECT
144 #define JEWELS_CANCEL BUTTON_POWER
146 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
147 #define JEWELS_UP BUTTON_RC_VOL_UP
148 #define JEWELS_DOWN BUTTON_RC_VOL_DOWN
149 #define JEWELS_LEFT BUTTON_RC_REW
150 #define JEWELS_RIGHT BUTTON_RC_FF
151 #define JEWELS_SELECT BUTTON_RC_PLAY
152 #define JEWELS_CANCEL BUTTON_RC_REC
154 #define JEWELS_RC_CANCEL BUTTON_REC
156 #elif CONFIG_KEYPAD == COWOND2_PAD
157 #define JEWELS_CANCEL BUTTON_POWER
159 #elif CONFIG_KEYPAD == IAUDIO67_PAD
160 #define JEWELS_UP BUTTON_STOP
161 #define JEWELS_DOWN BUTTON_PLAY
162 #define JEWELS_LEFT BUTTON_LEFT
163 #define JEWELS_RIGHT BUTTON_RIGHT
164 #define JEWELS_SELECT BUTTON_MENU
165 #define JEWELS_CANCEL BUTTON_POWER
167 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
168 #define JEWELS_UP BUTTON_UP
169 #define JEWELS_DOWN BUTTON_DOWN
170 #define JEWELS_LEFT BUTTON_LEFT
171 #define JEWELS_RIGHT BUTTON_RIGHT
172 #define JEWELS_SELECT BUTTON_SELECT
173 #define JEWELS_CANCEL BUTTON_BACK
175 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
176 #define JEWELS_UP BUTTON_UP
177 #define JEWELS_DOWN BUTTON_DOWN
178 #define JEWELS_LEFT BUTTON_LEFT
179 #define JEWELS_RIGHT BUTTON_RIGHT
180 #define JEWELS_SELECT BUTTON_SELECT
181 #define JEWELS_CANCEL BUTTON_POWER
183 #else
184 #error No keymap defined!
185 #endif
187 #ifdef HAVE_TOUCHSCREEN
188 #ifndef JEWELS_UP
189 #define JEWELS_UP BUTTON_TOPMIDDLE
190 #endif
191 #ifndef JEWELS_DOWN
192 #define JEWELS_DOWN BUTTON_BOTTOMMIDDLE
193 #endif
194 #ifndef JEWELS_LEFT
195 #define JEWELS_LEFT BUTTON_MIDLEFT
196 #endif
197 #ifndef JEWELS_RIGHT
198 #define JEWELS_RIGHT BUTTON_MIDRIGHT
199 #endif
200 #ifndef JEWELS_SELECT
201 #define JEWELS_SELECT BUTTON_CENTER
202 #endif
203 #ifndef JEWELS_CANCEL
204 #define JEWELS_CANCEL BUTTON_TOPLEFT
205 #endif
206 #endif
208 /* use 30x30 tiles (iPod Video, Gigabeat) */
209 #if (LCD_HEIGHT == 240) && (LCD_WIDTH == 320) || \
210 ((LCD_HEIGHT == 320) && (LCD_WIDTH == 240))
211 #define TILE_WIDTH 30
212 #define TILE_HEIGHT 30
213 #define YOFS 0
214 #define NUM_SCORES 10
216 /* use 22x22 tiles (H300, iPod Color) */
217 #elif ((LCD_HEIGHT == 176) && (LCD_WIDTH == 220)) || \
218 ((LCD_HEIGHT == 220) && (LCD_WIDTH == 176))
219 #define TILE_WIDTH 22
220 #define TILE_HEIGHT 22
221 #define YOFS 0
222 #define NUM_SCORES 10
224 /* use 16x16 tiles (iPod Nano) */
225 #elif (LCD_HEIGHT == 132) && (LCD_WIDTH == 176)
226 #define TILE_WIDTH 16
227 #define TILE_HEIGHT 16
228 #define YOFS 4
229 #define NUM_SCORES 10
231 /* use 16x16 tiles (H100, iAudio X5, iPod 3G, iPod 4G grayscale) */
232 #elif (LCD_HEIGHT == 128) && (LCD_WIDTH == 160)
233 #define TILE_WIDTH 16
234 #define TILE_HEIGHT 16
235 #define YOFS 0
236 #define NUM_SCORES 10
238 /* use 14x14 tiles (H10 5/6 GB) */
239 #elif (LCD_HEIGHT == 128) && (LCD_WIDTH == 128)
240 #define TILE_WIDTH 14
241 #define TILE_HEIGHT 14
242 #define YOFS 0
243 #define NUM_SCORES 10
245 /* use 13x13 tiles (iPod Mini) */
246 #elif (LCD_HEIGHT == 110) && (LCD_WIDTH == 138)
247 #define TILE_WIDTH 13
248 #define TILE_HEIGHT 13
249 #define YOFS 6
250 #define NUM_SCORES 10
252 /* use 12x12 tiles (iAudio M3) */
253 #elif (LCD_HEIGHT == 96) && (LCD_WIDTH == 128)
254 #define TILE_WIDTH 12
255 #define TILE_HEIGHT 12
256 #define YOFS 0
257 #define NUM_SCORES 9
259 /* use 10x10 tiles (Sansa c200) */
260 #elif (LCD_HEIGHT == 80) && (LCD_WIDTH == 132)
261 #define TILE_WIDTH 10
262 #define TILE_HEIGHT 10
263 #define YOFS 0
264 #define NUM_SCORES 8
266 /* use 10x8 tiles (iFP 700) */
267 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 128)
268 #define TILE_WIDTH 10
269 #define TILE_HEIGHT 8
270 #define YOFS 0
271 #define NUM_SCORES 8
273 /* use 10x8 tiles (Recorder, Ondio) */
274 #elif (LCD_HEIGHT == 64) && (LCD_WIDTH == 112)
275 #define TILE_WIDTH 10
276 #define TILE_HEIGHT 8
277 #define YOFS 0
278 #define NUM_SCORES 8
280 #else
281 #error JEWELS: Unsupported LCD
282 #endif
284 /* save files */
285 #define SCORE_FILE PLUGIN_GAMES_DIR "/jewels.score"
286 #define SAVE_FILE PLUGIN_GAMES_DIR "/jewels.save"
288 /* final game return status */
289 #define BJ_QUIT_FROM_GAME 4
290 #define BJ_END 3
291 #define BJ_USB 2
292 #define BJ_QUIT 1
293 #define BJ_LOSE 0
295 /* swap directions */
296 #define SWAP_UP 0
297 #define SWAP_RIGHT 1
298 #define SWAP_DOWN 2
299 #define SWAP_LEFT 3
301 /* play board dimension */
302 #define BJ_HEIGHT 9
303 #define BJ_WIDTH 8
305 /* next level threshold */
306 #define LEVEL_PTS 100
308 /* animation frame rate */
309 #define MAX_FPS 20
311 /* Game types */
312 enum game_type {
313 GAME_TYPE_NORMAL,
314 GAME_TYPE_PUZZLE
317 /* menu values */
318 #define FONT_HEIGHT 8
319 #define MAX_MITEMS 6
320 #define MENU_WIDTH 100
322 /* menu results */
323 enum menu_result {
324 MRES_NONE,
325 MRES_NEW,
326 MRES_PUZZLE,
327 MRES_SAVE,
328 MRES_RESUME,
329 MRES_SCORES,
330 MRES_HELP,
331 MRES_QUIT,
332 MRES_PLAYBACK,
333 MRES_EXIT
336 /* menu commands */
337 enum menu_cmd {
338 MCMD_NONE,
339 MCMD_NEXT,
340 MCMD_PREV,
341 MCMD_SELECT
344 /* menus */
345 struct jewels_menu {
346 char *title;
347 bool hasframe;
348 int selected;
349 int itemcnt;
350 struct jewels_menuitem {
351 char *text;
352 enum menu_result res;
353 } items[MAX_MITEMS];
354 } bjmenu[] = {
355 {"Jewels", false, 0, 6,
356 {{"New Game", MRES_NEW},
357 {"Puzzle", MRES_PUZZLE},
358 {"Resume Game", MRES_RESUME},
359 {"High Scores", MRES_SCORES},
360 {"Help", MRES_HELP},
361 {"Quit", MRES_QUIT}}},
362 {"Menu", true, 0, 5,
363 {{"Audio Playback", MRES_PLAYBACK },
364 {"Resume Game", MRES_RESUME},
365 {"Save Game", MRES_SAVE},
366 {"End Game", MRES_QUIT},
367 {"Exit Jewels", MRES_EXIT}}}
370 /* external bitmaps */
371 extern const fb_data jewels[];
373 /* tile background colors */
374 #ifdef HAVE_LCD_COLOR
375 static const unsigned jewels_bkgd[2] = {
376 LCD_RGBPACK(104, 63, 63),
377 LCD_RGBPACK(83, 44, 44)
379 #endif
381 /* the tile struct
382 * type is the jewel number 0-7
383 * falling if the jewel is falling
384 * delete marks the jewel for deletion
386 struct tile {
387 int type;
388 bool falling;
389 bool delete;
392 /* the game context struct
393 * score is the current level score
394 * segments is the number of cleared segments in the current run
395 * level is the current level
396 * type is the game type (normal or puzzle)
397 * highscores is the list of high scores
398 * resume denotes whether to resume the currently loaded game
399 * dirty denotes whether the high scores are out of sync with the saved file
400 * playboard is the game playing board (first row is hidden)
401 * num_jewels is the number of different jewels to use
403 struct game_context {
404 unsigned int score;
405 unsigned int segments;
406 unsigned int level;
407 unsigned int type;
408 unsigned int highscores[NUM_SCORES];
409 bool resume;
410 bool dirty;
411 struct tile playboard[BJ_HEIGHT][BJ_WIDTH];
412 unsigned int num_jewels;
415 #define MAX_NUM_JEWELS 7
417 #define MAX_PUZZLE_TILES 4
418 #define NUM_PUZZLE_LEVELS 10
420 struct puzzle_tile {
421 int x;
422 int y;
423 int tile_type;
426 struct puzzle_level {
427 unsigned int num_jewels;
428 unsigned int num_tiles;
429 struct puzzle_tile tiles[MAX_PUZZLE_TILES];
432 #define PUZZLE_TILE_UP 1
433 #define PUZZLE_TILE_DOWN 2
434 #define PUZZLE_TILE_LEFT 4
435 #define PUZZLE_TILE_RIGHT 8
437 struct puzzle_level puzzle_levels[NUM_PUZZLE_LEVELS] = {
438 { 5, 2, { {3, 3, PUZZLE_TILE_RIGHT},
439 {4, 2, PUZZLE_TILE_LEFT} } },
440 { 5, 2, { {3, 2, PUZZLE_TILE_DOWN},
441 {3, 4, PUZZLE_TILE_UP} } },
442 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN},
443 {3, 4, PUZZLE_TILE_UP|PUZZLE_TILE_DOWN},
444 {3, 6, PUZZLE_TILE_UP} } },
445 { 6, 3, { {3, 2, PUZZLE_TILE_RIGHT},
446 {4, 3, PUZZLE_TILE_LEFT|PUZZLE_TILE_RIGHT},
447 {5, 4, PUZZLE_TILE_LEFT} } },
448 { 6, 2, { {3, 4, PUZZLE_TILE_RIGHT},
449 {4, 2, PUZZLE_TILE_LEFT} } },
450 { 6, 2, { {3, 2, PUZZLE_TILE_DOWN},
451 {4, 4, PUZZLE_TILE_UP} } },
452 { 7, 4, { {3, 2, PUZZLE_TILE_RIGHT|PUZZLE_TILE_DOWN},
453 {4, 3, PUZZLE_TILE_LEFT|PUZZLE_TILE_DOWN},
454 {3, 4, PUZZLE_TILE_RIGHT|PUZZLE_TILE_UP},
455 {4, 4, PUZZLE_TILE_LEFT|PUZZLE_TILE_UP} } },
456 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN},
457 {4, 4, PUZZLE_TILE_UP|PUZZLE_TILE_DOWN},
458 {3, 6, PUZZLE_TILE_UP} } },
459 { 7, 3, { {2, 2, PUZZLE_TILE_RIGHT},
460 {4, 1, PUZZLE_TILE_LEFT|PUZZLE_TILE_RIGHT},
461 {5, 4, PUZZLE_TILE_LEFT} } },
462 { 7, 4, { {3, 0, PUZZLE_TILE_RIGHT|PUZZLE_TILE_DOWN},
463 {5, 0, PUZZLE_TILE_LEFT|PUZZLE_TILE_DOWN},
464 {2, 7, PUZZLE_TILE_RIGHT|PUZZLE_TILE_UP},
465 {4, 7, PUZZLE_TILE_LEFT|PUZZLE_TILE_UP} } },
468 /*****************************************************************************
469 * jewels_init() initializes jewels data structures.
470 ******************************************************************************/
471 static void jewels_init(struct game_context* bj) {
472 /* seed the rand generator */
473 rb->srand(*rb->current_tick);
475 /* check for resumed game */
476 if(bj->resume) {
477 bj->resume = false;
478 return;
481 /* reset scoring */
482 bj->level = 1;
483 bj->score = 0;
484 bj->segments = 0;
486 /* clear playing board */
487 rb->memset(bj->playboard, 0, sizeof(bj->playboard));
490 /*****************************************************************************
491 * jewels_setcolors() set the foreground and background colors.
492 ******************************************************************************/
493 static inline void jewels_setcolors(void) {
494 #ifdef HAVE_LCD_COLOR
495 rb->lcd_set_background(LCD_RGBPACK(49, 26, 26));
496 rb->lcd_set_foreground(LCD_RGBPACK(210, 181, 181));
497 #endif
500 /*****************************************************************************
501 * jewels_drawboard() redraws the entire game board.
502 ******************************************************************************/
503 static void jewels_drawboard(struct game_context* bj) {
504 int i, j;
505 int w, h;
506 unsigned int tempscore;
507 char *title = "Level";
508 char str[10];
510 tempscore = (bj->score>LEVEL_PTS ? LEVEL_PTS : bj->score);
512 /* clear screen */
513 rb->lcd_clear_display();
515 /* dispay playing board */
516 for(i=0; i<BJ_HEIGHT-1; i++){
517 for(j=0; j<BJ_WIDTH; j++){
518 #ifdef HAVE_LCD_COLOR
519 rb->lcd_set_foreground(jewels_bkgd[(i+j)%2]);
520 rb->lcd_fillrect(j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
521 TILE_WIDTH, TILE_HEIGHT);
522 rb->lcd_bitmap_transparent_part(jewels,
523 0, TILE_HEIGHT*(bj->playboard[i+1][j].type),
524 TILE_WIDTH, j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
525 TILE_WIDTH, TILE_HEIGHT);
526 #else
527 rb->lcd_bitmap_part(jewels,
528 0, TILE_HEIGHT*(bj->playboard[i+1][j].type),
529 TILE_WIDTH, j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
530 TILE_WIDTH, TILE_HEIGHT);
531 #endif
535 #if LCD_WIDTH > LCD_HEIGHT /* horizontal layout */
537 /* draw separator lines */
538 jewels_setcolors();
539 rb->lcd_vline(BJ_WIDTH*TILE_WIDTH, 0, LCD_HEIGHT-1);
540 rb->lcd_hline(BJ_WIDTH*TILE_WIDTH, LCD_WIDTH-1, 18);
541 rb->lcd_hline(BJ_WIDTH*TILE_WIDTH, LCD_WIDTH-1, LCD_HEIGHT-10);
543 /* draw progress bar */
544 #ifdef HAVE_LCD_COLOR
545 rb->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
546 #endif
547 rb->lcd_fillrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
548 (LCD_HEIGHT-10)-(((LCD_HEIGHT-10)-18)*
549 tempscore/LEVEL_PTS),
550 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
551 ((LCD_HEIGHT-10)-18)*tempscore/LEVEL_PTS);
552 #ifdef HAVE_LCD_COLOR
553 rb->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
554 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4+1,
555 (LCD_HEIGHT-10)-(((LCD_HEIGHT-10)-18)*
556 tempscore/LEVEL_PTS)+1,
557 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-2,
558 ((LCD_HEIGHT-10)-18)*tempscore/LEVEL_PTS-1);
559 jewels_setcolors();
560 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
561 (LCD_HEIGHT-10)-(((LCD_HEIGHT-10)-18)*
562 tempscore/LEVEL_PTS),
563 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
564 ((LCD_HEIGHT-10)-18)*tempscore/LEVEL_PTS+1);
565 #endif
567 /* print text */
568 rb->lcd_getstringsize(title, &w, &h);
569 rb->lcd_putsxy(LCD_WIDTH-(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-w/2, 1, title);
571 rb->snprintf(str, 4, "%d", bj->level);
572 rb->lcd_getstringsize(str, &w, &h);
573 rb->lcd_putsxy(LCD_WIDTH-(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-w/2, 10, str);
575 rb->snprintf(str, 6, "%d", (bj->level-1)*LEVEL_PTS+bj->score);
576 rb->lcd_getstringsize(str, &w, &h);
577 rb->lcd_putsxy(LCD_WIDTH-(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-w/2,
578 LCD_HEIGHT-8, str);
580 #elif LCD_WIDTH < LCD_HEIGHT /* vertical layout */
582 /* draw separator lines */
583 jewels_setcolors();
584 rb->lcd_hline(0, LCD_WIDTH-1, 8*TILE_HEIGHT+YOFS);
585 rb->lcd_hline(0, LCD_WIDTH-1, LCD_HEIGHT-14);
586 rb->lcd_vline(LCD_WIDTH/2, LCD_HEIGHT-14, 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(0, (8*TILE_HEIGHT+YOFS)
593 +(LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/4,
594 LCD_WIDTH*tempscore/LEVEL_PTS,
595 (LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/2);
596 #ifdef HAVE_LCD_COLOR
597 rb->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
598 rb->lcd_drawrect(1, (8*TILE_HEIGHT+YOFS)
599 +(LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/4+1,
600 LCD_WIDTH*tempscore/LEVEL_PTS-1,
601 (LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/2-2);
602 jewels_setcolors();
603 rb->lcd_drawrect(0, (8*TILE_HEIGHT+YOFS)
604 +(LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/4,
605 LCD_WIDTH*tempscore/LEVEL_PTS+1,
606 (LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/2);
607 #endif
609 /* print text */
610 rb->snprintf(str, 10, "%s %d", title, bj->level);
611 rb->lcd_putsxy(1, LCD_HEIGHT-10, str);
613 rb->snprintf(str, 6, "%d", (bj->level-1)*LEVEL_PTS+bj->score);
614 rb->lcd_getstringsize(str, &w, &h);
615 rb->lcd_putsxy((LCD_WIDTH-2)-w, LCD_HEIGHT-10, str);
617 #else /* square layout */
619 /* draw separator lines */
620 jewels_setcolors();
621 rb->lcd_hline(0, LCD_WIDTH-1, 8*TILE_HEIGHT+YOFS);
622 rb->lcd_vline(BJ_WIDTH*TILE_WIDTH, 0, 8*TILE_HEIGHT+YOFS);
623 rb->lcd_vline(LCD_WIDTH/2, 8*TILE_HEIGHT+YOFS, LCD_HEIGHT-1);
625 /* draw progress bar */
626 #ifdef HAVE_LCD_COLOR
627 rb->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
628 #endif
629 rb->lcd_fillrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
630 (8*TILE_HEIGHT+YOFS)-(8*TILE_HEIGHT+YOFS)
631 *tempscore/LEVEL_PTS,
632 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
633 (8*TILE_HEIGHT+YOFS)*tempscore/LEVEL_PTS);
634 #ifdef HAVE_LCD_COLOR
635 rb->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
636 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4+1,
637 (8*TILE_HEIGHT+YOFS)-(8*TILE_HEIGHT+YOFS)
638 *tempscore/LEVEL_PTS+1,
639 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-2,
640 (8*TILE_HEIGHT+YOFS)*tempscore/LEVEL_PTS-1);
641 jewels_setcolors();
642 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
643 (8*TILE_HEIGHT+YOFS)-(8*TILE_HEIGHT+YOFS)
644 *tempscore/LEVEL_PTS,
645 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
646 (8*TILE_HEIGHT+YOFS)*tempscore/LEVEL_PTS+1);
647 #endif
649 /* print text */
650 rb->snprintf(str, 10, "%s %d", title, bj->level);
651 rb->lcd_putsxy(1, LCD_HEIGHT-(LCD_HEIGHT-(8*TILE_HEIGHT+YOFS))/2-3, str);
653 rb->snprintf(str, 6, "%d", (bj->level-1)*LEVEL_PTS+bj->score);
654 rb->lcd_getstringsize(str, &w, &h);
655 rb->lcd_putsxy((LCD_WIDTH-2)-w,
656 LCD_HEIGHT-(LCD_HEIGHT-(8*TILE_HEIGHT+YOFS))/2-3, str);
658 #endif /* layout */
660 rb->lcd_update();
663 /*****************************************************************************
664 * jewels_showmenu() displays the chosen menu after performing the chosen
665 * menu command.
666 ******************************************************************************/
667 static enum menu_result jewels_showmenu(struct jewels_menu* menu,
668 enum menu_cmd cmd) {
669 int i;
670 int w, h;
671 int firstline;
672 int adj;
673 int extraline = LCD_HEIGHT <= ((menu->itemcnt+2)*FONT_HEIGHT) ? 0 : 1;
675 /* handle menu command */
676 switch(cmd) {
677 case MCMD_NEXT:
678 menu->selected = (menu->selected+1)%menu->itemcnt;
679 break;
681 case MCMD_PREV:
682 menu->selected = (menu->selected-1+menu->itemcnt)%menu->itemcnt;
683 break;
685 case MCMD_SELECT:
686 return menu->items[menu->selected].res;
688 default:
689 break;
692 /* clear menu area */
693 firstline = (LCD_HEIGHT/FONT_HEIGHT-(menu->itemcnt+3))/2;
695 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
696 rb->lcd_fillrect((LCD_WIDTH-MENU_WIDTH)/2, firstline*FONT_HEIGHT,
697 MENU_WIDTH, (menu->itemcnt+3)*FONT_HEIGHT);
698 rb->lcd_set_drawmode(DRMODE_SOLID);
700 if(menu->hasframe) {
701 rb->lcd_drawrect((LCD_WIDTH-MENU_WIDTH)/2-1, firstline*FONT_HEIGHT-1,
702 MENU_WIDTH+2, (menu->itemcnt+3)*FONT_HEIGHT+2);
703 rb->lcd_hline((LCD_WIDTH-MENU_WIDTH)/2-1,
704 (LCD_WIDTH-MENU_WIDTH)/2-1+MENU_WIDTH+2,
705 (firstline+1)*FONT_HEIGHT);
708 /* draw menu items */
709 rb->lcd_getstringsize(menu->title, &w, &h);
710 rb->lcd_putsxy((LCD_WIDTH-w)/2, firstline*FONT_HEIGHT, menu->title);
712 for(i=0; i<menu->itemcnt; i++) {
713 if(i == menu->selected) {
714 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
716 rb->lcd_putsxy((LCD_WIDTH-MENU_WIDTH)/2,
717 (firstline+i+1+extraline)*FONT_HEIGHT,
718 menu->items[i].text);
719 if(i == menu->selected) {
720 rb->lcd_set_drawmode(DRMODE_SOLID);
724 adj = (firstline == 0 ? 0 : 1);
725 rb->lcd_update_rect((LCD_WIDTH-MENU_WIDTH)/2-1, firstline*FONT_HEIGHT-adj,
726 MENU_WIDTH+2, (menu->itemcnt+3)*FONT_HEIGHT+2*adj);
727 return MRES_NONE;
730 /*****************************************************************************
731 * jewels_putjewels() makes the jewels fall to fill empty spots and adds
732 * new random jewels at the empty spots at the top of each row.
733 ******************************************************************************/
734 static void jewels_putjewels(struct game_context* bj){
735 int i, j, k;
736 bool mark, done;
737 long lasttick, currenttick;
739 /* loop to make all the jewels fall */
740 while(true) {
741 /* mark falling jewels and add new jewels to hidden top row*/
742 mark = false;
743 done = true;
744 for(j=0; j<BJ_WIDTH; j++) {
745 if(bj->playboard[1][j].type == 0) {
746 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
748 for(i=BJ_HEIGHT-2; i>=0; i--) {
749 if(!mark && bj->playboard[i+1][j].type == 0) {
750 mark = true;
751 done = false;
753 if(mark) bj->playboard[i][j].falling = true;
755 /*if(bj->playboard[1][j].falling) {
756 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
757 bj->playboard[0][j].falling = true;
759 mark = false;
762 /* break if there are no falling jewels */
763 if(done) break;
765 /* animate falling jewels */
766 lasttick = *rb->current_tick;
768 for(k=1; k<=8; k++) {
769 for(i=BJ_HEIGHT-2; i>=0; i--) {
770 for(j=0; j<BJ_WIDTH; j++) {
771 if(bj->playboard[i][j].falling &&
772 bj->playboard[i][j].type != 0) {
773 /* clear old position */
774 #ifdef HAVE_LCD_COLOR
775 if(i == 0 && YOFS) {
776 rb->lcd_set_foreground(rb->lcd_get_background());
777 } else {
778 rb->lcd_set_foreground(jewels_bkgd[(i-1+j)%2]);
780 rb->lcd_fillrect(j*TILE_WIDTH, (i-1)*TILE_HEIGHT+YOFS,
781 TILE_WIDTH, TILE_HEIGHT);
782 if(bj->playboard[i+1][j].type == 0) {
783 rb->lcd_set_foreground(jewels_bkgd[(i+j)%2]);
784 rb->lcd_fillrect(j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
785 TILE_WIDTH, TILE_HEIGHT);
787 #else
788 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
789 rb->lcd_fillrect(j*TILE_WIDTH, (i-1)*TILE_HEIGHT+YOFS,
790 TILE_WIDTH, TILE_HEIGHT);
791 if(bj->playboard[i+1][j].type == 0) {
792 rb->lcd_fillrect(j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
793 TILE_WIDTH, TILE_HEIGHT);
795 rb->lcd_set_drawmode(DRMODE_SOLID);
796 #endif
798 /* draw new position */
799 #ifdef HAVE_LCD_COLOR
800 rb->lcd_bitmap_transparent_part(jewels, 0,
801 TILE_HEIGHT*(bj->playboard[i][j].type),
802 TILE_WIDTH, j*TILE_WIDTH,
803 (i-1)*TILE_HEIGHT+YOFS+
804 ((((TILE_HEIGHT<<10)*k)/8)>>10),
805 TILE_WIDTH, TILE_HEIGHT);
806 #else
807 rb->lcd_bitmap_part(jewels, 0,
808 TILE_HEIGHT*(bj->playboard[i][j].type),
809 TILE_WIDTH, j*TILE_WIDTH,
810 (i-1)*TILE_HEIGHT+YOFS+
811 ((((TILE_HEIGHT<<10)*k)/8)>>10),
812 TILE_WIDTH, TILE_HEIGHT);
813 #endif
818 rb->lcd_update_rect(0, 0, TILE_WIDTH*8, LCD_HEIGHT);
819 jewels_setcolors();
821 /* framerate limiting */
822 currenttick = *rb->current_tick;
823 if(currenttick-lasttick < HZ/MAX_FPS) {
824 rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick));
825 } else {
826 rb->yield();
828 lasttick = currenttick;
831 /* shift jewels down */
832 for(j=0; j<BJ_WIDTH; j++) {
833 for(i=BJ_HEIGHT-1; i>=1; i--) {
834 if(bj->playboard[i-1][j].falling) {
835 bj->playboard[i][j].type = bj->playboard[i-1][j].type;
840 /* clear out top row */
841 for(j=0; j<BJ_WIDTH; j++) {
842 bj->playboard[0][j].type = 0;
845 /* mark everything not falling */
846 for(i=0; i<BJ_HEIGHT; i++) {
847 for(j=0; j<BJ_WIDTH; j++) {
848 bj->playboard[i][j].falling = false;
854 /*****************************************************************************
855 * jewels_clearjewels() finds all the connected rows and columns and
856 * calculates and returns the points earned.
857 ******************************************************************************/
858 static unsigned int jewels_clearjewels(struct game_context* bj) {
859 int i, j;
860 int last, run;
861 unsigned int points = 0;
863 /* check for connected rows */
864 for(i=1; i<BJ_HEIGHT; i++) {
865 last = 0;
866 run = 1;
867 for(j=0; j<BJ_WIDTH; j++) {
868 if(bj->playboard[i][j].type == last &&
869 bj->playboard[i][j].type != 0 &&
870 bj->playboard[i][j].type <= MAX_NUM_JEWELS) {
871 run++;
873 if(run == 3) {
874 bj->segments++;
875 points += bj->segments;
876 bj->playboard[i][j].delete = true;
877 bj->playboard[i][j-1].delete = true;
878 bj->playboard[i][j-2].delete = true;
879 } else if(run > 3) {
880 points++;
881 bj->playboard[i][j].delete = true;
883 } else {
884 run = 1;
885 last = bj->playboard[i][j].type;
890 /* check for connected columns */
891 for(j=0; j<BJ_WIDTH; j++) {
892 last = 0;
893 run = 1;
894 for(i=1; i<BJ_HEIGHT; i++) {
895 if(bj->playboard[i][j].type != 0 &&
896 bj->playboard[i][j].type == last &&
897 bj->playboard[i][j].type <= MAX_NUM_JEWELS) {
898 run++;
900 if(run == 3) {
901 bj->segments++;
902 points += bj->segments;
903 bj->playboard[i][j].delete = true;
904 bj->playboard[i-1][j].delete = true;
905 bj->playboard[i-2][j].delete = true;
906 } else if(run > 3) {
907 points++;
908 bj->playboard[i][j].delete = true;
910 } else {
911 run = 1;
912 last = bj->playboard[i][j].type;
917 /* clear deleted jewels */
918 for(i=1; i<BJ_HEIGHT; i++) {
919 for(j=0; j<BJ_WIDTH; j++) {
920 if(bj->playboard[i][j].delete) {
921 bj->playboard[i][j].delete = false;
922 bj->playboard[i][j].type = 0;
927 return points;
930 /*****************************************************************************
931 * jewels_runboard() runs the board until it settles in a fixed state and
932 * returns points earned.
933 ******************************************************************************/
934 static unsigned int jewels_runboard(struct game_context* bj) {
935 unsigned int points = 0;
936 unsigned int ret;
938 bj->segments = 0;
940 while((ret = jewels_clearjewels(bj)) > 0) {
941 points += ret;
942 jewels_drawboard(bj);
943 jewels_putjewels(bj);
946 return points;
949 /*****************************************************************************
950 * jewels_swapjewels() swaps two jewels as long as it results in points and
951 * returns points earned.
952 ******************************************************************************/
953 static unsigned int jewels_swapjewels(struct game_context* bj,
954 int x, int y, int direc) {
955 int k;
956 int horzmod, vertmod;
957 int movelen = 0;
958 bool undo = false;
959 unsigned int points = 0;
960 long lasttick, currenttick;
962 /* check for invalid parameters */
963 if(x < 0 || x >= BJ_WIDTH || y < 0 || y >= BJ_HEIGHT-1 ||
964 direc < SWAP_UP || direc > SWAP_LEFT) {
965 return 0;
968 /* check for invalid directions */
969 if((x == 0 && direc == SWAP_LEFT) ||
970 (x == BJ_WIDTH-1 && direc == SWAP_RIGHT) ||
971 (y == 0 && direc == SWAP_UP) ||
972 (y == BJ_HEIGHT-2 && direc == SWAP_DOWN)) {
973 return 0;
976 /* set direction variables */
977 horzmod = 0;
978 vertmod = 0;
979 switch(direc) {
980 case SWAP_UP:
981 vertmod = -1;
982 movelen = TILE_HEIGHT;
983 break;
984 case SWAP_RIGHT:
985 horzmod = 1;
986 movelen = TILE_WIDTH;
987 break;
988 case SWAP_DOWN:
989 vertmod = 1;
990 movelen = TILE_HEIGHT;
991 break;
992 case SWAP_LEFT:
993 horzmod = -1;
994 movelen = TILE_WIDTH;
995 break;
998 while(true) {
999 lasttick = *rb->current_tick;
1001 /* animate swapping jewels */
1002 for(k=0; k<=8; k++) {
1003 /* clear old position */
1004 #ifdef HAVE_LCD_COLOR
1005 rb->lcd_set_foreground(jewels_bkgd[(x+y)%2]);
1006 rb->lcd_fillrect(x*TILE_WIDTH,
1007 y*TILE_HEIGHT+YOFS,
1008 TILE_WIDTH, TILE_HEIGHT);
1009 rb->lcd_set_foreground(jewels_bkgd[(x+horzmod+y+vertmod)%2]);
1010 rb->lcd_fillrect((x+horzmod)*TILE_WIDTH,
1011 (y+vertmod)*TILE_HEIGHT+YOFS,
1012 TILE_WIDTH, TILE_HEIGHT);
1013 #else
1014 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1015 rb->lcd_fillrect(x*TILE_WIDTH,
1016 y*TILE_HEIGHT+YOFS,
1017 TILE_WIDTH, TILE_HEIGHT);
1018 rb->lcd_fillrect((x+horzmod)*TILE_WIDTH,
1019 (y+vertmod)*TILE_HEIGHT+YOFS,
1020 TILE_WIDTH, TILE_HEIGHT);
1021 rb->lcd_set_drawmode(DRMODE_SOLID);
1022 #endif
1023 /* draw new position */
1024 #ifdef HAVE_LCD_COLOR
1025 rb->lcd_bitmap_transparent_part(jewels,
1026 0, TILE_HEIGHT*(bj->playboard
1027 [y+1+vertmod][x+horzmod].type), TILE_WIDTH,
1028 (x+horzmod)*TILE_WIDTH-horzmod*
1029 ((((movelen<<10)*k)/8)>>10),
1030 (y+vertmod)*TILE_HEIGHT-vertmod*
1031 ((((movelen<<10)*k)/8)>>10)+YOFS,
1032 TILE_WIDTH, TILE_HEIGHT);
1033 rb->lcd_bitmap_transparent_part(jewels,
1034 0, TILE_HEIGHT*(bj->playboard[y+1][x].type),
1035 TILE_WIDTH, x*TILE_WIDTH+horzmod*
1036 ((((movelen<<10)*k)/8)>>10),
1037 y*TILE_HEIGHT+vertmod*
1038 ((((movelen<<10)*k)/8)>>10)+YOFS,
1039 TILE_WIDTH, TILE_HEIGHT);
1040 #else
1041 rb->lcd_bitmap_part(jewels,
1042 0, TILE_HEIGHT*(bj->playboard
1043 [y+1+vertmod][x+horzmod].type), TILE_WIDTH,
1044 (x+horzmod)*TILE_WIDTH-horzmod*
1045 ((((movelen<<10)*k)/8)>>10),
1046 (y+vertmod)*TILE_HEIGHT-vertmod*
1047 ((((movelen<<10)*k)/8)>>10)+YOFS,
1048 TILE_WIDTH, TILE_HEIGHT);
1049 rb->lcd_set_drawmode(DRMODE_FG);
1050 rb->lcd_bitmap_part(jewels,
1051 0, TILE_HEIGHT*(bj->playboard[y+1][x].type),
1052 TILE_WIDTH, x*TILE_WIDTH+horzmod*
1053 ((((movelen<<10)*k)/8)>>10),
1054 y*TILE_HEIGHT+vertmod*
1055 ((((movelen<<10)*k)/8)>>10)+YOFS,
1056 TILE_WIDTH, TILE_HEIGHT);
1057 rb->lcd_set_drawmode(DRMODE_SOLID);
1058 #endif
1060 rb->lcd_update_rect(0, 0, TILE_WIDTH*8, LCD_HEIGHT);
1061 jewels_setcolors();
1063 /* framerate limiting */
1064 currenttick = *rb->current_tick;
1065 if(currenttick-lasttick < HZ/MAX_FPS) {
1066 rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick));
1067 } else {
1068 rb->yield();
1070 lasttick = currenttick;
1073 /* swap jewels */
1074 int temp = bj->playboard[y+1][x].type;
1075 bj->playboard[y+1][x].type =
1076 bj->playboard[y+1+vertmod][x+horzmod].type;
1077 bj->playboard[y+1+vertmod][x+horzmod].type = temp;
1079 if(undo) break;
1081 points = jewels_runboard(bj);
1082 if(points == 0) {
1083 undo = true;
1084 } else {
1085 break;
1089 return points;
1092 /*****************************************************************************
1093 * jewels_movesavail() uses pattern matching to see if there are any
1094 * available move left.
1095 ******************************************************************************/
1096 static bool jewels_movesavail(struct game_context* bj) {
1097 int i, j;
1098 bool moves = false;
1099 int mytype;
1101 for(i=1; i<BJ_HEIGHT; i++) {
1102 for(j=0; j<BJ_WIDTH; j++) {
1103 mytype = bj->playboard[i][j].type;
1104 if(mytype == 0 || mytype > MAX_NUM_JEWELS) continue;
1106 /* check horizontal patterns */
1107 if(j <= BJ_WIDTH-3) {
1108 if(i > 1) {
1109 if(bj->playboard[i-1][j+1].type == mytype) {
1110 if(bj->playboard[i-1][j+2].type == mytype)
1111 {moves = true; break;}
1112 if(bj->playboard[i][j+2].type == mytype)
1113 {moves = true; break;}
1115 if(bj->playboard[i][j+1].type == mytype) {
1116 if(bj->playboard[i-1][j+2].type == mytype)
1117 {moves = true; break;}
1121 if(j <= BJ_WIDTH-4) {
1122 if(bj->playboard[i][j+3].type == mytype) {
1123 if(bj->playboard[i][j+1].type == mytype)
1124 {moves = true; break;}
1125 if(bj->playboard[i][j+2].type == mytype)
1126 {moves = true; break;}
1130 if(i < BJ_HEIGHT-1) {
1131 if(bj->playboard[i][j+1].type == mytype) {
1132 if(bj->playboard[i+1][j+2].type == mytype)
1133 {moves = true; break;}
1135 if(bj->playboard[i+1][j+1].type == mytype) {
1136 if(bj->playboard[i][j+2].type == mytype)
1137 {moves = true; break;}
1138 if(bj->playboard[i+1][j+2].type == mytype)
1139 {moves = true; break;}
1144 /* check vertical patterns */
1145 if(i <= BJ_HEIGHT-3) {
1146 if(j > 0) {
1147 if(bj->playboard[i+1][j-1].type == mytype) {
1148 if(bj->playboard[i+2][j-1].type == mytype)
1149 {moves = true; break;}
1150 if(bj->playboard[i+2][j].type == mytype)
1151 {moves = true; break;}
1153 if(bj->playboard[i+1][j].type == mytype) {
1154 if(bj->playboard[i+2][j-1].type == mytype)
1155 {moves = true; break;}
1159 if(i <= BJ_HEIGHT-4) {
1160 if(bj->playboard[i+3][j].type == mytype) {
1161 if(bj->playboard[i+1][j].type == mytype)
1162 {moves = true; break;}
1163 if(bj->playboard[i+2][j].type == mytype)
1164 {moves = true; break;}
1168 if(j < BJ_WIDTH-1) {
1169 if(bj->playboard[i+1][j].type == mytype) {
1170 if(bj->playboard[i+2][j+1].type == mytype)
1171 {moves = true; break;}
1173 if(bj->playboard[i+1][j+1].type == mytype) {
1174 if(bj->playboard[i+2][j].type == mytype)
1175 {moves = true; break;}
1176 if (bj->playboard[i+2][j+1].type == mytype)
1177 {moves = true; break;}
1183 if(moves) break;
1186 return moves;
1189 /*****************************************************************************
1190 * jewels_puzzle_is_finished(bj) checks if the puzzle is finished.
1191 ******************************************************************************/
1192 static int jewels_puzzle_is_finished(struct game_context* bj) {
1193 unsigned int i, j;
1194 for(i=0; i<BJ_HEIGHT; i++) {
1195 for(j=0; j<BJ_WIDTH; j++) {
1196 int mytype = bj->playboard[i][j].type;
1197 if(mytype>MAX_NUM_JEWELS) {
1198 mytype -= MAX_NUM_JEWELS;
1199 if(mytype&PUZZLE_TILE_UP) {
1200 if(i==0 || bj->playboard[i-1][j].type<=MAX_NUM_JEWELS ||
1201 !((bj->playboard[i-1][j].type-MAX_NUM_JEWELS)
1202 &PUZZLE_TILE_DOWN))
1203 return 0;
1205 if(mytype&PUZZLE_TILE_DOWN) {
1206 if(i==BJ_HEIGHT-1 ||
1207 bj->playboard[i+1][j].type<=MAX_NUM_JEWELS ||
1208 !((bj->playboard[i+1][j].type-MAX_NUM_JEWELS)
1209 &PUZZLE_TILE_UP))
1210 return 0;
1212 if(mytype&PUZZLE_TILE_LEFT) {
1213 if(j==0 || bj->playboard[i][j-1].type<=MAX_NUM_JEWELS ||
1214 !((bj->playboard[i][j-1].type-MAX_NUM_JEWELS)
1215 &PUZZLE_TILE_RIGHT))
1216 return 0;
1218 if(mytype&PUZZLE_TILE_RIGHT) {
1219 if(j==BJ_WIDTH-1 ||
1220 bj->playboard[i][j+1].type<=MAX_NUM_JEWELS ||
1221 !((bj->playboard[i][j+1].type-MAX_NUM_JEWELS)
1222 &PUZZLE_TILE_LEFT))
1223 return 0;
1228 return 1;
1231 /*****************************************************************************
1232 * jewels_initlevel() initialises a level.
1233 ******************************************************************************/
1234 static unsigned int jewels_initlevel(struct game_context* bj) {
1235 unsigned int points = 0;
1237 switch(bj->type) {
1238 case GAME_TYPE_NORMAL:
1239 bj->num_jewels = MAX_NUM_JEWELS;
1240 break;
1242 case GAME_TYPE_PUZZLE:
1244 unsigned int i, j;
1245 struct puzzle_tile *tile;
1247 bj->num_jewels = puzzle_levels[bj->level-1].num_jewels;
1249 for(i=0; i<BJ_HEIGHT; i++) {
1250 for(j=0; j<BJ_WIDTH; j++) {
1251 bj->playboard[i][j].type = (rb->rand()%bj->num_jewels)+1;
1252 bj->playboard[i][j].falling = false;
1253 bj->playboard[i][j].delete = false;
1256 jewels_runboard(bj);
1257 tile = puzzle_levels[bj->level-1].tiles;
1258 for(i=0; i<puzzle_levels[bj->level-1].num_tiles; i++, tile++) {
1259 bj->playboard[tile->y+1][tile->x].type = MAX_NUM_JEWELS
1260 +tile->tile_type;
1263 break;
1266 jewels_drawboard(bj);
1268 /* run the play board */
1269 jewels_putjewels(bj);
1270 points += jewels_runboard(bj);
1271 return points;
1274 /*****************************************************************************
1275 * jewels_nextlevel() advances the game to the next level and returns
1276 * points earned.
1277 ******************************************************************************/
1278 static void jewels_nextlevel(struct game_context* bj) {
1279 int i, x, y;
1280 unsigned int points = 0;
1282 switch(bj->type) {
1283 case GAME_TYPE_NORMAL:
1284 /* roll over score, change and display level */
1285 while(bj->score >= LEVEL_PTS) {
1286 bj->score -= LEVEL_PTS;
1287 bj->level++;
1288 rb->splashf(HZ*2, "Level %d", bj->level);
1289 jewels_drawboard(bj);
1292 /* randomly clear some jewels */
1293 for(i=0; i<16; i++) {
1294 x = rb->rand()%8;
1295 y = rb->rand()%8;
1297 if(bj->playboard[y][x].type != 0) {
1298 points++;
1299 bj->playboard[y][x].type = 0;
1302 break;
1304 case GAME_TYPE_PUZZLE:
1305 bj->level++;
1306 if(bj->level>NUM_PUZZLE_LEVELS) {
1307 rb->splash(HZ*2, "You win!");
1308 bj->level = 1;
1309 } else {
1310 rb->splashf(HZ*2, "Level %d", bj->level);
1312 break;
1315 points += jewels_initlevel(bj);
1316 bj->score += points;
1319 /*****************************************************************************
1320 * jewels_recordscore() inserts a high score into the high scores list and
1321 * returns the high score position.
1322 ******************************************************************************/
1323 static int jewels_recordscore(struct game_context* bj) {
1324 int i;
1325 int position = 0;
1326 unsigned int current, temp;
1328 /* calculate total score */
1329 current = (bj->level-1)*LEVEL_PTS+bj->score;
1330 if(current <= 0) return 0;
1332 /* insert the current score into the high scores */
1333 for(i=0; i<NUM_SCORES; i++) {
1334 if(current >= bj->highscores[i]) {
1335 if(!position) {
1336 position = i+1;
1337 bj->dirty = true;
1339 temp = bj->highscores[i];
1340 bj->highscores[i] = current;
1341 current = temp;
1345 return position;
1348 /*****************************************************************************
1349 * jewels_loadscores() loads the high scores saved file.
1350 ******************************************************************************/
1351 static void jewels_loadscores(struct game_context* bj) {
1352 int fd;
1354 bj->dirty = false;
1356 /* clear high scores */
1357 rb->memset(bj->highscores, 0, sizeof(bj->highscores));
1359 /* open scores file */
1360 fd = rb->open(SCORE_FILE, O_RDONLY);
1361 if(fd < 0) return;
1363 /* read in high scores */
1364 if(rb->read(fd, bj->highscores, sizeof(bj->highscores)) <= 0) {
1365 /* scores are bad, reset */
1366 rb->memset(bj->highscores, 0, sizeof(bj->highscores));
1369 rb->close(fd);
1372 /*****************************************************************************
1373 * jewels_savescores() saves the high scores saved file.
1374 ******************************************************************************/
1375 static void jewels_savescores(struct game_context* bj) {
1376 int fd;
1378 /* write out the high scores to the save file */
1379 fd = rb->open(SCORE_FILE, O_WRONLY|O_CREAT);
1380 rb->write(fd, bj->highscores, sizeof(bj->highscores));
1381 rb->close(fd);
1382 bj->dirty = false;
1385 /*****************************************************************************
1386 * jewels_loadgame() loads the saved game and returns load success.
1387 ******************************************************************************/
1388 static bool jewels_loadgame(struct game_context* bj) {
1389 int fd;
1390 bool loaded = false;
1392 /* open game file */
1393 fd = rb->open(SAVE_FILE, O_RDONLY);
1394 if(fd < 0) return loaded;
1396 /* read in saved game */
1397 while(true) {
1398 if(rb->read(fd, &bj->score, sizeof(bj->score)) <= 0) break;
1399 if(rb->read(fd, &bj->level, sizeof(bj->level)) <= 0) break;
1400 if(rb->read(fd, &bj->type, sizeof(bj->type)) <= 0) break;
1401 if(rb->read(fd, bj->playboard, sizeof(bj->playboard)) <= 0) break;
1402 bj->resume = true;
1403 loaded = true;
1404 break;
1407 rb->close(fd);
1409 /* delete saved file */
1410 rb->remove(SAVE_FILE);
1411 return loaded;
1414 /*****************************************************************************
1415 * jewels_savegame() saves the current game state.
1416 ******************************************************************************/
1417 static void jewels_savegame(struct game_context* bj) {
1418 int fd;
1420 /* write out the game state to the save file */
1421 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
1422 rb->write(fd, &bj->score, sizeof(bj->score));
1423 rb->write(fd, &bj->level, sizeof(bj->level));
1424 rb->write(fd, &bj->type, sizeof(bj->type));
1425 rb->write(fd, bj->playboard, sizeof(bj->playboard));
1426 rb->close(fd);
1428 bj->resume = true;
1431 /*****************************************************************************
1432 * jewels_callback() is the default event handler callback which is called
1433 * on usb connect and shutdown.
1434 ******************************************************************************/
1435 static void jewels_callback(void* param) {
1436 struct game_context* bj = (struct game_context*) param;
1437 if(bj->dirty) {
1438 rb->splash(HZ, "Saving high scores...");
1439 jewels_savescores(bj);
1443 /*****************************************************************************
1444 * jewels_main() is the main game subroutine, it returns the final game status.
1445 ******************************************************************************/
1446 static int jewels_main(struct game_context* bj) {
1447 int i, j;
1448 int w, h;
1449 int button;
1450 char str[18];
1451 bool startgame = false;
1452 bool inmenu = false;
1453 bool selected = false;
1454 enum menu_cmd cmd = MCMD_NONE;
1455 enum menu_result res;
1457 /* the cursor coordinates */
1458 int x=0, y=0;
1460 /* don't resume by default */
1461 bj->resume = false;
1463 /********************
1464 * menu *
1465 ********************/
1466 rb->lcd_clear_display();
1468 while(!startgame) {
1469 res = jewels_showmenu(&bjmenu[0], cmd);
1470 cmd = MCMD_NONE;
1472 rb->snprintf(str, 18, "High Score: %d", bj->highscores[0]);
1473 rb->lcd_getstringsize(str, &w, &h);
1474 rb->lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT-8, str);
1475 rb->lcd_update();
1477 rb->yield();
1479 switch(res) {
1480 case MRES_NEW:
1481 startgame = true;
1482 bj->type = GAME_TYPE_NORMAL;
1483 continue;
1485 case MRES_PUZZLE:
1486 startgame = true;
1487 bj->type = GAME_TYPE_PUZZLE;
1488 continue;
1490 case MRES_RESUME:
1491 if(!jewels_loadgame(bj)) {
1492 rb->splash(HZ*2, "Nothing to resume");
1493 rb->lcd_clear_display();
1494 } else {
1495 startgame = true;
1497 continue;
1499 case MRES_SCORES:
1500 rb->lcd_clear_display();
1502 /* room for a title? */
1503 j = 0;
1504 if(LCD_HEIGHT-NUM_SCORES*8 >= 8) {
1505 rb->snprintf(str, 12, "%s", "High Scores");
1506 rb->lcd_getstringsize(str, &w, &h);
1507 rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, str);
1508 j = 2;
1511 /* print high scores */
1512 for(i=0; i<NUM_SCORES; i++) {
1513 rb->snprintf(str, 11, "#%02d: %d", i+1, bj->highscores[i]);
1514 rb->lcd_puts(0, i+j, str);
1517 rb->lcd_update();
1518 while(true) {
1519 button = rb->button_get(true);
1520 if(button != BUTTON_NONE && !(button&BUTTON_REL)) break;
1521 rb->yield();
1523 rb->lcd_clear_display();
1524 continue;
1526 case MRES_HELP:
1527 /* welcome screen to display key bindings */
1528 rb->lcd_clear_display();
1529 rb->snprintf(str, 5, "%s", "Help");
1530 rb->lcd_getstringsize(str, &w, &h);
1531 rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, str);
1532 #if CONFIG_KEYPAD == RECORDER_PAD
1533 rb->lcd_puts(0, 2, "Controls:");
1534 rb->lcd_puts(0, 3, "Directions = move");
1535 rb->lcd_puts(0, 4, "PLAY = select");
1536 rb->lcd_puts(0, 5, "Long PLAY = menu");
1537 rb->lcd_puts(0, 6, "OFF = cancel");
1538 #elif CONFIG_KEYPAD == ONDIO_PAD
1539 rb->lcd_puts(0, 2, "Controls:");
1540 rb->lcd_puts(0, 3, "Directions = move");
1541 rb->lcd_puts(0, 4, "MENU = select");
1542 rb->lcd_puts(0, 5, "Long MENU = menu");
1543 rb->lcd_puts(0, 6, "OFF = cancel");
1544 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
1545 rb->lcd_puts(0, 2, "Controls:");
1546 rb->lcd_puts(0, 3, "Directions = move");
1547 rb->lcd_puts(0, 4, "SELECT = select");
1548 rb->lcd_puts(0, 5, "Long SELECT = menu");
1549 rb->lcd_puts(0, 6, "PLAY = cancel");
1550 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
1551 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1552 rb->lcd_puts(0, 3, "form connected segments");
1553 rb->lcd_puts(0, 4, "of three or more of the");
1554 rb->lcd_puts(0, 5, "same type.");
1555 rb->lcd_puts(0, 7, "Controls:");
1556 rb->lcd_puts(0, 8, "Directions to move");
1557 rb->lcd_puts(0, 9, "SELECT to select");
1558 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1559 rb->lcd_puts(0, 11, "OFF to cancel");
1560 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1561 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1562 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1563 rb->lcd_puts(0, 3, "form connected segments");
1564 rb->lcd_puts(0, 4, "of three or more of the");
1565 rb->lcd_puts(0, 5, "same type.");
1566 rb->lcd_puts(0, 7, "Controls:");
1567 rb->lcd_puts(0, 8, "Directions or scroll to move");
1568 rb->lcd_puts(0, 9, "SELECT to select");
1569 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1570 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
1571 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1572 rb->lcd_puts(0, 3, "form connected segments");
1573 rb->lcd_puts(0, 4, "of three or more of the");
1574 rb->lcd_puts(0, 5, "same type.");
1575 rb->lcd_puts(0, 7, "Controls:");
1576 rb->lcd_puts(0, 8, "Directions to move");
1577 rb->lcd_puts(0, 9, "SELECT to select");
1578 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1579 rb->lcd_puts(0, 11, "PLAY to cancel");
1580 #elif CONFIG_KEYPAD == GIGABEAT_PAD \
1581 || CONFIG_KEYPAD == MROBE100_PAD
1582 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1583 rb->lcd_puts(0, 3, "form connected segments");
1584 rb->lcd_puts(0, 4, "of three or more of the");
1585 rb->lcd_puts(0, 5, "same type.");
1586 rb->lcd_puts(0, 7, "Controls:");
1587 rb->lcd_puts(0, 8, "Directions to move");
1588 rb->lcd_puts(0, 9, "SELECT to select");
1589 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1590 rb->lcd_puts(0, 11, "POWER to cancel");
1591 #elif CONFIG_KEYPAD == SANSA_E200_PAD \
1592 || CONFIG_KEYPAD == SANSA_C200_PAD \
1593 || CONFIG_KEYPAD == SANSA_CLIP_PAD \
1594 || CONFIG_KEYPAD == SANSA_FUZE_PAD \
1595 || CONFIG_KEYPAD == SANSA_M200_PAD
1596 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1597 rb->lcd_puts(0, 3, "form connected segments");
1598 rb->lcd_puts(0, 4, "of three or more of the");
1599 rb->lcd_puts(0, 5, "same type.");
1600 rb->lcd_puts(0, 7, "Controls:");
1601 rb->lcd_puts(0, 8, "Directions to move");
1602 rb->lcd_puts(0, 9, "SELECT to select");
1603 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1604 rb->lcd_puts(0, 11, "POWER to cancel");
1605 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1606 rb->lcd_puts(0, 2, "Swap pairs of jewels");
1607 rb->lcd_puts(0, 3, "to form connected");
1608 rb->lcd_puts(0, 4, "segments of three or ");
1609 rb->lcd_puts(0, 5, "more of the");
1610 rb->lcd_puts(0, 6, "same type.");
1611 rb->lcd_puts(0, 8, "Controls:");
1612 rb->lcd_puts(0, 9, "Directions or scroll to move");
1613 rb->lcd_puts(0, 10, "PLAY to select");
1614 rb->lcd_puts(0, 11, "Long PLAY for menu");
1615 rb->lcd_puts(0, 12, "POWER to cancel");
1616 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1617 rb->lcd_puts(0, 2, "Swap pairs of jewels");
1618 rb->lcd_puts(0, 3, "to form connected");
1619 rb->lcd_puts(0, 4, "segments of three or ");
1620 rb->lcd_puts(0, 5, "more of the");
1621 rb->lcd_puts(0, 6, "same type.");
1622 rb->lcd_puts(0, 8, "Controls:");
1623 rb->lcd_puts(0, 9, "Directions or scroll to move");
1624 rb->lcd_puts(0, 10, "PLAY to select");
1625 rb->lcd_puts(0, 11, "Long PLAY for menu");
1626 rb->lcd_puts(0, 12, "REC to cancel");
1627 #elif CONFIG_KEYPAD == COWOND2_PAD
1628 rb->lcd_puts(0, 11, "POWER to cancel");
1629 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
1630 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1631 rb->lcd_puts(0, 3, "form connected segments");
1632 rb->lcd_puts(0, 4, "of three or more of the");
1633 rb->lcd_puts(0, 5, "same type.");
1634 rb->lcd_puts(0, 7, "Controls:");
1635 rb->lcd_puts(0, 8, "Directions to move");
1636 rb->lcd_puts(0, 9, "SELECT to select");
1637 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1638 rb->lcd_puts(0, 11, "BACK to cancel");
1639 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
1640 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1641 rb->lcd_puts(0, 3, "form connected segments");
1642 rb->lcd_puts(0, 4, "of three or more of the");
1643 rb->lcd_puts(0, 5, "same type.");
1644 rb->lcd_puts(0, 7, "Controls:");
1645 rb->lcd_puts(0, 8, "Directions to move");
1646 rb->lcd_puts(0, 9, "MIDDLE to select");
1647 rb->lcd_puts(0, 10, "Long MIDDLE to show menu");
1648 rb->lcd_puts(0, 11, "BACK to cancel");
1649 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
1650 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1651 rb->lcd_puts(0, 3, "form connected segments");
1652 rb->lcd_puts(0, 4, "of three or more of the");
1653 rb->lcd_puts(0, 5, "same type.");
1654 rb->lcd_puts(0, 7, "Controls:");
1655 rb->lcd_puts(0, 8, "Directions to move");
1656 rb->lcd_puts(0, 9, "SELECT/PLAY to select");
1657 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1658 rb->lcd_puts(0, 11, "POWER to cancel");
1659 #else
1660 #warning: missing help text.
1661 #endif
1663 #ifdef HAVE_TOUCHSCREEN
1664 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1665 rb->lcd_puts(0, 3, "form connected segments");
1666 rb->lcd_puts(0, 4, "of three or more of the");
1667 rb->lcd_puts(0, 5, "same type.");
1668 rb->lcd_puts(0, 7, "Controls:");
1669 rb->lcd_puts(0, 8, "Directions to move");
1670 rb->lcd_puts(0, 9, "CENTER to select");
1671 rb->lcd_puts(0, 10, "Long CENTER to show menu");
1672 #endif
1673 rb->lcd_update();
1674 while(true) {
1675 button = rb->button_get(true);
1676 if(button != BUTTON_NONE && !(button&BUTTON_REL)) break;
1678 rb->lcd_clear_display();
1679 continue;
1681 case MRES_QUIT:
1682 return BJ_QUIT;
1684 default:
1685 break;
1688 /* handle menu button presses */
1689 button = rb->button_get(true);
1690 switch(button){
1691 #ifdef JEWELS_SCROLLWHEEL
1692 case JEWELS_PREV:
1693 case (JEWELS_PREV|BUTTON_REPEAT):
1694 #endif
1695 case JEWELS_UP:
1696 case (JEWELS_UP|BUTTON_REPEAT):
1697 cmd = MCMD_PREV;
1698 break;
1700 #ifdef JEWELS_SCROLLWHEEL
1701 case JEWELS_NEXT:
1702 case (JEWELS_NEXT|BUTTON_REPEAT):
1703 #endif
1704 case JEWELS_DOWN:
1705 case (JEWELS_DOWN|BUTTON_REPEAT):
1706 cmd = MCMD_NEXT;
1707 break;
1709 case JEWELS_SELECT:
1710 case JEWELS_RIGHT:
1711 cmd = MCMD_SELECT;
1712 break;
1714 #ifdef JEWELS_CANCEL
1715 #ifdef JEWELS_RC_CANCEL
1716 case JEWELS_RC_CANCEL:
1717 #endif
1718 case JEWELS_CANCEL:
1719 return BJ_QUIT;
1720 #endif
1722 default:
1723 if(rb->default_event_handler_ex(button, jewels_callback,
1724 (void*) bj) == SYS_USB_CONNECTED)
1725 return BJ_USB;
1726 break;
1730 /********************
1731 * init *
1732 ********************/
1733 jewels_init(bj);
1735 /********************
1736 * setup the board *
1737 ********************/
1738 bj->score += jewels_initlevel(bj);
1739 if (!jewels_movesavail(bj)) {
1740 switch(bj->type) {
1741 case GAME_TYPE_NORMAL:
1742 return BJ_LOSE;
1744 case GAME_TYPE_PUZZLE:
1745 do {
1746 rb->splash(2*HZ, "No more moves!");
1747 bj->score += jewels_initlevel(bj);
1748 } while(!jewels_movesavail(bj));
1749 break;
1753 /**********************
1754 * play *
1755 **********************/
1756 while(true) {
1757 int no_movesavail = false;
1759 if(!inmenu) {
1760 /* refresh the board */
1761 jewels_drawboard(bj);
1763 /* display the cursor */
1764 if(selected) {
1765 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1766 rb->lcd_fillrect(x*TILE_WIDTH, y*TILE_HEIGHT+YOFS,
1767 TILE_WIDTH, TILE_HEIGHT);
1768 rb->lcd_set_drawmode(DRMODE_SOLID);
1769 } else {
1770 rb->lcd_drawrect(x*TILE_WIDTH, y*TILE_HEIGHT+YOFS,
1771 TILE_WIDTH, TILE_HEIGHT);
1773 rb->lcd_update_rect(x*TILE_WIDTH, y*TILE_HEIGHT+YOFS,
1774 TILE_WIDTH, TILE_HEIGHT);
1775 } else {
1776 res = jewels_showmenu(&bjmenu[1], cmd);
1777 cmd = MCMD_NONE;
1778 switch(res) {
1779 case MRES_RESUME:
1780 inmenu = false;
1781 selected = false;
1782 continue;
1784 case MRES_PLAYBACK:
1785 playback_control(NULL);
1786 rb->lcd_setfont(FONT_SYSFIXED);
1787 inmenu = false;
1788 selected = false;
1789 break;
1791 case MRES_SAVE:
1792 rb->splash(HZ, "Saving game...");
1793 jewels_savegame(bj);
1794 return BJ_END;
1796 case MRES_QUIT:
1797 return BJ_END;
1799 case MRES_EXIT:
1800 return BJ_QUIT_FROM_GAME;
1802 default:
1803 break;
1807 /* handle game button presses */
1808 rb->yield();
1809 button = rb->button_get(true);
1810 switch(button){
1811 case JEWELS_LEFT: /* move cursor left */
1812 case (JEWELS_LEFT|BUTTON_REPEAT):
1813 if(!inmenu) {
1814 if(selected) {
1815 bj->score += jewels_swapjewels(bj, x, y, SWAP_LEFT);
1816 selected = false;
1817 if (!jewels_movesavail(bj)) no_movesavail = true;
1818 } else {
1819 x = (x+BJ_WIDTH-1)%BJ_WIDTH;
1822 break;
1824 case JEWELS_RIGHT: /* move cursor right */
1825 case (JEWELS_RIGHT|BUTTON_REPEAT):
1826 if(!inmenu) {
1827 if(selected) {
1828 bj->score += jewels_swapjewels(bj, x, y, SWAP_RIGHT);
1829 selected = false;
1830 if (!jewels_movesavail(bj)) no_movesavail = true;
1831 } else {
1832 x = (x+1)%BJ_WIDTH;
1834 } else {
1835 cmd = MCMD_SELECT;
1837 break;
1839 case JEWELS_DOWN: /* move cursor down */
1840 case (JEWELS_DOWN|BUTTON_REPEAT):
1841 if(!inmenu) {
1842 if(selected) {
1843 bj->score += jewels_swapjewels(bj, x, y, SWAP_DOWN);
1844 selected = false;
1845 if (!jewels_movesavail(bj)) no_movesavail = true;
1846 } else {
1847 y = (y+1)%(BJ_HEIGHT-1);
1849 } else {
1850 cmd = MCMD_NEXT;
1852 break;
1854 case JEWELS_UP: /* move cursor up */
1855 case (JEWELS_UP|BUTTON_REPEAT):
1856 if(!inmenu) {
1857 if(selected) {
1858 bj->score += jewels_swapjewels(bj, x, y, SWAP_UP);
1859 selected = false;
1860 if (!jewels_movesavail(bj)) no_movesavail = true;
1861 } else {
1862 y = (y+(BJ_HEIGHT-1)-1)%(BJ_HEIGHT-1);
1864 } else {
1865 cmd = MCMD_PREV;
1867 break;
1869 #ifdef JEWELS_SCROLLWHEEL
1870 case JEWELS_PREV: /* scroll backwards */
1871 case (JEWELS_PREV|BUTTON_REPEAT):
1872 if(!inmenu) {
1873 if(!selected) {
1874 if(x == 0) {
1875 y = (y+(BJ_HEIGHT-1)-1)%(BJ_HEIGHT-1);
1877 x = (x+BJ_WIDTH-1)%BJ_WIDTH;
1879 } else {
1880 cmd = MCMD_PREV;
1882 break;
1884 case JEWELS_NEXT: /* scroll forwards */
1885 case (JEWELS_NEXT|BUTTON_REPEAT):
1886 if(!inmenu) {
1887 if(!selected) {
1888 if(x == BJ_WIDTH-1) {
1889 y = (y+1)%(BJ_HEIGHT-1);
1891 x = (x+1)%BJ_WIDTH;
1893 } else {
1894 cmd = MCMD_NEXT;
1896 break;
1897 #endif
1899 case JEWELS_SELECT: /* toggle selected */
1900 if(!inmenu) {
1901 selected = !selected;
1902 } else {
1903 cmd = MCMD_SELECT;
1905 break;
1907 case (JEWELS_SELECT|BUTTON_REPEAT): /* show menu */
1908 if(!inmenu) inmenu = true;
1909 break;
1911 #ifdef JEWELS_CANCEL
1912 #ifdef JEWELS_RC_CANCEL
1913 case JEWELS_RC_CANCEL:
1914 #endif
1915 case JEWELS_CANCEL: /* end game */
1916 return BJ_END;
1917 break;
1918 #endif
1920 default:
1921 if(rb->default_event_handler_ex(button, jewels_callback,
1922 (void*) bj) == SYS_USB_CONNECTED)
1923 return BJ_USB;
1924 break;
1927 if (no_movesavail) {
1928 switch(bj->type) {
1929 case GAME_TYPE_NORMAL:
1930 return BJ_LOSE;
1932 case GAME_TYPE_PUZZLE:
1933 do {
1934 rb->splash(2*HZ, "No more moves!");
1935 bj->score += jewels_initlevel(bj);
1936 } while(!jewels_movesavail(bj));
1937 break;
1941 switch(bj->type) {
1942 case GAME_TYPE_NORMAL:
1943 if(bj->score >= LEVEL_PTS)
1944 jewels_nextlevel(bj);
1945 break;
1947 case GAME_TYPE_PUZZLE:
1948 if(jewels_puzzle_is_finished(bj))
1949 jewels_nextlevel(bj);
1950 break;
1955 /*****************************************************************************
1956 * plugin entry point.
1957 ******************************************************************************/
1958 enum plugin_status plugin_start(const void* parameter) {
1959 struct game_context bj;
1960 bool exit = false;
1961 int position;
1962 char str[19];
1964 /* plugin init */
1965 (void)parameter;
1966 /* end of plugin init */
1968 /* load high scores */
1969 jewels_loadscores(&bj);
1971 rb->lcd_setfont(FONT_SYSFIXED);
1972 #if LCD_DEPTH > 1
1973 rb->lcd_set_backdrop(NULL);
1974 #endif
1975 jewels_setcolors();
1977 while(!exit) {
1978 switch(jewels_main(&bj)){
1979 case BJ_LOSE:
1980 rb->splash(HZ*2, "No more moves!");
1981 /* fall through to BJ_END */
1983 case BJ_END:
1984 if(!bj.resume) {
1985 if((position = jewels_recordscore(&bj))) {
1986 rb->snprintf(str, 19, "New high score #%d!", position);
1987 rb->splash(HZ*2, str);
1990 break;
1992 case BJ_USB:
1993 rb->lcd_setfont(FONT_UI);
1994 return PLUGIN_USB_CONNECTED;
1996 case BJ_QUIT:
1997 if(bj.dirty) {
1998 rb->splash(HZ, "Saving high scores...");
1999 jewels_savescores(&bj);
2001 exit = true;
2002 break;
2004 case BJ_QUIT_FROM_GAME:
2005 if(!bj.resume) {
2006 if((position = jewels_recordscore(&bj))) {
2007 rb->snprintf(str, 19, "New high score #%d!", position);
2008 rb->splash(HZ*2, str);
2011 if(bj.dirty) {
2012 rb->splash(HZ, "Saving high scores...");
2013 jewels_savescores(&bj);
2015 exit = true;
2016 break;
2018 default:
2019 break;
2023 rb->lcd_setfont(FONT_UI);
2024 return PLUGIN_OK;
2027 #endif /* HAVE_LCD_BITMAP */