Use the AMS_LOWMEM define to indicate memory size as the .lds files do in config...
[kugel-rb.git] / apps / plugins / jewels.c
blob6bf5fcf8acf58a4a203c674ba3b8ec019c73ea53
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 /* menu values */
334 #define FONT_HEIGHT 8
335 #define MAX_MITEMS 6
336 #define MENU_WIDTH 100
338 /* menu results */
339 enum menu_result {
340 MRES_NONE,
341 MRES_NEW,
342 MRES_PUZZLE,
343 MRES_SAVE,
344 MRES_RESUME,
345 MRES_SCORES,
346 MRES_HELP,
347 MRES_QUIT,
348 MRES_PLAYBACK,
349 MRES_EXIT
352 /* menu commands */
353 enum menu_cmd {
354 MCMD_NONE,
355 MCMD_NEXT,
356 MCMD_PREV,
357 MCMD_SELECT
360 /* menus */
361 struct jewels_menu {
362 char *title;
363 bool hasframe;
364 int selected;
365 int itemcnt;
366 struct jewels_menuitem {
367 char *text;
368 enum menu_result res;
369 } items[MAX_MITEMS];
370 } bjmenu[] = {
371 {"Jewels", false, 0, 6,
372 {{"New Game", MRES_NEW},
373 {"Puzzle", MRES_PUZZLE},
374 {"Resume Saved Game", MRES_RESUME},
375 {"High Scores", MRES_SCORES},
376 {"Help", MRES_HELP},
377 {"Quit", MRES_QUIT}}},
378 {"Menu", true, 0, 5,
379 {{"Audio Playback", MRES_PLAYBACK },
380 {"Resume Game", MRES_RESUME},
381 {"Save Game", MRES_SAVE},
382 {"End Game", MRES_QUIT},
383 {"Exit Jewels", MRES_EXIT}}}
386 /* external bitmaps */
387 extern const fb_data jewels[];
389 /* tile background colors */
390 #ifdef HAVE_LCD_COLOR
391 static const unsigned jewels_bkgd[2] = {
392 LCD_RGBPACK(104, 63, 63),
393 LCD_RGBPACK(83, 44, 44)
395 #endif
397 /* the tile struct
398 * type is the jewel number 0-7
399 * falling if the jewel is falling
400 * delete marks the jewel for deletion
402 struct tile {
403 int type;
404 bool falling;
405 bool delete;
408 /* the game context struct
409 * score is the current level score
410 * segments is the number of cleared segments in the current run
411 * level is the current level
412 * type is the game type (normal or puzzle)
413 * highscores is the list of high scores
414 * resume denotes whether to resume the currently loaded game
415 * dirty denotes whether the high scores are out of sync with the saved file
416 * playboard is the game playing board (first row is hidden)
417 * num_jewels is the number of different jewels to use
419 struct game_context {
420 unsigned int score;
421 unsigned int segments;
422 unsigned int level;
423 unsigned int type;
424 unsigned int highscores[NUM_SCORES];
425 bool resume;
426 bool dirty;
427 struct tile playboard[BJ_HEIGHT][BJ_WIDTH];
428 unsigned int num_jewels;
431 #define MAX_NUM_JEWELS 7
433 #define MAX_PUZZLE_TILES 4
434 #define NUM_PUZZLE_LEVELS 10
436 struct puzzle_tile {
437 int x;
438 int y;
439 int tile_type;
442 struct puzzle_level {
443 unsigned int num_jewels;
444 unsigned int num_tiles;
445 struct puzzle_tile tiles[MAX_PUZZLE_TILES];
448 #define PUZZLE_TILE_UP 1
449 #define PUZZLE_TILE_DOWN 2
450 #define PUZZLE_TILE_LEFT 4
451 #define PUZZLE_TILE_RIGHT 8
453 struct puzzle_level puzzle_levels[NUM_PUZZLE_LEVELS] = {
454 { 5, 2, { {3, 3, PUZZLE_TILE_RIGHT},
455 {4, 2, PUZZLE_TILE_LEFT} } },
456 { 5, 2, { {3, 2, PUZZLE_TILE_DOWN},
457 {3, 4, PUZZLE_TILE_UP} } },
458 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN},
459 {3, 4, PUZZLE_TILE_UP|PUZZLE_TILE_DOWN},
460 {3, 6, PUZZLE_TILE_UP} } },
461 { 6, 3, { {3, 2, PUZZLE_TILE_RIGHT},
462 {4, 3, PUZZLE_TILE_LEFT|PUZZLE_TILE_RIGHT},
463 {5, 4, PUZZLE_TILE_LEFT} } },
464 { 6, 2, { {3, 4, PUZZLE_TILE_RIGHT},
465 {4, 2, PUZZLE_TILE_LEFT} } },
466 { 6, 2, { {3, 2, PUZZLE_TILE_DOWN},
467 {4, 4, PUZZLE_TILE_UP} } },
468 { 7, 4, { {3, 2, PUZZLE_TILE_RIGHT|PUZZLE_TILE_DOWN},
469 {4, 3, PUZZLE_TILE_LEFT|PUZZLE_TILE_DOWN},
470 {3, 4, PUZZLE_TILE_RIGHT|PUZZLE_TILE_UP},
471 {4, 4, PUZZLE_TILE_LEFT|PUZZLE_TILE_UP} } },
472 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN},
473 {4, 4, PUZZLE_TILE_UP|PUZZLE_TILE_DOWN},
474 {3, 6, PUZZLE_TILE_UP} } },
475 { 7, 3, { {2, 2, PUZZLE_TILE_RIGHT},
476 {4, 1, PUZZLE_TILE_LEFT|PUZZLE_TILE_RIGHT},
477 {5, 4, PUZZLE_TILE_LEFT} } },
478 { 7, 4, { {3, 0, PUZZLE_TILE_RIGHT|PUZZLE_TILE_DOWN},
479 {5, 0, PUZZLE_TILE_LEFT|PUZZLE_TILE_DOWN},
480 {2, 7, PUZZLE_TILE_RIGHT|PUZZLE_TILE_UP},
481 {4, 7, PUZZLE_TILE_LEFT|PUZZLE_TILE_UP} } },
484 /*****************************************************************************
485 * jewels_init() initializes jewels data structures.
486 ******************************************************************************/
487 static void jewels_init(struct game_context* bj) {
488 /* seed the rand generator */
489 rb->srand(*rb->current_tick);
491 /* check for resumed game */
492 if(bj->resume) {
493 bj->resume = false;
494 return;
497 /* reset scoring */
498 bj->level = 1;
499 bj->score = 0;
500 bj->segments = 0;
502 /* clear playing board */
503 rb->memset(bj->playboard, 0, sizeof(bj->playboard));
506 /*****************************************************************************
507 * jewels_setcolors() set the foreground and background colors.
508 ******************************************************************************/
509 static inline void jewels_setcolors(void) {
510 #ifdef HAVE_LCD_COLOR
511 rb->lcd_set_background(LCD_RGBPACK(49, 26, 26));
512 rb->lcd_set_foreground(LCD_RGBPACK(210, 181, 181));
513 #endif
516 /*****************************************************************************
517 * jewels_drawboard() redraws the entire game board.
518 ******************************************************************************/
519 static void jewels_drawboard(struct game_context* bj) {
520 int i, j;
521 int w, h;
522 unsigned int tempscore;
523 char *title = "Level";
524 char str[10];
526 tempscore = (bj->score>LEVEL_PTS ? LEVEL_PTS : bj->score);
528 /* clear screen */
529 rb->lcd_clear_display();
531 /* dispay playing board */
532 for(i=0; i<BJ_HEIGHT-1; i++){
533 for(j=0; j<BJ_WIDTH; j++){
534 #ifdef HAVE_LCD_COLOR
535 rb->lcd_set_foreground(jewels_bkgd[(i+j)%2]);
536 rb->lcd_fillrect(j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
537 TILE_WIDTH, TILE_HEIGHT);
538 rb->lcd_bitmap_transparent_part(jewels,
539 0, TILE_HEIGHT*(bj->playboard[i+1][j].type),
540 TILE_WIDTH, j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
541 TILE_WIDTH, TILE_HEIGHT);
542 #else
543 rb->lcd_bitmap_part(jewels,
544 0, TILE_HEIGHT*(bj->playboard[i+1][j].type),
545 TILE_WIDTH, j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
546 TILE_WIDTH, TILE_HEIGHT);
547 #endif
551 #if LCD_WIDTH > LCD_HEIGHT /* horizontal layout */
553 /* draw separator lines */
554 jewels_setcolors();
555 rb->lcd_vline(BJ_WIDTH*TILE_WIDTH, 0, LCD_HEIGHT-1);
556 rb->lcd_hline(BJ_WIDTH*TILE_WIDTH, LCD_WIDTH-1, 18);
557 rb->lcd_hline(BJ_WIDTH*TILE_WIDTH, LCD_WIDTH-1, LCD_HEIGHT-10);
559 /* draw progress bar */
560 #ifdef HAVE_LCD_COLOR
561 rb->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
562 #endif
563 rb->lcd_fillrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
564 (LCD_HEIGHT-10)-(((LCD_HEIGHT-10)-18)*
565 tempscore/LEVEL_PTS),
566 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
567 ((LCD_HEIGHT-10)-18)*tempscore/LEVEL_PTS);
568 #ifdef HAVE_LCD_COLOR
569 rb->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
570 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4+1,
571 (LCD_HEIGHT-10)-(((LCD_HEIGHT-10)-18)*
572 tempscore/LEVEL_PTS)+1,
573 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-2,
574 ((LCD_HEIGHT-10)-18)*tempscore/LEVEL_PTS-1);
575 jewels_setcolors();
576 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
577 (LCD_HEIGHT-10)-(((LCD_HEIGHT-10)-18)*
578 tempscore/LEVEL_PTS),
579 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
580 ((LCD_HEIGHT-10)-18)*tempscore/LEVEL_PTS+1);
581 #endif
583 /* print text */
584 rb->lcd_getstringsize(title, &w, &h);
585 rb->lcd_putsxy(LCD_WIDTH-(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-w/2, 1, title);
587 rb->snprintf(str, 4, "%d", bj->level);
588 rb->lcd_getstringsize(str, &w, &h);
589 rb->lcd_putsxy(LCD_WIDTH-(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-w/2, 10, str);
591 rb->snprintf(str, 6, "%d", (bj->level-1)*LEVEL_PTS+bj->score);
592 rb->lcd_getstringsize(str, &w, &h);
593 rb->lcd_putsxy(LCD_WIDTH-(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-w/2,
594 LCD_HEIGHT-8, str);
596 #elif LCD_WIDTH < LCD_HEIGHT /* vertical layout */
598 /* draw separator lines */
599 jewels_setcolors();
600 rb->lcd_hline(0, LCD_WIDTH-1, 8*TILE_HEIGHT+YOFS);
601 rb->lcd_hline(0, LCD_WIDTH-1, LCD_HEIGHT-14);
602 rb->lcd_vline(LCD_WIDTH/2, LCD_HEIGHT-14, LCD_HEIGHT-1);
604 /* draw progress bar */
605 #ifdef HAVE_LCD_COLOR
606 rb->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
607 #endif
608 rb->lcd_fillrect(0, (8*TILE_HEIGHT+YOFS)
609 +(LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/4,
610 LCD_WIDTH*tempscore/LEVEL_PTS,
611 (LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/2);
612 #ifdef HAVE_LCD_COLOR
613 rb->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
614 rb->lcd_drawrect(1, (8*TILE_HEIGHT+YOFS)
615 +(LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/4+1,
616 LCD_WIDTH*tempscore/LEVEL_PTS-1,
617 (LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/2-2);
618 jewels_setcolors();
619 rb->lcd_drawrect(0, (8*TILE_HEIGHT+YOFS)
620 +(LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/4,
621 LCD_WIDTH*tempscore/LEVEL_PTS+1,
622 (LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/2);
623 #endif
625 /* print text */
626 rb->snprintf(str, 10, "%s %d", title, bj->level);
627 rb->lcd_putsxy(1, LCD_HEIGHT-10, str);
629 rb->snprintf(str, 6, "%d", (bj->level-1)*LEVEL_PTS+bj->score);
630 rb->lcd_getstringsize(str, &w, &h);
631 rb->lcd_putsxy((LCD_WIDTH-2)-w, LCD_HEIGHT-10, str);
633 #else /* square layout */
635 /* draw separator lines */
636 jewels_setcolors();
637 rb->lcd_hline(0, LCD_WIDTH-1, 8*TILE_HEIGHT+YOFS);
638 rb->lcd_vline(BJ_WIDTH*TILE_WIDTH, 0, 8*TILE_HEIGHT+YOFS);
639 rb->lcd_vline(LCD_WIDTH/2, 8*TILE_HEIGHT+YOFS, LCD_HEIGHT-1);
641 /* draw progress bar */
642 #ifdef HAVE_LCD_COLOR
643 rb->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
644 #endif
645 rb->lcd_fillrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
646 (8*TILE_HEIGHT+YOFS)-(8*TILE_HEIGHT+YOFS)
647 *tempscore/LEVEL_PTS,
648 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
649 (8*TILE_HEIGHT+YOFS)*tempscore/LEVEL_PTS);
650 #ifdef HAVE_LCD_COLOR
651 rb->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
652 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4+1,
653 (8*TILE_HEIGHT+YOFS)-(8*TILE_HEIGHT+YOFS)
654 *tempscore/LEVEL_PTS+1,
655 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-2,
656 (8*TILE_HEIGHT+YOFS)*tempscore/LEVEL_PTS-1);
657 jewels_setcolors();
658 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
659 (8*TILE_HEIGHT+YOFS)-(8*TILE_HEIGHT+YOFS)
660 *tempscore/LEVEL_PTS,
661 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
662 (8*TILE_HEIGHT+YOFS)*tempscore/LEVEL_PTS+1);
663 #endif
665 /* print text */
666 rb->snprintf(str, 10, "%s %d", title, bj->level);
667 rb->lcd_putsxy(1, LCD_HEIGHT-(LCD_HEIGHT-(8*TILE_HEIGHT+YOFS))/2-3, str);
669 rb->snprintf(str, 6, "%d", (bj->level-1)*LEVEL_PTS+bj->score);
670 rb->lcd_getstringsize(str, &w, &h);
671 rb->lcd_putsxy((LCD_WIDTH-2)-w,
672 LCD_HEIGHT-(LCD_HEIGHT-(8*TILE_HEIGHT+YOFS))/2-3, str);
674 #endif /* layout */
676 rb->lcd_update();
679 /*****************************************************************************
680 * jewels_showmenu() displays the chosen menu after performing the chosen
681 * menu command.
682 ******************************************************************************/
683 static enum menu_result jewels_showmenu(struct jewels_menu* menu,
684 enum menu_cmd cmd) {
685 int i;
686 int w, h;
687 int firstline;
688 int adj;
689 int extraline = LCD_HEIGHT <= ((menu->itemcnt+2)*FONT_HEIGHT) ? 0 : 1;
691 /* handle menu command */
692 switch(cmd) {
693 case MCMD_NEXT:
694 menu->selected = (menu->selected+1)%menu->itemcnt;
695 break;
697 case MCMD_PREV:
698 menu->selected = (menu->selected-1+menu->itemcnt)%menu->itemcnt;
699 break;
701 case MCMD_SELECT:
702 return menu->items[menu->selected].res;
704 default:
705 break;
708 /* clear menu area */
709 firstline = (LCD_HEIGHT/FONT_HEIGHT-(menu->itemcnt+3))/2;
711 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
712 rb->lcd_fillrect((LCD_WIDTH-MENU_WIDTH)/2, firstline*FONT_HEIGHT,
713 MENU_WIDTH, (menu->itemcnt+3)*FONT_HEIGHT);
714 rb->lcd_set_drawmode(DRMODE_SOLID);
716 if(menu->hasframe) {
717 rb->lcd_drawrect((LCD_WIDTH-MENU_WIDTH)/2-1, firstline*FONT_HEIGHT-1,
718 MENU_WIDTH+2, (menu->itemcnt+3)*FONT_HEIGHT+2);
719 rb->lcd_hline((LCD_WIDTH-MENU_WIDTH)/2-1,
720 (LCD_WIDTH-MENU_WIDTH)/2-1+MENU_WIDTH+2,
721 (firstline+1)*FONT_HEIGHT);
724 /* draw menu items */
725 rb->lcd_getstringsize(menu->title, &w, &h);
726 rb->lcd_putsxy((LCD_WIDTH-w)/2, firstline*FONT_HEIGHT, menu->title);
728 for(i=0; i<menu->itemcnt; i++) {
729 if(i == menu->selected) {
730 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
732 rb->lcd_putsxy((LCD_WIDTH-MENU_WIDTH)/2,
733 (firstline+i+1+extraline)*FONT_HEIGHT,
734 menu->items[i].text);
735 if(i == menu->selected) {
736 rb->lcd_set_drawmode(DRMODE_SOLID);
740 adj = (firstline == 0 ? 0 : 1);
741 rb->lcd_update_rect((LCD_WIDTH-MENU_WIDTH)/2-1, firstline*FONT_HEIGHT-adj,
742 MENU_WIDTH+2, (menu->itemcnt+3)*FONT_HEIGHT+2*adj);
743 return MRES_NONE;
746 /*****************************************************************************
747 * jewels_putjewels() makes the jewels fall to fill empty spots and adds
748 * new random jewels at the empty spots at the top of each row.
749 ******************************************************************************/
750 static void jewels_putjewels(struct game_context* bj){
751 int i, j, k;
752 bool mark, done;
753 long lasttick, currenttick;
755 /* loop to make all the jewels fall */
756 while(true) {
757 /* mark falling jewels and add new jewels to hidden top row*/
758 mark = false;
759 done = true;
760 for(j=0; j<BJ_WIDTH; j++) {
761 if(bj->playboard[1][j].type == 0) {
762 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
764 for(i=BJ_HEIGHT-2; i>=0; i--) {
765 if(!mark && bj->playboard[i+1][j].type == 0) {
766 mark = true;
767 done = false;
769 if(mark) bj->playboard[i][j].falling = true;
771 /*if(bj->playboard[1][j].falling) {
772 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
773 bj->playboard[0][j].falling = true;
775 mark = false;
778 /* break if there are no falling jewels */
779 if(done) break;
781 /* animate falling jewels */
782 lasttick = *rb->current_tick;
784 for(k=1; k<=8; k++) {
785 for(i=BJ_HEIGHT-2; i>=0; i--) {
786 for(j=0; j<BJ_WIDTH; j++) {
787 if(bj->playboard[i][j].falling &&
788 bj->playboard[i][j].type != 0) {
789 /* clear old position */
790 #ifdef HAVE_LCD_COLOR
791 if(i == 0 && YOFS) {
792 rb->lcd_set_foreground(rb->lcd_get_background());
793 } else {
794 rb->lcd_set_foreground(jewels_bkgd[(i-1+j)%2]);
796 rb->lcd_fillrect(j*TILE_WIDTH, (i-1)*TILE_HEIGHT+YOFS,
797 TILE_WIDTH, TILE_HEIGHT);
798 if(bj->playboard[i+1][j].type == 0) {
799 rb->lcd_set_foreground(jewels_bkgd[(i+j)%2]);
800 rb->lcd_fillrect(j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
801 TILE_WIDTH, TILE_HEIGHT);
803 #else
804 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
805 rb->lcd_fillrect(j*TILE_WIDTH, (i-1)*TILE_HEIGHT+YOFS,
806 TILE_WIDTH, TILE_HEIGHT);
807 if(bj->playboard[i+1][j].type == 0) {
808 rb->lcd_fillrect(j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
809 TILE_WIDTH, TILE_HEIGHT);
811 rb->lcd_set_drawmode(DRMODE_SOLID);
812 #endif
814 /* draw new position */
815 #ifdef HAVE_LCD_COLOR
816 rb->lcd_bitmap_transparent_part(jewels, 0,
817 TILE_HEIGHT*(bj->playboard[i][j].type),
818 TILE_WIDTH, j*TILE_WIDTH,
819 (i-1)*TILE_HEIGHT+YOFS+
820 ((((TILE_HEIGHT<<10)*k)/8)>>10),
821 TILE_WIDTH, TILE_HEIGHT);
822 #else
823 rb->lcd_bitmap_part(jewels, 0,
824 TILE_HEIGHT*(bj->playboard[i][j].type),
825 TILE_WIDTH, j*TILE_WIDTH,
826 (i-1)*TILE_HEIGHT+YOFS+
827 ((((TILE_HEIGHT<<10)*k)/8)>>10),
828 TILE_WIDTH, TILE_HEIGHT);
829 #endif
834 rb->lcd_update_rect(0, 0, TILE_WIDTH*8, LCD_HEIGHT);
835 jewels_setcolors();
837 /* framerate limiting */
838 currenttick = *rb->current_tick;
839 if(currenttick-lasttick < HZ/MAX_FPS) {
840 rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick));
841 } else {
842 rb->yield();
844 lasttick = currenttick;
847 /* shift jewels down */
848 for(j=0; j<BJ_WIDTH; j++) {
849 for(i=BJ_HEIGHT-1; i>=1; i--) {
850 if(bj->playboard[i-1][j].falling) {
851 bj->playboard[i][j].type = bj->playboard[i-1][j].type;
856 /* clear out top row */
857 for(j=0; j<BJ_WIDTH; j++) {
858 bj->playboard[0][j].type = 0;
861 /* mark everything not falling */
862 for(i=0; i<BJ_HEIGHT; i++) {
863 for(j=0; j<BJ_WIDTH; j++) {
864 bj->playboard[i][j].falling = false;
870 /*****************************************************************************
871 * jewels_clearjewels() finds all the connected rows and columns and
872 * calculates and returns the points earned.
873 ******************************************************************************/
874 static unsigned int jewels_clearjewels(struct game_context* bj) {
875 int i, j;
876 int last, run;
877 unsigned int points = 0;
879 /* check for connected rows */
880 for(i=1; i<BJ_HEIGHT; i++) {
881 last = 0;
882 run = 1;
883 for(j=0; j<BJ_WIDTH; j++) {
884 if(bj->playboard[i][j].type == last &&
885 bj->playboard[i][j].type != 0 &&
886 bj->playboard[i][j].type <= MAX_NUM_JEWELS) {
887 run++;
889 if(run == 3) {
890 bj->segments++;
891 points += bj->segments;
892 bj->playboard[i][j].delete = true;
893 bj->playboard[i][j-1].delete = true;
894 bj->playboard[i][j-2].delete = true;
895 } else if(run > 3) {
896 points++;
897 bj->playboard[i][j].delete = true;
899 } else {
900 run = 1;
901 last = bj->playboard[i][j].type;
906 /* check for connected columns */
907 for(j=0; j<BJ_WIDTH; j++) {
908 last = 0;
909 run = 1;
910 for(i=1; i<BJ_HEIGHT; i++) {
911 if(bj->playboard[i][j].type != 0 &&
912 bj->playboard[i][j].type == last &&
913 bj->playboard[i][j].type <= MAX_NUM_JEWELS) {
914 run++;
916 if(run == 3) {
917 bj->segments++;
918 points += bj->segments;
919 bj->playboard[i][j].delete = true;
920 bj->playboard[i-1][j].delete = true;
921 bj->playboard[i-2][j].delete = true;
922 } else if(run > 3) {
923 points++;
924 bj->playboard[i][j].delete = true;
926 } else {
927 run = 1;
928 last = bj->playboard[i][j].type;
933 /* clear deleted jewels */
934 for(i=1; i<BJ_HEIGHT; i++) {
935 for(j=0; j<BJ_WIDTH; j++) {
936 if(bj->playboard[i][j].delete) {
937 bj->playboard[i][j].delete = false;
938 bj->playboard[i][j].type = 0;
943 return points;
946 /*****************************************************************************
947 * jewels_runboard() runs the board until it settles in a fixed state and
948 * returns points earned.
949 ******************************************************************************/
950 static unsigned int jewels_runboard(struct game_context* bj) {
951 unsigned int points = 0;
952 unsigned int ret;
954 bj->segments = 0;
956 while((ret = jewels_clearjewels(bj)) > 0) {
957 points += ret;
958 jewels_drawboard(bj);
959 jewels_putjewels(bj);
962 return points;
965 /*****************************************************************************
966 * jewels_swapjewels() swaps two jewels as long as it results in points and
967 * returns points earned.
968 ******************************************************************************/
969 static unsigned int jewels_swapjewels(struct game_context* bj,
970 int x, int y, int direc) {
971 int k;
972 int horzmod, vertmod;
973 int movelen = 0;
974 bool undo = false;
975 unsigned int points = 0;
976 long lasttick, currenttick;
978 /* check for invalid parameters */
979 if(x < 0 || x >= BJ_WIDTH || y < 0 || y >= BJ_HEIGHT-1 ||
980 direc < SWAP_UP || direc > SWAP_LEFT) {
981 return 0;
984 /* check for invalid directions */
985 if((x == 0 && direc == SWAP_LEFT) ||
986 (x == BJ_WIDTH-1 && direc == SWAP_RIGHT) ||
987 (y == 0 && direc == SWAP_UP) ||
988 (y == BJ_HEIGHT-2 && direc == SWAP_DOWN)) {
989 return 0;
992 /* set direction variables */
993 horzmod = 0;
994 vertmod = 0;
995 switch(direc) {
996 case SWAP_UP:
997 vertmod = -1;
998 movelen = TILE_HEIGHT;
999 break;
1000 case SWAP_RIGHT:
1001 horzmod = 1;
1002 movelen = TILE_WIDTH;
1003 break;
1004 case SWAP_DOWN:
1005 vertmod = 1;
1006 movelen = TILE_HEIGHT;
1007 break;
1008 case SWAP_LEFT:
1009 horzmod = -1;
1010 movelen = TILE_WIDTH;
1011 break;
1014 while(true) {
1015 lasttick = *rb->current_tick;
1017 /* animate swapping jewels */
1018 for(k=0; k<=8; k++) {
1019 /* clear old position */
1020 #ifdef HAVE_LCD_COLOR
1021 rb->lcd_set_foreground(jewels_bkgd[(x+y)%2]);
1022 rb->lcd_fillrect(x*TILE_WIDTH,
1023 y*TILE_HEIGHT+YOFS,
1024 TILE_WIDTH, TILE_HEIGHT);
1025 rb->lcd_set_foreground(jewels_bkgd[(x+horzmod+y+vertmod)%2]);
1026 rb->lcd_fillrect((x+horzmod)*TILE_WIDTH,
1027 (y+vertmod)*TILE_HEIGHT+YOFS,
1028 TILE_WIDTH, TILE_HEIGHT);
1029 #else
1030 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
1031 rb->lcd_fillrect(x*TILE_WIDTH,
1032 y*TILE_HEIGHT+YOFS,
1033 TILE_WIDTH, TILE_HEIGHT);
1034 rb->lcd_fillrect((x+horzmod)*TILE_WIDTH,
1035 (y+vertmod)*TILE_HEIGHT+YOFS,
1036 TILE_WIDTH, TILE_HEIGHT);
1037 rb->lcd_set_drawmode(DRMODE_SOLID);
1038 #endif
1039 /* draw new position */
1040 #ifdef HAVE_LCD_COLOR
1041 rb->lcd_bitmap_transparent_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_bitmap_transparent_part(jewels,
1050 0, TILE_HEIGHT*(bj->playboard[y+1][x].type),
1051 TILE_WIDTH, x*TILE_WIDTH+horzmod*
1052 ((((movelen<<10)*k)/8)>>10),
1053 y*TILE_HEIGHT+vertmod*
1054 ((((movelen<<10)*k)/8)>>10)+YOFS,
1055 TILE_WIDTH, TILE_HEIGHT);
1056 #else
1057 rb->lcd_bitmap_part(jewels,
1058 0, TILE_HEIGHT*(bj->playboard
1059 [y+1+vertmod][x+horzmod].type), TILE_WIDTH,
1060 (x+horzmod)*TILE_WIDTH-horzmod*
1061 ((((movelen<<10)*k)/8)>>10),
1062 (y+vertmod)*TILE_HEIGHT-vertmod*
1063 ((((movelen<<10)*k)/8)>>10)+YOFS,
1064 TILE_WIDTH, TILE_HEIGHT);
1065 rb->lcd_set_drawmode(DRMODE_FG);
1066 rb->lcd_bitmap_part(jewels,
1067 0, TILE_HEIGHT*(bj->playboard[y+1][x].type),
1068 TILE_WIDTH, x*TILE_WIDTH+horzmod*
1069 ((((movelen<<10)*k)/8)>>10),
1070 y*TILE_HEIGHT+vertmod*
1071 ((((movelen<<10)*k)/8)>>10)+YOFS,
1072 TILE_WIDTH, TILE_HEIGHT);
1073 rb->lcd_set_drawmode(DRMODE_SOLID);
1074 #endif
1076 rb->lcd_update_rect(0, 0, TILE_WIDTH*8, LCD_HEIGHT);
1077 jewels_setcolors();
1079 /* framerate limiting */
1080 currenttick = *rb->current_tick;
1081 if(currenttick-lasttick < HZ/MAX_FPS) {
1082 rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick));
1083 } else {
1084 rb->yield();
1086 lasttick = currenttick;
1089 /* swap jewels */
1090 int temp = bj->playboard[y+1][x].type;
1091 bj->playboard[y+1][x].type =
1092 bj->playboard[y+1+vertmod][x+horzmod].type;
1093 bj->playboard[y+1+vertmod][x+horzmod].type = temp;
1095 if(undo) break;
1097 points = jewels_runboard(bj);
1098 if(points == 0) {
1099 undo = true;
1100 } else {
1101 break;
1105 return points;
1108 /*****************************************************************************
1109 * jewels_movesavail() uses pattern matching to see if there are any
1110 * available move left.
1111 ******************************************************************************/
1112 static bool jewels_movesavail(struct game_context* bj) {
1113 int i, j;
1114 bool moves = false;
1115 int mytype;
1117 for(i=1; i<BJ_HEIGHT; i++) {
1118 for(j=0; j<BJ_WIDTH; j++) {
1119 mytype = bj->playboard[i][j].type;
1120 if(mytype == 0 || mytype > MAX_NUM_JEWELS) continue;
1122 /* check horizontal patterns */
1123 if(j <= BJ_WIDTH-3) {
1124 if(i > 1) {
1125 if(bj->playboard[i-1][j+1].type == mytype) {
1126 if(bj->playboard[i-1][j+2].type == mytype)
1127 {moves = true; break;}
1128 if(bj->playboard[i][j+2].type == mytype)
1129 {moves = true; break;}
1131 if(bj->playboard[i][j+1].type == mytype) {
1132 if(bj->playboard[i-1][j+2].type == mytype)
1133 {moves = true; break;}
1137 if(j <= BJ_WIDTH-4) {
1138 if(bj->playboard[i][j+3].type == mytype) {
1139 if(bj->playboard[i][j+1].type == mytype)
1140 {moves = true; break;}
1141 if(bj->playboard[i][j+2].type == mytype)
1142 {moves = true; break;}
1146 if(i < BJ_HEIGHT-1) {
1147 if(bj->playboard[i][j+1].type == mytype) {
1148 if(bj->playboard[i+1][j+2].type == mytype)
1149 {moves = true; break;}
1151 if(bj->playboard[i+1][j+1].type == mytype) {
1152 if(bj->playboard[i][j+2].type == mytype)
1153 {moves = true; break;}
1154 if(bj->playboard[i+1][j+2].type == mytype)
1155 {moves = true; break;}
1160 /* check vertical patterns */
1161 if(i <= BJ_HEIGHT-3) {
1162 if(j > 0) {
1163 if(bj->playboard[i+1][j-1].type == mytype) {
1164 if(bj->playboard[i+2][j-1].type == mytype)
1165 {moves = true; break;}
1166 if(bj->playboard[i+2][j].type == mytype)
1167 {moves = true; break;}
1169 if(bj->playboard[i+1][j].type == mytype) {
1170 if(bj->playboard[i+2][j-1].type == mytype)
1171 {moves = true; break;}
1175 if(i <= BJ_HEIGHT-4) {
1176 if(bj->playboard[i+3][j].type == mytype) {
1177 if(bj->playboard[i+1][j].type == mytype)
1178 {moves = true; break;}
1179 if(bj->playboard[i+2][j].type == mytype)
1180 {moves = true; break;}
1184 if(j < BJ_WIDTH-1) {
1185 if(bj->playboard[i+1][j].type == mytype) {
1186 if(bj->playboard[i+2][j+1].type == mytype)
1187 {moves = true; break;}
1189 if(bj->playboard[i+1][j+1].type == mytype) {
1190 if(bj->playboard[i+2][j].type == mytype)
1191 {moves = true; break;}
1192 if (bj->playboard[i+2][j+1].type == mytype)
1193 {moves = true; break;}
1199 if(moves) break;
1202 return moves;
1205 /*****************************************************************************
1206 * jewels_puzzle_is_finished(bj) checks if the puzzle is finished.
1207 ******************************************************************************/
1208 static int jewels_puzzle_is_finished(struct game_context* bj) {
1209 unsigned int i, j;
1210 for(i=0; i<BJ_HEIGHT; i++) {
1211 for(j=0; j<BJ_WIDTH; j++) {
1212 int mytype = bj->playboard[i][j].type;
1213 if(mytype>MAX_NUM_JEWELS) {
1214 mytype -= MAX_NUM_JEWELS;
1215 if(mytype&PUZZLE_TILE_UP) {
1216 if(i==0 || bj->playboard[i-1][j].type<=MAX_NUM_JEWELS ||
1217 !((bj->playboard[i-1][j].type-MAX_NUM_JEWELS)
1218 &PUZZLE_TILE_DOWN))
1219 return 0;
1221 if(mytype&PUZZLE_TILE_DOWN) {
1222 if(i==BJ_HEIGHT-1 ||
1223 bj->playboard[i+1][j].type<=MAX_NUM_JEWELS ||
1224 !((bj->playboard[i+1][j].type-MAX_NUM_JEWELS)
1225 &PUZZLE_TILE_UP))
1226 return 0;
1228 if(mytype&PUZZLE_TILE_LEFT) {
1229 if(j==0 || bj->playboard[i][j-1].type<=MAX_NUM_JEWELS ||
1230 !((bj->playboard[i][j-1].type-MAX_NUM_JEWELS)
1231 &PUZZLE_TILE_RIGHT))
1232 return 0;
1234 if(mytype&PUZZLE_TILE_RIGHT) {
1235 if(j==BJ_WIDTH-1 ||
1236 bj->playboard[i][j+1].type<=MAX_NUM_JEWELS ||
1237 !((bj->playboard[i][j+1].type-MAX_NUM_JEWELS)
1238 &PUZZLE_TILE_LEFT))
1239 return 0;
1244 return 1;
1247 /*****************************************************************************
1248 * jewels_initlevel() initialises a level.
1249 ******************************************************************************/
1250 static unsigned int jewels_initlevel(struct game_context* bj) {
1251 unsigned int points = 0;
1253 switch(bj->type) {
1254 case GAME_TYPE_NORMAL:
1255 bj->num_jewels = MAX_NUM_JEWELS;
1256 break;
1258 case GAME_TYPE_PUZZLE:
1260 unsigned int i, j;
1261 struct puzzle_tile *tile;
1263 bj->num_jewels = puzzle_levels[bj->level-1].num_jewels;
1265 for(i=0; i<BJ_HEIGHT; i++) {
1266 for(j=0; j<BJ_WIDTH; j++) {
1267 bj->playboard[i][j].type = (rb->rand()%bj->num_jewels)+1;
1268 bj->playboard[i][j].falling = false;
1269 bj->playboard[i][j].delete = false;
1272 jewels_runboard(bj);
1273 tile = puzzle_levels[bj->level-1].tiles;
1274 for(i=0; i<puzzle_levels[bj->level-1].num_tiles; i++, tile++) {
1275 bj->playboard[tile->y+1][tile->x].type = MAX_NUM_JEWELS
1276 +tile->tile_type;
1279 break;
1282 jewels_drawboard(bj);
1284 /* run the play board */
1285 jewels_putjewels(bj);
1286 points += jewels_runboard(bj);
1287 return points;
1290 /*****************************************************************************
1291 * jewels_nextlevel() advances the game to the next level and returns
1292 * points earned.
1293 ******************************************************************************/
1294 static void jewels_nextlevel(struct game_context* bj) {
1295 int i, x, y;
1296 unsigned int points = 0;
1298 switch(bj->type) {
1299 case GAME_TYPE_NORMAL:
1300 /* roll over score, change and display level */
1301 while(bj->score >= LEVEL_PTS) {
1302 bj->score -= LEVEL_PTS;
1303 bj->level++;
1304 rb->splashf(HZ*2, "Level %d", bj->level);
1305 jewels_drawboard(bj);
1308 /* randomly clear some jewels */
1309 for(i=0; i<16; i++) {
1310 x = rb->rand()%8;
1311 y = rb->rand()%8;
1313 if(bj->playboard[y][x].type != 0) {
1314 points++;
1315 bj->playboard[y][x].type = 0;
1318 break;
1320 case GAME_TYPE_PUZZLE:
1321 bj->level++;
1322 if(bj->level>NUM_PUZZLE_LEVELS) {
1323 rb->splash(HZ*2, "You win!");
1324 bj->level = 1;
1325 } else {
1326 rb->splashf(HZ*2, "Level %d", bj->level);
1328 break;
1331 points += jewels_initlevel(bj);
1332 bj->score += points;
1335 /*****************************************************************************
1336 * jewels_recordscore() inserts a high score into the high scores list and
1337 * returns the high score position.
1338 ******************************************************************************/
1339 static int jewels_recordscore(struct game_context* bj) {
1340 int i;
1341 int position = 0;
1342 unsigned int current, temp;
1344 /* calculate total score */
1345 current = (bj->level-1)*LEVEL_PTS+bj->score;
1346 if(current <= 0) return 0;
1348 /* insert the current score into the high scores */
1349 for(i=0; i<NUM_SCORES; i++) {
1350 if(current >= bj->highscores[i]) {
1351 if(!position) {
1352 position = i+1;
1353 bj->dirty = true;
1355 temp = bj->highscores[i];
1356 bj->highscores[i] = current;
1357 current = temp;
1361 return position;
1364 /*****************************************************************************
1365 * jewels_loadscores() loads the high scores saved file.
1366 ******************************************************************************/
1367 static void jewels_loadscores(struct game_context* bj) {
1368 int fd;
1370 bj->dirty = false;
1372 /* clear high scores */
1373 rb->memset(bj->highscores, 0, sizeof(bj->highscores));
1375 /* open scores file */
1376 fd = rb->open(SCORE_FILE, O_RDONLY);
1377 if(fd < 0) return;
1379 /* read in high scores */
1380 if(rb->read(fd, bj->highscores, sizeof(bj->highscores)) <= 0) {
1381 /* scores are bad, reset */
1382 rb->memset(bj->highscores, 0, sizeof(bj->highscores));
1385 rb->close(fd);
1388 /*****************************************************************************
1389 * jewels_savescores() saves the high scores saved file.
1390 ******************************************************************************/
1391 static void jewels_savescores(struct game_context* bj) {
1392 int fd;
1394 /* write out the high scores to the save file */
1395 fd = rb->open(SCORE_FILE, O_WRONLY|O_CREAT);
1396 rb->write(fd, bj->highscores, sizeof(bj->highscores));
1397 rb->close(fd);
1398 bj->dirty = false;
1401 /*****************************************************************************
1402 * jewels_loadgame() loads the saved game and returns load success.
1403 ******************************************************************************/
1404 static bool jewels_loadgame(struct game_context* bj) {
1405 int fd;
1406 bool loaded = false;
1408 /* open game file */
1409 fd = rb->open(SAVE_FILE, O_RDONLY);
1410 if(fd < 0) return loaded;
1412 /* read in saved game */
1413 while(true) {
1414 if(rb->read(fd, &bj->score, sizeof(bj->score)) <= 0) break;
1415 if(rb->read(fd, &bj->level, sizeof(bj->level)) <= 0) break;
1416 if(rb->read(fd, &bj->type, sizeof(bj->type)) <= 0) break;
1417 if(rb->read(fd, bj->playboard, sizeof(bj->playboard)) <= 0) break;
1418 bj->resume = true;
1419 loaded = true;
1420 break;
1423 rb->close(fd);
1425 /* delete saved file */
1426 rb->remove(SAVE_FILE);
1427 return loaded;
1430 /*****************************************************************************
1431 * jewels_savegame() saves the current game state.
1432 ******************************************************************************/
1433 static void jewels_savegame(struct game_context* bj) {
1434 int fd;
1436 /* write out the game state to the save file */
1437 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT);
1438 rb->write(fd, &bj->score, sizeof(bj->score));
1439 rb->write(fd, &bj->level, sizeof(bj->level));
1440 rb->write(fd, &bj->type, sizeof(bj->type));
1441 rb->write(fd, bj->playboard, sizeof(bj->playboard));
1442 rb->close(fd);
1444 bj->resume = true;
1447 /*****************************************************************************
1448 * jewels_callback() is the default event handler callback which is called
1449 * on usb connect and shutdown.
1450 ******************************************************************************/
1451 static void jewels_callback(void* param) {
1452 struct game_context* bj = (struct game_context*) param;
1453 if(bj->dirty) {
1454 rb->splash(HZ, "Saving high scores...");
1455 jewels_savescores(bj);
1459 /*****************************************************************************
1460 * jewels_main() is the main game subroutine, it returns the final game status.
1461 ******************************************************************************/
1462 static int jewels_main(struct game_context* bj) {
1463 int i, j;
1464 int w, h;
1465 int button;
1466 char str[18];
1467 bool startgame = false;
1468 bool inmenu = false;
1469 bool selected = false;
1470 enum menu_cmd cmd = MCMD_NONE;
1471 enum menu_result res;
1473 /* the cursor coordinates */
1474 int x=0, y=0;
1476 /* don't resume by default */
1477 bj->resume = false;
1479 /********************
1480 * menu *
1481 ********************/
1482 rb->lcd_clear_display();
1484 while(!startgame) {
1485 res = jewels_showmenu(&bjmenu[0], cmd);
1486 cmd = MCMD_NONE;
1488 rb->snprintf(str, 18, "High Score: %d", bj->highscores[0]);
1489 rb->lcd_getstringsize(str, &w, &h);
1490 rb->lcd_putsxy((LCD_WIDTH-w)/2, LCD_HEIGHT-8, str);
1491 rb->lcd_update();
1493 rb->yield();
1495 switch(res) {
1496 case MRES_NEW:
1497 startgame = true;
1498 bj->type = GAME_TYPE_NORMAL;
1499 continue;
1501 case MRES_PUZZLE:
1502 startgame = true;
1503 bj->type = GAME_TYPE_PUZZLE;
1504 continue;
1506 case MRES_RESUME:
1507 if(!jewels_loadgame(bj)) {
1508 rb->splash(HZ*2, "Nothing to resume");
1509 rb->lcd_clear_display();
1510 } else {
1511 startgame = true;
1513 continue;
1515 case MRES_SCORES:
1516 rb->lcd_clear_display();
1518 /* room for a title? */
1519 j = 0;
1520 if(LCD_HEIGHT-NUM_SCORES*8 >= 8) {
1521 rb->snprintf(str, 12, "%s", "High Scores");
1522 rb->lcd_getstringsize(str, &w, &h);
1523 rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, str);
1524 j = 2;
1527 /* print high scores */
1528 for(i=0; i<NUM_SCORES; i++) {
1529 rb->snprintf(str, 11, "#%02d: %d", i+1, bj->highscores[i]);
1530 rb->lcd_puts(0, i+j, str);
1533 rb->lcd_update();
1534 while(true) {
1535 button = rb->button_get(true);
1536 if(button != BUTTON_NONE && !(button&BUTTON_REL)) break;
1537 rb->yield();
1539 rb->lcd_clear_display();
1540 continue;
1542 case MRES_HELP:
1543 /* welcome screen to display key bindings */
1544 rb->lcd_clear_display();
1545 rb->snprintf(str, 5, "%s", "Help");
1546 rb->lcd_getstringsize(str, &w, &h);
1547 rb->lcd_putsxy((LCD_WIDTH-w)/2, 0, str);
1548 #if CONFIG_KEYPAD == RECORDER_PAD
1549 rb->lcd_puts(0, 2, "Controls:");
1550 rb->lcd_puts(0, 3, "Directions = move");
1551 rb->lcd_puts(0, 4, "PLAY = select");
1552 rb->lcd_puts(0, 5, "Long PLAY = menu");
1553 rb->lcd_puts(0, 6, "OFF = cancel");
1554 #elif CONFIG_KEYPAD == ONDIO_PAD
1555 rb->lcd_puts(0, 2, "Controls:");
1556 rb->lcd_puts(0, 3, "Directions = move");
1557 rb->lcd_puts(0, 4, "MENU = select");
1558 rb->lcd_puts(0, 5, "Long MENU = menu");
1559 rb->lcd_puts(0, 6, "OFF = cancel");
1560 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
1561 rb->lcd_puts(0, 2, "Controls:");
1562 rb->lcd_puts(0, 3, "Directions = move");
1563 rb->lcd_puts(0, 4, "SELECT = select");
1564 rb->lcd_puts(0, 5, "Long SELECT = menu");
1565 rb->lcd_puts(0, 6, "PLAY = cancel");
1566 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
1567 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1568 rb->lcd_puts(0, 3, "form connected segments");
1569 rb->lcd_puts(0, 4, "of three or more of the");
1570 rb->lcd_puts(0, 5, "same type.");
1571 rb->lcd_puts(0, 7, "Controls:");
1572 rb->lcd_puts(0, 8, "Directions to move");
1573 rb->lcd_puts(0, 9, "SELECT to select");
1574 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1575 rb->lcd_puts(0, 11, "OFF to cancel");
1576 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
1577 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
1578 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1579 rb->lcd_puts(0, 3, "form connected segments");
1580 rb->lcd_puts(0, 4, "of three or more of the");
1581 rb->lcd_puts(0, 5, "same type.");
1582 rb->lcd_puts(0, 7, "Controls:");
1583 rb->lcd_puts(0, 8, "Directions or scroll to move");
1584 rb->lcd_puts(0, 9, "SELECT to select");
1585 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1586 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
1587 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1588 rb->lcd_puts(0, 3, "form connected segments");
1589 rb->lcd_puts(0, 4, "of three or more of the");
1590 rb->lcd_puts(0, 5, "same type.");
1591 rb->lcd_puts(0, 7, "Controls:");
1592 rb->lcd_puts(0, 8, "Directions to move");
1593 rb->lcd_puts(0, 9, "SELECT to select");
1594 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1595 rb->lcd_puts(0, 11, "PLAY to cancel");
1596 #elif CONFIG_KEYPAD == GIGABEAT_PAD \
1597 || CONFIG_KEYPAD == MROBE100_PAD
1598 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1599 rb->lcd_puts(0, 3, "form connected segments");
1600 rb->lcd_puts(0, 4, "of three or more of the");
1601 rb->lcd_puts(0, 5, "same type.");
1602 rb->lcd_puts(0, 7, "Controls:");
1603 rb->lcd_puts(0, 8, "Directions to move");
1604 rb->lcd_puts(0, 9, "SELECT to select");
1605 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1606 rb->lcd_puts(0, 11, "POWER to cancel");
1607 #elif CONFIG_KEYPAD == SANSA_E200_PAD \
1608 || CONFIG_KEYPAD == SANSA_C200_PAD \
1609 || CONFIG_KEYPAD == SANSA_CLIP_PAD \
1610 || CONFIG_KEYPAD == SANSA_FUZE_PAD \
1611 || CONFIG_KEYPAD == SANSA_M200_PAD
1612 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1613 rb->lcd_puts(0, 3, "form connected segments");
1614 rb->lcd_puts(0, 4, "of three or more of the");
1615 rb->lcd_puts(0, 5, "same type.");
1616 rb->lcd_puts(0, 7, "Controls:");
1617 rb->lcd_puts(0, 8, "Directions to move");
1618 rb->lcd_puts(0, 9, "SELECT to select");
1619 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1620 rb->lcd_puts(0, 11, "POWER to cancel");
1621 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
1622 rb->lcd_puts(0, 2, "Swap pairs of jewels");
1623 rb->lcd_puts(0, 3, "to form connected");
1624 rb->lcd_puts(0, 4, "segments of three or ");
1625 rb->lcd_puts(0, 5, "more of the");
1626 rb->lcd_puts(0, 6, "same type.");
1627 rb->lcd_puts(0, 8, "Controls:");
1628 rb->lcd_puts(0, 9, "Directions or scroll to move");
1629 rb->lcd_puts(0, 10, "PLAY to select");
1630 rb->lcd_puts(0, 11, "Long PLAY for menu");
1631 rb->lcd_puts(0, 12, "POWER to cancel");
1632 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
1633 rb->lcd_puts(0, 2, "Swap pairs of jewels");
1634 rb->lcd_puts(0, 3, "to form connected");
1635 rb->lcd_puts(0, 4, "segments of three or ");
1636 rb->lcd_puts(0, 5, "more of the");
1637 rb->lcd_puts(0, 6, "same type.");
1638 rb->lcd_puts(0, 8, "Controls:");
1639 rb->lcd_puts(0, 9, "Directions or scroll to move");
1640 rb->lcd_puts(0, 10, "PLAY to select");
1641 rb->lcd_puts(0, 11, "Long PLAY for menu");
1642 rb->lcd_puts(0, 12, "REC to cancel");
1643 #elif CONFIG_KEYPAD == COWOND2_PAD
1644 rb->lcd_puts(0, 11, "POWER to cancel");
1645 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
1646 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1647 rb->lcd_puts(0, 3, "form connected segments");
1648 rb->lcd_puts(0, 4, "of three or more of the");
1649 rb->lcd_puts(0, 5, "same type.");
1650 rb->lcd_puts(0, 7, "Controls:");
1651 rb->lcd_puts(0, 8, "Directions to move");
1652 rb->lcd_puts(0, 9, "SELECT to select");
1653 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1654 rb->lcd_puts(0, 11, "BACK to cancel");
1655 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
1656 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1657 rb->lcd_puts(0, 3, "form connected segments");
1658 rb->lcd_puts(0, 4, "of three or more of the");
1659 rb->lcd_puts(0, 5, "same type.");
1660 rb->lcd_puts(0, 7, "Controls:");
1661 rb->lcd_puts(0, 8, "Directions to move");
1662 rb->lcd_puts(0, 9, "MIDDLE to select");
1663 rb->lcd_puts(0, 10, "Long MIDDLE to show menu");
1664 rb->lcd_puts(0, 11, "BACK to cancel");
1665 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
1666 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1667 rb->lcd_puts(0, 3, "form connected segments");
1668 rb->lcd_puts(0, 4, "of three or more of the");
1669 rb->lcd_puts(0, 5, "same type.");
1670 rb->lcd_puts(0, 7, "Controls:");
1671 rb->lcd_puts(0, 8, "Directions to move");
1672 rb->lcd_puts(0, 9, "SELECT/PLAY to select");
1673 rb->lcd_puts(0, 10, "Long SELECT to show menu");
1674 rb->lcd_puts(0, 11, "POWER to cancel");
1675 #elif CONFIG_KEYPAD == ONDAVX747_PAD || CONFIG_KEYPAD == MROBE500_PAD
1676 rb->lcd_puts(0, 11, "POWER to cancel");
1677 #else
1678 #warning: missing help text.
1679 #endif
1681 #ifdef HAVE_TOUCHSCREEN
1682 rb->lcd_puts(0, 2, "Swap pairs of jewels to");
1683 rb->lcd_puts(0, 3, "form connected segments");
1684 rb->lcd_puts(0, 4, "of three or more of the");
1685 rb->lcd_puts(0, 5, "same type.");
1686 rb->lcd_puts(0, 7, "Controls:");
1687 rb->lcd_puts(0, 8, "Directions to move");
1688 rb->lcd_puts(0, 9, "CENTER to select");
1689 rb->lcd_puts(0, 10, "Long CENTER to show menu");
1690 #endif
1691 rb->lcd_update();
1692 while(true) {
1693 button = rb->button_get(true);
1694 if(button != BUTTON_NONE && !(button&BUTTON_REL)) break;
1696 rb->lcd_clear_display();
1697 continue;
1699 case MRES_QUIT:
1700 return BJ_QUIT;
1702 default:
1703 break;
1706 /* handle menu button presses */
1707 button = rb->button_get(true);
1708 switch(button){
1709 #ifdef JEWELS_SCROLLWHEEL
1710 case JEWELS_PREV:
1711 case (JEWELS_PREV|BUTTON_REPEAT):
1712 #endif
1713 case JEWELS_UP:
1714 case (JEWELS_UP|BUTTON_REPEAT):
1715 cmd = MCMD_PREV;
1716 break;
1718 #ifdef JEWELS_SCROLLWHEEL
1719 case JEWELS_NEXT:
1720 case (JEWELS_NEXT|BUTTON_REPEAT):
1721 #endif
1722 case JEWELS_DOWN:
1723 case (JEWELS_DOWN|BUTTON_REPEAT):
1724 cmd = MCMD_NEXT;
1725 break;
1727 case JEWELS_SELECT:
1728 case JEWELS_RIGHT:
1729 cmd = MCMD_SELECT;
1730 break;
1732 #ifdef JEWELS_CANCEL
1733 #ifdef JEWELS_RC_CANCEL
1734 case JEWELS_RC_CANCEL:
1735 #endif
1736 case JEWELS_CANCEL:
1737 return BJ_QUIT;
1738 #endif
1740 default:
1741 if(rb->default_event_handler_ex(button, jewels_callback,
1742 (void*) bj) == SYS_USB_CONNECTED)
1743 return BJ_USB;
1744 break;
1748 /********************
1749 * init *
1750 ********************/
1751 jewels_init(bj);
1753 /********************
1754 * setup the board *
1755 ********************/
1756 bj->score += jewels_initlevel(bj);
1757 if (!jewels_movesavail(bj)) {
1758 switch(bj->type) {
1759 case GAME_TYPE_NORMAL:
1760 return BJ_LOSE;
1762 case GAME_TYPE_PUZZLE:
1763 do {
1764 rb->splash(2*HZ, "No more moves!");
1765 bj->score += jewels_initlevel(bj);
1766 } while(!jewels_movesavail(bj));
1767 break;
1771 /**********************
1772 * play *
1773 **********************/
1774 while(true) {
1775 int no_movesavail = false;
1777 if(!inmenu) {
1778 /* refresh the board */
1779 jewels_drawboard(bj);
1781 /* display the cursor */
1782 if(selected) {
1783 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1784 rb->lcd_fillrect(x*TILE_WIDTH, y*TILE_HEIGHT+YOFS,
1785 TILE_WIDTH, TILE_HEIGHT);
1786 rb->lcd_set_drawmode(DRMODE_SOLID);
1787 } else {
1788 rb->lcd_drawrect(x*TILE_WIDTH, y*TILE_HEIGHT+YOFS,
1789 TILE_WIDTH, TILE_HEIGHT);
1791 rb->lcd_update_rect(x*TILE_WIDTH, y*TILE_HEIGHT+YOFS,
1792 TILE_WIDTH, TILE_HEIGHT);
1793 } else {
1794 res = jewels_showmenu(&bjmenu[1], cmd);
1795 cmd = MCMD_NONE;
1796 switch(res) {
1797 case MRES_RESUME:
1798 inmenu = false;
1799 selected = false;
1800 continue;
1802 case MRES_PLAYBACK:
1803 playback_control(NULL);
1804 rb->lcd_setfont(FONT_SYSFIXED);
1805 inmenu = false;
1806 selected = false;
1807 break;
1809 case MRES_SAVE:
1810 rb->splash(HZ, "Saving game...");
1811 jewels_savegame(bj);
1812 return BJ_END;
1814 case MRES_QUIT:
1815 return BJ_END;
1817 case MRES_EXIT:
1818 return BJ_QUIT_FROM_GAME;
1820 default:
1821 break;
1825 /* handle game button presses */
1826 rb->yield();
1827 button = rb->button_get(true);
1828 switch(button){
1829 case JEWELS_LEFT: /* move cursor left */
1830 case (JEWELS_LEFT|BUTTON_REPEAT):
1831 if(!inmenu) {
1832 if(selected) {
1833 bj->score += jewels_swapjewels(bj, x, y, SWAP_LEFT);
1834 selected = false;
1835 if (!jewels_movesavail(bj)) no_movesavail = true;
1836 } else {
1837 x = (x+BJ_WIDTH-1)%BJ_WIDTH;
1840 break;
1842 case JEWELS_RIGHT: /* move cursor right */
1843 case (JEWELS_RIGHT|BUTTON_REPEAT):
1844 if(!inmenu) {
1845 if(selected) {
1846 bj->score += jewels_swapjewels(bj, x, y, SWAP_RIGHT);
1847 selected = false;
1848 if (!jewels_movesavail(bj)) no_movesavail = true;
1849 } else {
1850 x = (x+1)%BJ_WIDTH;
1852 } else {
1853 cmd = MCMD_SELECT;
1855 break;
1857 case JEWELS_DOWN: /* move cursor down */
1858 case (JEWELS_DOWN|BUTTON_REPEAT):
1859 if(!inmenu) {
1860 if(selected) {
1861 bj->score += jewels_swapjewels(bj, x, y, SWAP_DOWN);
1862 selected = false;
1863 if (!jewels_movesavail(bj)) no_movesavail = true;
1864 } else {
1865 y = (y+1)%(BJ_HEIGHT-1);
1867 } else {
1868 cmd = MCMD_NEXT;
1870 break;
1872 case JEWELS_UP: /* move cursor up */
1873 case (JEWELS_UP|BUTTON_REPEAT):
1874 if(!inmenu) {
1875 if(selected) {
1876 bj->score += jewels_swapjewels(bj, x, y, SWAP_UP);
1877 selected = false;
1878 if (!jewels_movesavail(bj)) no_movesavail = true;
1879 } else {
1880 y = (y+(BJ_HEIGHT-1)-1)%(BJ_HEIGHT-1);
1882 } else {
1883 cmd = MCMD_PREV;
1885 break;
1887 #ifdef JEWELS_SCROLLWHEEL
1888 case JEWELS_PREV: /* scroll backwards */
1889 case (JEWELS_PREV|BUTTON_REPEAT):
1890 if(!inmenu) {
1891 if(!selected) {
1892 if(x == 0) {
1893 y = (y+(BJ_HEIGHT-1)-1)%(BJ_HEIGHT-1);
1895 x = (x+BJ_WIDTH-1)%BJ_WIDTH;
1897 } else {
1898 cmd = MCMD_PREV;
1900 break;
1902 case JEWELS_NEXT: /* scroll forwards */
1903 case (JEWELS_NEXT|BUTTON_REPEAT):
1904 if(!inmenu) {
1905 if(!selected) {
1906 if(x == BJ_WIDTH-1) {
1907 y = (y+1)%(BJ_HEIGHT-1);
1909 x = (x+1)%BJ_WIDTH;
1911 } else {
1912 cmd = MCMD_NEXT;
1914 break;
1915 #endif
1917 case JEWELS_SELECT: /* toggle selected */
1918 if(!inmenu) {
1919 selected = !selected;
1920 } else {
1921 cmd = MCMD_SELECT;
1923 break;
1925 #ifdef JEWELS_MENU
1926 case JEWELS_MENU:
1927 #endif
1928 case (JEWELS_SELECT|BUTTON_REPEAT): /* show menu */
1929 if(!inmenu) inmenu = true;
1930 break;
1932 #ifdef JEWELS_CANCEL
1933 #ifdef JEWELS_RC_CANCEL
1934 case JEWELS_RC_CANCEL:
1935 #endif
1936 case JEWELS_CANCEL: /* end game */
1937 return BJ_END;
1938 break;
1939 #endif
1941 default:
1942 if(rb->default_event_handler_ex(button, jewels_callback,
1943 (void*) bj) == SYS_USB_CONNECTED)
1944 return BJ_USB;
1945 break;
1948 if (no_movesavail) {
1949 switch(bj->type) {
1950 case GAME_TYPE_NORMAL:
1951 return BJ_LOSE;
1953 case GAME_TYPE_PUZZLE:
1954 do {
1955 rb->splash(2*HZ, "No more moves!");
1956 bj->score += jewels_initlevel(bj);
1957 } while(!jewels_movesavail(bj));
1958 break;
1962 switch(bj->type) {
1963 case GAME_TYPE_NORMAL:
1964 if(bj->score >= LEVEL_PTS)
1965 jewels_nextlevel(bj);
1966 break;
1968 case GAME_TYPE_PUZZLE:
1969 if(jewels_puzzle_is_finished(bj))
1970 jewels_nextlevel(bj);
1971 break;
1976 /*****************************************************************************
1977 * plugin entry point.
1978 ******************************************************************************/
1979 enum plugin_status plugin_start(const void* parameter) {
1980 struct game_context bj;
1981 bool exit = false;
1982 int position;
1983 char str[19];
1985 /* plugin init */
1986 (void)parameter;
1987 /* end of plugin init */
1989 /* load high scores */
1990 jewels_loadscores(&bj);
1992 rb->lcd_setfont(FONT_SYSFIXED);
1993 #if LCD_DEPTH > 1
1994 rb->lcd_set_backdrop(NULL);
1995 #endif
1996 jewels_setcolors();
1998 while(!exit) {
1999 switch(jewels_main(&bj)){
2000 case BJ_LOSE:
2001 rb->splash(HZ*2, "No more moves!");
2002 /* fall through to BJ_END */
2004 case BJ_END:
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 break;
2013 case BJ_USB:
2014 rb->lcd_setfont(FONT_UI);
2015 return PLUGIN_USB_CONNECTED;
2017 case BJ_QUIT:
2018 if(bj.dirty) {
2019 rb->splash(HZ, "Saving high scores...");
2020 jewels_savescores(&bj);
2022 exit = true;
2023 break;
2025 case BJ_QUIT_FROM_GAME:
2026 if(!bj.resume) {
2027 if((position = jewels_recordscore(&bj))) {
2028 rb->snprintf(str, 19, "New high score #%d!", position);
2029 rb->splash(HZ*2, str);
2032 if(bj.dirty) {
2033 rb->splash(HZ, "Saving high scores...");
2034 jewels_savescores(&bj);
2036 exit = true;
2037 break;
2039 default:
2040 break;
2044 rb->lcd_setfont(FONT_UI);
2045 return PLUGIN_OK;
2048 #endif /* HAVE_LCD_BITMAP */