Re-add the lseek to the beginning of the file which was accidentally removed.
[kugel-rb.git] / apps / plugins / jewels.c
blob71267484b12927298450c7b941361757072b7ce0
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/display_text.h"
26 #include "lib/highscore.h"
27 #include "lib/playback_control.h"
28 #include "pluginbitmaps/jewels.h"
30 /* button definitions */
31 #if CONFIG_KEYPAD == RECORDER_PAD
32 #define JEWELS_UP BUTTON_UP
33 #define JEWELS_DOWN BUTTON_DOWN
34 #define JEWELS_LEFT BUTTON_LEFT
35 #define JEWELS_RIGHT BUTTON_RIGHT
36 #define JEWELS_SELECT BUTTON_PLAY
37 #define JEWELS_CANCEL BUTTON_OFF
38 #define HK_SELECT "PLAY"
39 #define HK_CANCEL "OFF"
41 #elif CONFIG_KEYPAD == ARCHOS_AV300_PAD
42 #define JEWELS_UP BUTTON_UP
43 #define JEWELS_DOWN BUTTON_DOWN
44 #define JEWELS_LEFT BUTTON_LEFT
45 #define JEWELS_RIGHT BUTTON_RIGHT
46 #define JEWELS_SELECT BUTTON_SELECT
47 #define JEWELS_CANCEL BUTTON_OFF
48 #define HK_SELECT "SELECT"
49 #define HK_CANCEL "OFF"
51 #elif CONFIG_KEYPAD == ONDIO_PAD
52 #define JEWELS_UP BUTTON_UP
53 #define JEWELS_DOWN BUTTON_DOWN
54 #define JEWELS_LEFT BUTTON_LEFT
55 #define JEWELS_RIGHT BUTTON_RIGHT
56 #define JEWELS_SELECT BUTTON_MENU
57 #define JEWELS_CANCEL BUTTON_OFF
58 #define HK_SELECT "MENU"
59 #define HK_CANCEL "OFF"
61 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
62 #define JEWELS_UP BUTTON_UP
63 #define JEWELS_DOWN BUTTON_DOWN
64 #define JEWELS_LEFT BUTTON_LEFT
65 #define JEWELS_RIGHT BUTTON_RIGHT
66 #define JEWELS_SELECT BUTTON_SELECT
67 #define JEWELS_CANCEL BUTTON_OFF
68 #define JEWELS_RC_CANCEL BUTTON_RC_STOP
69 #define HK_SELECT "SELECT"
70 #define HK_CANCEL "OFF"
72 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
73 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
74 #define JEWELS_SCROLLWHEEL
75 #define JEWELS_UP BUTTON_MENU
76 #define JEWELS_DOWN BUTTON_PLAY
77 #define JEWELS_LEFT BUTTON_LEFT
78 #define JEWELS_RIGHT BUTTON_RIGHT
79 #define JEWELS_PREV BUTTON_SCROLL_BACK
80 #define JEWELS_NEXT BUTTON_SCROLL_FWD
81 #define JEWELS_SELECT BUTTON_SELECT
82 #define JEWELS_CANCEL (BUTTON_SELECT | BUTTON_MENU)
83 #define HK_SELECT "SELECT"
84 #define HK_CANCEL "SEL + MENU"
86 #elif (CONFIG_KEYPAD == IPOD_3G_PAD)
87 #define JEWELS_LEFT BUTTON_LEFT
88 #define JEWELS_RIGHT BUTTON_RIGHT
89 #define JEWELS_UP BUTTON_SCROLL_BACK
90 #define JEWELS_DOWN BUTTON_SCROLL_FWD
91 #define JEWELS_SELECT BUTTON_SELECT
92 #define JEWELS_CANCEL BUTTON_MENU
93 #define HK_SELECT "SELECT"
94 #define HK_CANCEL "MENU"
96 #elif CONFIG_KEYPAD == IRIVER_IFP7XX_PAD
97 #define JEWELS_UP BUTTON_UP
98 #define JEWELS_DOWN BUTTON_DOWN
99 #define JEWELS_LEFT BUTTON_LEFT
100 #define JEWELS_RIGHT BUTTON_RIGHT
101 #define JEWELS_SELECT BUTTON_SELECT
102 #define JEWELS_CANCEL BUTTON_PLAY
103 #define HK_SELECT "SELECT"
104 #define HK_CANCEL "PLAY"
106 #elif CONFIG_KEYPAD == IAUDIO_X5M5_PAD
107 #define JEWELS_UP BUTTON_UP
108 #define JEWELS_DOWN BUTTON_DOWN
109 #define JEWELS_LEFT BUTTON_LEFT
110 #define JEWELS_RIGHT BUTTON_RIGHT
111 #define JEWELS_SELECT BUTTON_SELECT
112 #define JEWELS_CANCEL BUTTON_POWER
113 #define HK_SELECT "SELECT"
114 #define HK_CANCEL "POWER"
116 #elif CONFIG_KEYPAD == GIGABEAT_PAD
117 #define JEWELS_UP BUTTON_UP
118 #define JEWELS_DOWN BUTTON_DOWN
119 #define JEWELS_LEFT BUTTON_LEFT
120 #define JEWELS_RIGHT BUTTON_RIGHT
121 #define JEWELS_SELECT BUTTON_SELECT
122 #define JEWELS_CANCEL BUTTON_POWER
123 #define HK_SELECT "SELECT"
124 #define HK_CANCEL "POWER"
126 #elif CONFIG_KEYPAD == SANSA_E200_PAD
127 #define JEWELS_SCROLLWHEEL
128 #define JEWELS_UP BUTTON_UP
129 #define JEWELS_DOWN BUTTON_DOWN
130 #define JEWELS_LEFT BUTTON_LEFT
131 #define JEWELS_RIGHT BUTTON_RIGHT
132 #define JEWELS_PREV BUTTON_SCROLL_BACK
133 #define JEWELS_NEXT BUTTON_SCROLL_FWD
134 #define JEWELS_SELECT BUTTON_SELECT
135 #define JEWELS_CANCEL BUTTON_POWER
136 #define HK_SELECT "SELECT"
137 #define HK_CANCEL "POWER"
139 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
140 #define JEWELS_SCROLLWHEEL
141 #define JEWELS_UP BUTTON_UP
142 #define JEWELS_DOWN BUTTON_DOWN
143 #define JEWELS_LEFT BUTTON_LEFT
144 #define JEWELS_RIGHT BUTTON_RIGHT
145 #define JEWELS_PREV BUTTON_SCROLL_BACK
146 #define JEWELS_NEXT BUTTON_SCROLL_FWD
147 #define JEWELS_SELECT BUTTON_SELECT
148 #define JEWELS_CANCEL (BUTTON_HOME|BUTTON_REPEAT)
149 #define HK_SELECT "SELECT"
150 #define HK_CANCEL "HOME"
152 #elif CONFIG_KEYPAD == SANSA_C200_PAD || \
153 CONFIG_KEYPAD == SANSA_CLIP_PAD || \
154 CONFIG_KEYPAD == SANSA_M200_PAD
155 #define JEWELS_UP BUTTON_UP
156 #define JEWELS_DOWN BUTTON_DOWN
157 #define JEWELS_LEFT BUTTON_LEFT
158 #define JEWELS_RIGHT BUTTON_RIGHT
159 #define JEWELS_SELECT BUTTON_SELECT
160 #define JEWELS_CANCEL BUTTON_POWER
161 #define HK_SELECT "SELECT"
162 #define HK_CANCEL "POWER"
164 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
165 #define JEWELS_UP BUTTON_SCROLL_UP
166 #define JEWELS_DOWN BUTTON_SCROLL_DOWN
167 #define JEWELS_LEFT BUTTON_LEFT
168 #define JEWELS_RIGHT BUTTON_RIGHT
169 #define JEWELS_SELECT BUTTON_PLAY
170 #define JEWELS_CANCEL BUTTON_POWER
171 #define HK_SELECT "PLAY"
172 #define HK_CANCEL "POWER"
174 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
175 #define JEWELS_UP BUTTON_UP
176 #define JEWELS_DOWN BUTTON_DOWN
177 #define JEWELS_LEFT BUTTON_LEFT
178 #define JEWELS_RIGHT BUTTON_RIGHT
179 #define JEWELS_SELECT BUTTON_SELECT
180 #define JEWELS_CANCEL BUTTON_BACK
181 #define HK_SELECT "SELECT"
182 #define HK_CANCEL "BACK"
184 #elif CONFIG_KEYPAD == MROBE100_PAD
185 #define JEWELS_UP BUTTON_UP
186 #define JEWELS_DOWN BUTTON_DOWN
187 #define JEWELS_LEFT BUTTON_LEFT
188 #define JEWELS_RIGHT BUTTON_RIGHT
189 #define JEWELS_SELECT BUTTON_SELECT
190 #define JEWELS_CANCEL BUTTON_POWER
191 #define HK_SELECT "SELECT"
192 #define HK_CANCEL "POWER"
194 #elif CONFIG_KEYPAD == IAUDIO_M3_PAD
195 #define JEWELS_UP BUTTON_RC_VOL_UP
196 #define JEWELS_DOWN BUTTON_RC_VOL_DOWN
197 #define JEWELS_LEFT BUTTON_RC_REW
198 #define JEWELS_RIGHT BUTTON_RC_FF
199 #define JEWELS_SELECT BUTTON_RC_PLAY
200 #define JEWELS_CANCEL BUTTON_RC_REC
201 #define HK_SELECT "PLAY"
202 #define HK_CANCEL "REC"
204 #define JEWELS_RC_CANCEL BUTTON_REC
206 #elif CONFIG_KEYPAD == COWON_D2_PAD
207 #define JEWELS_CANCEL BUTTON_POWER
208 #define HK_CANCEL "POWER"
210 #elif CONFIG_KEYPAD == IAUDIO67_PAD
211 #define JEWELS_UP BUTTON_STOP
212 #define JEWELS_DOWN BUTTON_PLAY
213 #define JEWELS_LEFT BUTTON_LEFT
214 #define JEWELS_RIGHT BUTTON_RIGHT
215 #define JEWELS_SELECT BUTTON_MENU
216 #define JEWELS_CANCEL BUTTON_POWER
217 #define HK_SELECT "MENU"
218 #define HK_CANCEL "POWER"
220 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
221 #define JEWELS_UP BUTTON_UP
222 #define JEWELS_DOWN BUTTON_DOWN
223 #define JEWELS_LEFT BUTTON_LEFT
224 #define JEWELS_RIGHT BUTTON_RIGHT
225 #define JEWELS_SELECT BUTTON_SELECT
226 #define JEWELS_CANCEL BUTTON_BACK
227 #define HK_SELECT "MIDDLE"
228 #define HK_CANCEL "BACK"
230 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
231 #define JEWELS_UP BUTTON_UP
232 #define JEWELS_DOWN BUTTON_DOWN
233 #define JEWELS_LEFT BUTTON_LEFT
234 #define JEWELS_RIGHT BUTTON_RIGHT
235 #define JEWELS_SELECT BUTTON_SELECT
236 #define JEWELS_CANCEL BUTTON_POWER
237 #define HK_SELECT "SELECT"
238 #define HK_CANCEL "POWER"
240 #elif CONFIG_KEYPAD == PHILIPS_HDD6330_PAD
241 #define JEWELS_UP BUTTON_UP
242 #define JEWELS_DOWN BUTTON_DOWN
243 #define JEWELS_LEFT BUTTON_LEFT
244 #define JEWELS_RIGHT BUTTON_RIGHT
245 #define JEWELS_SELECT BUTTON_PLAY
246 #define JEWELS_CANCEL BUTTON_POWER
247 #define HK_SELECT "PLAY"
248 #define HK_CANCEL "POWER"
250 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
251 #define JEWELS_UP BUTTON_UP
252 #define JEWELS_DOWN BUTTON_DOWN
253 #define JEWELS_LEFT BUTTON_PREV
254 #define JEWELS_RIGHT BUTTON_NEXT
255 #define JEWELS_SELECT BUTTON_PLAY
256 #define JEWELS_CANCEL BUTTON_POWER
257 #define HK_SELECT "PLAY"
258 #define HK_CANCEL "POWER"
260 #elif CONFIG_KEYPAD == ONDAVX747_PAD || \
261 CONFIG_KEYPAD == ONDAVX777_PAD || \
262 CONFIG_KEYPAD == MROBE500_PAD
263 #define JEWELS_CANCEL BUTTON_POWER
264 #define HK_CANCEL "POWER"
266 #elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
267 #define JEWELS_UP BUTTON_UP
268 #define JEWELS_DOWN BUTTON_DOWN
269 #define JEWELS_LEFT BUTTON_LEFT
270 #define JEWELS_RIGHT BUTTON_RIGHT
271 #define JEWELS_SELECT BUTTON_PLAY
272 #define JEWELS_CANCEL BUTTON_REW
273 #define HK_SELECT "PLAY"
274 #define HK_CANCEL "REWIND"
276 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
277 #define JEWELS_UP BUTTON_UP
278 #define JEWELS_DOWN BUTTON_DOWN
279 #define JEWELS_LEFT BUTTON_PREV
280 #define JEWELS_RIGHT BUTTON_NEXT
281 #define JEWELS_SELECT BUTTON_OK
282 #define JEWELS_CANCEL BUTTON_REC
283 #define HK_SELECT "OK"
284 #define HK_CANCEL "REC"
286 #elif CONFIG_KEYPAD == MPIO_HD200_PAD
287 #define JEWELS_LEFT BUTTON_VOL_DOWN
288 #define JEWELS_RIGHT BUTTON_VOL_UP
289 #define JEWELS_UP BUTTON_REW
290 #define JEWELS_DOWN BUTTON_FF
291 #define JEWELS_SELECT BUTTON_FUNC
292 #define JEWELS_CANCEL BUTTON_REC
293 #define HK_SELECT "FUNC"
294 #define HK_CANCEL "REC"
296 #else
297 #error No keymap defined!
298 #endif
300 #ifdef HAVE_TOUCHSCREEN
301 #ifndef JEWELS_UP
302 #define JEWELS_UP BUTTON_TOPMIDDLE
303 #endif
304 #ifndef JEWELS_DOWN
305 #define JEWELS_DOWN BUTTON_BOTTOMMIDDLE
306 #endif
307 #ifndef JEWELS_LEFT
308 #define JEWELS_LEFT BUTTON_MIDLEFT
309 #endif
310 #ifndef JEWELS_RIGHT
311 #define JEWELS_RIGHT BUTTON_MIDRIGHT
312 #endif
313 #ifndef JEWELS_SELECT
314 #define JEWELS_SELECT BUTTON_CENTER
315 #define HK_SELECT "CENTER"
316 #endif
317 #ifndef JEWELS_CANCEL
318 #define JEWELS_CANCEL BUTTON_TOPLEFT
319 #define HK_CANCEL "TOPLEFT"
320 #endif
321 #endif
323 #define TILE_WIDTH BMPWIDTH_jewels
324 #define TILE_HEIGHT (BMPHEIGHT_jewels/23)
326 #if LCD_HEIGHT < LCD_WIDTH
327 /* This calculation assumes integer division w/ LCD_HEIGHT/TILE_HEIGHT */
328 #define YOFS LCD_HEIGHT-((LCD_HEIGHT/TILE_HEIGHT)*TILE_HEIGHT)
329 #else
330 #define YOFS 0
331 #endif
333 #define NUM_SCORES 5
335 /* swap directions */
336 #define SWAP_UP 0
337 #define SWAP_RIGHT 1
338 #define SWAP_DOWN 2
339 #define SWAP_LEFT 3
341 /* play board dimension */
342 #define BJ_HEIGHT 9
343 #define BJ_WIDTH 8
345 /* next level threshold */
346 #define LEVEL_PTS 100
348 /* animation frame rate */
349 #define MAX_FPS 20
351 /* text margin */
352 #define MARGIN 5
354 /* Game types */
355 enum game_type {
356 GAME_TYPE_NORMAL,
357 GAME_TYPE_PUZZLE
360 /* external bitmaps */
361 extern const fb_data jewels[];
363 /* tile background colors */
364 #ifdef HAVE_LCD_COLOR
365 static const unsigned jewels_bkgd[2] = {
366 LCD_RGBPACK(104, 63, 63),
367 LCD_RGBPACK(83, 44, 44)
369 #endif
371 /* the tile struct
372 * type is the jewel number 0-7
373 * falling if the jewel is falling
374 * delete marks the jewel for deletion
376 struct tile {
377 int type;
378 bool falling;
379 bool delete;
382 /* the game context struct
383 * score is the current level score
384 * segments is the number of cleared segments in the current run
385 * level is the current level
386 * tmp_type is the select type in the menu
387 * type is the game type (normal or puzzle)
388 * playboard is the game playing board (first row is hidden)
389 * num_jewels is the number of different jewels to use
391 struct game_context {
392 unsigned int score;
393 unsigned int segments;
394 unsigned int level;
395 unsigned int type;
396 unsigned int tmp_type;
397 struct tile playboard[BJ_HEIGHT][BJ_WIDTH];
398 unsigned int num_jewels;
401 #define MAX_NUM_JEWELS 7
403 #define MAX_PUZZLE_TILES 4
404 #define NUM_PUZZLE_LEVELS 10
406 struct puzzle_tile {
407 int x;
408 int y;
409 int tile_type;
412 struct puzzle_level {
413 unsigned int num_jewels;
414 unsigned int num_tiles;
415 struct puzzle_tile tiles[MAX_PUZZLE_TILES];
418 #define PUZZLE_TILE_UP 1
419 #define PUZZLE_TILE_DOWN 2
420 #define PUZZLE_TILE_LEFT 4
421 #define PUZZLE_TILE_RIGHT 8
423 struct puzzle_level puzzle_levels[NUM_PUZZLE_LEVELS] = {
424 { 5, 2, { {3, 3, PUZZLE_TILE_RIGHT},
425 {4, 2, PUZZLE_TILE_LEFT} } },
426 { 5, 2, { {3, 2, PUZZLE_TILE_DOWN},
427 {3, 4, PUZZLE_TILE_UP} } },
428 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN},
429 {3, 4, PUZZLE_TILE_UP|PUZZLE_TILE_DOWN},
430 {3, 6, PUZZLE_TILE_UP} } },
431 { 6, 3, { {3, 2, PUZZLE_TILE_RIGHT},
432 {4, 3, PUZZLE_TILE_LEFT|PUZZLE_TILE_RIGHT},
433 {5, 4, PUZZLE_TILE_LEFT} } },
434 { 6, 2, { {3, 4, PUZZLE_TILE_RIGHT},
435 {4, 2, PUZZLE_TILE_LEFT} } },
436 { 6, 2, { {3, 2, PUZZLE_TILE_DOWN},
437 {4, 4, PUZZLE_TILE_UP} } },
438 { 7, 4, { {3, 2, PUZZLE_TILE_RIGHT|PUZZLE_TILE_DOWN},
439 {4, 3, PUZZLE_TILE_LEFT|PUZZLE_TILE_DOWN},
440 {3, 4, PUZZLE_TILE_RIGHT|PUZZLE_TILE_UP},
441 {4, 4, PUZZLE_TILE_LEFT|PUZZLE_TILE_UP} } },
442 { 6, 3, { {3, 2, PUZZLE_TILE_DOWN},
443 {4, 4, PUZZLE_TILE_UP|PUZZLE_TILE_DOWN},
444 {3, 6, PUZZLE_TILE_UP} } },
445 { 7, 3, { {2, 2, PUZZLE_TILE_RIGHT},
446 {4, 1, PUZZLE_TILE_LEFT|PUZZLE_TILE_RIGHT},
447 {5, 4, PUZZLE_TILE_LEFT} } },
448 { 7, 4, { {3, 0, PUZZLE_TILE_RIGHT|PUZZLE_TILE_DOWN},
449 {5, 0, PUZZLE_TILE_LEFT|PUZZLE_TILE_DOWN},
450 {2, 7, PUZZLE_TILE_RIGHT|PUZZLE_TILE_UP},
451 {4, 7, PUZZLE_TILE_LEFT|PUZZLE_TILE_UP} } },
454 #define SAVE_FILE PLUGIN_GAMES_DIR "/jewels.save"
455 #define SCORE_FILE PLUGIN_GAMES_DIR "/jewels.score"
456 struct highscore highscores[NUM_SCORES];
458 static bool resume_file = false;
460 /*****************************************************************************
461 * jewels_setcolors() set the foreground and background colors.
462 ******************************************************************************/
463 static inline void jewels_setcolors(void) {
464 #ifdef HAVE_LCD_COLOR
465 rb->lcd_set_background(LCD_RGBPACK(49, 26, 26));
466 rb->lcd_set_foreground(LCD_RGBPACK(210, 181, 181));
467 #endif
470 /*****************************************************************************
471 * jewels_loadgame() loads the saved game and returns load success.
472 ******************************************************************************/
473 static bool jewels_loadgame(struct game_context* bj)
475 int fd;
476 bool loaded = false;
478 /* open game file */
479 fd = rb->open(SAVE_FILE, O_RDONLY);
480 if(fd < 0) return loaded;
482 /* read in saved game */
483 while(true) {
484 if(rb->read(fd, &bj->tmp_type, sizeof(bj->tmp_type)) <= 0) break;
485 if(rb->read(fd, &bj->type, sizeof(bj->type)) <= 0) break;
486 if(rb->read(fd, &bj->score, sizeof(bj->score)) <= 0) break;
487 if(rb->read(fd, &bj->level, sizeof(bj->level)) <= 0) break;
488 if(rb->read(fd, &bj->segments, sizeof(bj->segments)) <= 0) break;
489 if(rb->read(fd, &bj->num_jewels, sizeof(bj->num_jewels)) <= 0) break;
490 if(rb->read(fd, bj->playboard, sizeof(bj->playboard)) <= 0) break;
491 loaded = true;
492 break;
495 rb->close(fd);
497 return loaded;
500 /*****************************************************************************
501 * jewels_savegame() saves the current game state.
502 ******************************************************************************/
503 static void jewels_savegame(struct game_context* bj)
505 int fd;
506 /* write out the game state to the save file */
507 fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT, 0666);
508 if(fd < 0) return;
510 rb->write(fd, &bj->tmp_type, sizeof(bj->tmp_type));
511 rb->write(fd, &bj->type, sizeof(bj->type));
512 rb->write(fd, &bj->score, sizeof(bj->score));
513 rb->write(fd, &bj->level, sizeof(bj->level));
514 rb->write(fd, &bj->segments, sizeof(bj->segments));
515 rb->write(fd, &bj->num_jewels, sizeof(bj->num_jewels));
516 rb->write(fd, bj->playboard, sizeof(bj->playboard));
517 rb->close(fd);
520 /*****************************************************************************
521 * jewels_drawboard() redraws the entire game board.
522 ******************************************************************************/
523 static void jewels_drawboard(struct game_context* bj) {
524 int i, j;
525 int w, h;
526 unsigned int tempscore;
527 unsigned int size;
528 char *title = "Level";
529 char str[10];
531 if (bj->type == GAME_TYPE_NORMAL) {
532 tempscore = (bj->score>LEVEL_PTS ? LEVEL_PTS : bj->score);
533 size = LEVEL_PTS;
534 } else {
535 tempscore = (bj->level>NUM_PUZZLE_LEVELS ? NUM_PUZZLE_LEVELS : bj->level);
536 size = NUM_PUZZLE_LEVELS;
539 /* clear screen */
540 rb->lcd_clear_display();
542 /* dispay playing board */
543 for(i=0; i<BJ_HEIGHT-1; i++){
544 for(j=0; j<BJ_WIDTH; j++){
545 #ifdef HAVE_LCD_COLOR
546 rb->lcd_set_foreground(jewels_bkgd[(i+j)%2]);
547 rb->lcd_fillrect(j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
548 TILE_WIDTH, TILE_HEIGHT);
549 rb->lcd_bitmap_transparent_part(jewels,
550 0, TILE_HEIGHT*(bj->playboard[i+1][j].type),
551 STRIDE( SCREEN_MAIN,
552 BMPWIDTH_jewels, BMPHEIGHT_jewels),
553 j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
554 TILE_WIDTH, TILE_HEIGHT);
555 #else
556 rb->lcd_bitmap_part(jewels,
557 0, TILE_HEIGHT*(bj->playboard[i+1][j].type),
558 STRIDE( SCREEN_MAIN,
559 BMPWIDTH_jewels, BMPHEIGHT_jewels),
560 j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
561 TILE_WIDTH, TILE_HEIGHT);
562 #endif
566 #if LCD_WIDTH > LCD_HEIGHT /* horizontal layout */
568 /* draw separator lines */
569 jewels_setcolors();
570 rb->lcd_vline(BJ_WIDTH*TILE_WIDTH, 0, LCD_HEIGHT-1);
572 rb->lcd_hline(BJ_WIDTH*TILE_WIDTH, LCD_WIDTH-1, 18);
573 rb->lcd_hline(BJ_WIDTH*TILE_WIDTH, LCD_WIDTH-1, LCD_HEIGHT-10);
575 /* draw progress bar */
576 #ifdef HAVE_LCD_COLOR
577 rb->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
578 #endif
579 rb->lcd_fillrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
580 (LCD_HEIGHT-10)-(((LCD_HEIGHT-10)-18)*
581 tempscore/size),
582 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
583 ((LCD_HEIGHT-10)-18)*tempscore/size);
584 #ifdef HAVE_LCD_COLOR
585 rb->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
586 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4+1,
587 (LCD_HEIGHT-10)-(((LCD_HEIGHT-10)-18)*
588 tempscore/size)+1,
589 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-2,
590 ((LCD_HEIGHT-10)-18)*tempscore/size-1);
591 jewels_setcolors();
592 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
593 (LCD_HEIGHT-10)-(((LCD_HEIGHT-10)-18)*tempscore/size),
594 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
595 ((LCD_HEIGHT-10)-18)*tempscore/size+1);
596 #endif
598 /* print text */
599 rb->lcd_getstringsize(title, &w, &h);
600 rb->lcd_putsxy(LCD_WIDTH-(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-w/2, 1, title);
601 rb->snprintf(str, 4, "%d", bj->level);
602 rb->lcd_getstringsize(str, &w, &h);
603 rb->lcd_putsxy(LCD_WIDTH-(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-w/2, 10, str);
605 if (bj->type == GAME_TYPE_NORMAL) {
606 rb->snprintf(str, 6, "%d", (bj->level-1)*LEVEL_PTS+bj->score);
607 rb->lcd_getstringsize(str, &w, &h);
608 rb->lcd_putsxy(LCD_WIDTH-(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-w/2,
609 LCD_HEIGHT-8, str);
612 #elif LCD_WIDTH < LCD_HEIGHT /* vertical layout */
614 /* draw separator lines */
615 jewels_setcolors();
616 rb->lcd_hline(0, LCD_WIDTH-1, 8*TILE_HEIGHT+YOFS);
617 rb->lcd_hline(0, LCD_WIDTH-1, LCD_HEIGHT-14);
618 rb->lcd_vline(LCD_WIDTH/2, LCD_HEIGHT-14, LCD_HEIGHT-1);
620 /* draw progress bar */
621 #ifdef HAVE_LCD_COLOR
622 rb->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
623 #endif
624 rb->lcd_fillrect(0, (8*TILE_HEIGHT+YOFS)
625 +(LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/4,
626 LCD_WIDTH*tempscore/size,
627 (LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/2);
628 #ifdef HAVE_LCD_COLOR
629 rb->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
630 rb->lcd_drawrect(1, (8*TILE_HEIGHT+YOFS)
631 +(LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/4+1,
632 LCD_WIDTH*tempscore/size-1,
633 (LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/2-2);
634 jewels_setcolors();
635 rb->lcd_drawrect(0, (8*TILE_HEIGHT+YOFS)
636 +(LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/4,
637 LCD_WIDTH*tempscore/size+1,
638 (LCD_HEIGHT-14-(8*TILE_HEIGHT+YOFS))/2);
639 #endif
641 /* print text */
642 rb->lcd_putsxyf(1, LCD_HEIGHT-10, "%s %d", title, bj->level);
644 if (bj->type == GAME_TYPE_NORMAL) {
645 rb->snprintf(str, 6, "%d", (bj->level-1)*LEVEL_PTS+bj->score);
646 rb->lcd_getstringsize(str, &w, &h);
647 rb->lcd_putsxy((LCD_WIDTH-2)-w, LCD_HEIGHT-10, str);
651 #else /* square layout */
653 /* draw separator lines */
654 jewels_setcolors();
655 rb->lcd_hline(0, LCD_WIDTH-1, 8*TILE_HEIGHT+YOFS);
656 rb->lcd_vline(BJ_WIDTH*TILE_WIDTH, 0, 8*TILE_HEIGHT+YOFS);
657 rb->lcd_vline(LCD_WIDTH/2, 8*TILE_HEIGHT+YOFS, LCD_HEIGHT-1);
659 /* draw progress bar */
660 #ifdef HAVE_LCD_COLOR
661 rb->lcd_set_foreground(LCD_RGBPACK(104, 63, 63));
662 #endif
663 rb->lcd_fillrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
664 (8*TILE_HEIGHT+YOFS)-(8*TILE_HEIGHT+YOFS)*tempscore/size,
665 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
666 (8*TILE_HEIGHT+YOFS)*tempscore/size);
667 #ifdef HAVE_LCD_COLOR
668 rb->lcd_set_foreground(LCD_RGBPACK(83, 44, 44));
669 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4+1,
670 (8*TILE_HEIGHT+YOFS)-(8*TILE_HEIGHT+YOFS)
671 *tempscore/size+1,
672 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2-2,
673 (8*TILE_HEIGHT+YOFS)*tempscore/size-1);
674 jewels_setcolors();
675 rb->lcd_drawrect(BJ_WIDTH*TILE_WIDTH+(LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/4,
676 (8*TILE_HEIGHT+YOFS)-(8*TILE_HEIGHT+YOFS)
677 *tempscore/size,
678 (LCD_WIDTH-BJ_WIDTH*TILE_WIDTH)/2,
679 (8*TILE_HEIGHT+YOFS)*tempscore/size+1);
680 #endif
682 /* print text */
683 rb->lcd_putsxyf(1, LCD_HEIGHT-(LCD_HEIGHT-(8*TILE_HEIGHT+YOFS))/2-3,"%s %d",
684 title, bj->level);
686 if (bj->type == GAME_TYPE_NORMAL) {
687 rb->snprintf(str, 6, "%d", (bj->level-1)*LEVEL_PTS+bj->score);
688 rb->lcd_getstringsize(str, &w, &h);
689 rb->lcd_putsxy((LCD_WIDTH-2)-w,
690 LCD_HEIGHT-(LCD_HEIGHT-(8*TILE_HEIGHT+YOFS))/2-3, str);
693 #endif /* layout */
695 rb->lcd_update();
698 /*****************************************************************************
699 * jewels_putjewels() makes the jewels fall to fill empty spots and adds
700 * new random jewels at the empty spots at the top of each row.
701 ******************************************************************************/
702 static void jewels_putjewels(struct game_context* bj){
703 int i, j, k;
704 bool mark, done;
705 long lasttick, currenttick;
707 /* loop to make all the jewels fall */
708 while(true) {
709 /* mark falling jewels and add new jewels to hidden top row*/
710 mark = false;
711 done = true;
712 for(j=0; j<BJ_WIDTH; j++) {
713 if(bj->playboard[1][j].type == 0) {
714 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
716 for(i=BJ_HEIGHT-2; i>=0; i--) {
717 if(!mark && bj->playboard[i+1][j].type == 0) {
718 mark = true;
719 done = false;
721 if(mark) bj->playboard[i][j].falling = true;
723 /*if(bj->playboard[1][j].falling) {
724 bj->playboard[0][j].type = rb->rand()%bj->num_jewels+1;
725 bj->playboard[0][j].falling = true;
727 mark = false;
730 /* break if there are no falling jewels */
731 if(done) break;
733 /* animate falling jewels */
734 lasttick = *rb->current_tick;
736 for(k=1; k<=8; k++) {
737 for(i=BJ_HEIGHT-2; i>=0; i--) {
738 for(j=0; j<BJ_WIDTH; j++) {
739 if(bj->playboard[i][j].falling &&
740 bj->playboard[i][j].type != 0) {
741 /* clear old position */
742 #ifdef HAVE_LCD_COLOR
743 if(i == 0 && YOFS) {
744 rb->lcd_set_foreground(rb->lcd_get_background());
745 } else {
746 rb->lcd_set_foreground(jewels_bkgd[(i-1+j)%2]);
748 rb->lcd_fillrect(j*TILE_WIDTH, (i-1)*TILE_HEIGHT+YOFS,
749 TILE_WIDTH, TILE_HEIGHT);
750 if(bj->playboard[i+1][j].type == 0) {
751 rb->lcd_set_foreground(jewels_bkgd[(i+j)%2]);
752 rb->lcd_fillrect(j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
753 TILE_WIDTH, TILE_HEIGHT);
755 #else
756 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
757 rb->lcd_fillrect(j*TILE_WIDTH, (i-1)*TILE_HEIGHT+YOFS,
758 TILE_WIDTH, TILE_HEIGHT);
759 if(bj->playboard[i+1][j].type == 0) {
760 rb->lcd_fillrect(j*TILE_WIDTH, i*TILE_HEIGHT+YOFS,
761 TILE_WIDTH, TILE_HEIGHT);
763 rb->lcd_set_drawmode(DRMODE_SOLID);
764 #endif
766 /* draw new position */
767 #ifdef HAVE_LCD_COLOR
768 rb->lcd_bitmap_transparent_part(jewels, 0,
769 TILE_HEIGHT*(bj->playboard[i][j].type),
770 STRIDE( SCREEN_MAIN,
771 BMPWIDTH_jewels,
772 BMPHEIGHT_jewels),
773 j*TILE_WIDTH,
774 (i-1)*TILE_HEIGHT+YOFS+
775 ((((TILE_HEIGHT<<10)*k)/8)>>10),
776 TILE_WIDTH, TILE_HEIGHT);
777 #else
778 rb->lcd_bitmap_part(jewels, 0,
779 TILE_HEIGHT*(bj->playboard[i][j].type),
780 STRIDE( SCREEN_MAIN,
781 BMPWIDTH_jewels,
782 BMPHEIGHT_jewels),
783 j*TILE_WIDTH,
784 (i-1)*TILE_HEIGHT+YOFS+
785 ((((TILE_HEIGHT<<10)*k)/8)>>10),
786 TILE_WIDTH, TILE_HEIGHT);
787 #endif
792 rb->lcd_update_rect(0, 0, TILE_WIDTH*8, LCD_HEIGHT);
793 jewels_setcolors();
795 /* framerate limiting */
796 currenttick = *rb->current_tick;
797 if(currenttick-lasttick < HZ/MAX_FPS) {
798 rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick));
799 } else {
800 rb->yield();
802 lasttick = currenttick;
805 /* shift jewels down */
806 for(j=0; j<BJ_WIDTH; j++) {
807 for(i=BJ_HEIGHT-1; i>=1; i--) {
808 if(bj->playboard[i-1][j].falling) {
809 bj->playboard[i][j].type = bj->playboard[i-1][j].type;
814 /* clear out top row */
815 for(j=0; j<BJ_WIDTH; j++) {
816 bj->playboard[0][j].type = 0;
819 /* mark everything not falling */
820 for(i=0; i<BJ_HEIGHT; i++) {
821 for(j=0; j<BJ_WIDTH; j++) {
822 bj->playboard[i][j].falling = false;
828 /*****************************************************************************
829 * jewels_clearjewels() finds all the connected rows and columns and
830 * calculates and returns the points earned.
831 ******************************************************************************/
832 static unsigned int jewels_clearjewels(struct game_context* bj) {
833 int i, j;
834 int last, run;
835 unsigned int points = 0;
837 /* check for connected rows */
838 for(i=1; i<BJ_HEIGHT; i++) {
839 last = 0;
840 run = 1;
841 for(j=0; j<BJ_WIDTH; j++) {
842 if(bj->playboard[i][j].type == last &&
843 bj->playboard[i][j].type != 0 &&
844 bj->playboard[i][j].type <= MAX_NUM_JEWELS) {
845 run++;
847 if(run == 3) {
848 bj->segments++;
849 points += bj->segments;
850 bj->playboard[i][j].delete = true;
851 bj->playboard[i][j-1].delete = true;
852 bj->playboard[i][j-2].delete = true;
853 } else if(run > 3) {
854 points++;
855 bj->playboard[i][j].delete = true;
857 } else {
858 run = 1;
859 last = bj->playboard[i][j].type;
864 /* check for connected columns */
865 for(j=0; j<BJ_WIDTH; j++) {
866 last = 0;
867 run = 1;
868 for(i=1; i<BJ_HEIGHT; i++) {
869 if(bj->playboard[i][j].type != 0 &&
870 bj->playboard[i][j].type == last &&
871 bj->playboard[i][j].type <= MAX_NUM_JEWELS) {
872 run++;
874 if(run == 3) {
875 bj->segments++;
876 points += bj->segments;
877 bj->playboard[i][j].delete = true;
878 bj->playboard[i-1][j].delete = true;
879 bj->playboard[i-2][j].delete = true;
880 } else if(run > 3) {
881 points++;
882 bj->playboard[i][j].delete = true;
884 } else {
885 run = 1;
886 last = bj->playboard[i][j].type;
891 /* clear deleted jewels */
892 for(i=1; i<BJ_HEIGHT; i++) {
893 for(j=0; j<BJ_WIDTH; j++) {
894 if(bj->playboard[i][j].delete) {
895 bj->playboard[i][j].delete = false;
896 bj->playboard[i][j].type = 0;
901 return points;
904 /*****************************************************************************
905 * jewels_runboard() runs the board until it settles in a fixed state and
906 * returns points earned.
907 ******************************************************************************/
908 static unsigned int jewels_runboard(struct game_context* bj) {
909 unsigned int points = 0;
910 unsigned int ret;
912 bj->segments = 0;
914 while((ret = jewels_clearjewels(bj)) > 0) {
915 points += ret;
916 jewels_drawboard(bj);
917 jewels_putjewels(bj);
920 return points;
923 /*****************************************************************************
924 * jewels_swapjewels() swaps two jewels as long as it results in points and
925 * returns points earned.
926 ******************************************************************************/
927 static unsigned int jewels_swapjewels(struct game_context* bj,
928 int x, int y, int direc) {
929 int k;
930 int horzmod, vertmod;
931 int movelen = 0;
932 bool undo = false;
933 unsigned int points = 0;
934 long lasttick, currenttick;
936 /* check for invalid parameters */
937 if(x < 0 || x >= BJ_WIDTH || y < 0 || y >= BJ_HEIGHT-1 ||
938 direc < SWAP_UP || direc > SWAP_LEFT) {
939 return 0;
942 /* check for invalid directions */
943 if((x == 0 && direc == SWAP_LEFT) ||
944 (x == BJ_WIDTH-1 && direc == SWAP_RIGHT) ||
945 (y == 0 && direc == SWAP_UP) ||
946 (y == BJ_HEIGHT-2 && direc == SWAP_DOWN)) {
947 return 0;
950 /* set direction variables */
951 horzmod = 0;
952 vertmod = 0;
953 switch(direc) {
954 case SWAP_UP:
955 vertmod = -1;
956 movelen = TILE_HEIGHT;
957 break;
958 case SWAP_RIGHT:
959 horzmod = 1;
960 movelen = TILE_WIDTH;
961 break;
962 case SWAP_DOWN:
963 vertmod = 1;
964 movelen = TILE_HEIGHT;
965 break;
966 case SWAP_LEFT:
967 horzmod = -1;
968 movelen = TILE_WIDTH;
969 break;
972 while(true) {
973 lasttick = *rb->current_tick;
975 /* animate swapping jewels */
976 for(k=0; k<=8; k++) {
977 /* clear old position */
978 #ifdef HAVE_LCD_COLOR
979 rb->lcd_set_foreground(jewels_bkgd[(x+y)%2]);
980 rb->lcd_fillrect(x*TILE_WIDTH,
981 y*TILE_HEIGHT+YOFS,
982 TILE_WIDTH, TILE_HEIGHT);
983 rb->lcd_set_foreground(jewels_bkgd[(x+horzmod+y+vertmod)%2]);
984 rb->lcd_fillrect((x+horzmod)*TILE_WIDTH,
985 (y+vertmod)*TILE_HEIGHT+YOFS,
986 TILE_WIDTH, TILE_HEIGHT);
987 #else
988 rb->lcd_set_drawmode(DRMODE_SOLID|DRMODE_INVERSEVID);
989 rb->lcd_fillrect(x*TILE_WIDTH,
990 y*TILE_HEIGHT+YOFS,
991 TILE_WIDTH, TILE_HEIGHT);
992 rb->lcd_fillrect((x+horzmod)*TILE_WIDTH,
993 (y+vertmod)*TILE_HEIGHT+YOFS,
994 TILE_WIDTH, TILE_HEIGHT);
995 rb->lcd_set_drawmode(DRMODE_SOLID);
996 #endif
997 /* draw new position */
998 #ifdef HAVE_LCD_COLOR
999 rb->lcd_bitmap_transparent_part(jewels,
1000 0, TILE_HEIGHT*(bj->playboard
1001 [y+1+vertmod][x+horzmod].type),
1002 STRIDE( SCREEN_MAIN,
1003 BMPWIDTH_jewels, BMPHEIGHT_jewels),
1004 (x+horzmod)*TILE_WIDTH-horzmod*
1005 ((((movelen<<10)*k)/8)>>10),
1006 (y+vertmod)*TILE_HEIGHT-vertmod*
1007 ((((movelen<<10)*k)/8)>>10)+YOFS,
1008 TILE_WIDTH, TILE_HEIGHT);
1009 rb->lcd_bitmap_transparent_part(jewels,
1010 0, TILE_HEIGHT*(bj->playboard[y+1][x].type),
1011 STRIDE( SCREEN_MAIN,
1012 BMPWIDTH_jewels, BMPHEIGHT_jewels),
1013 x*TILE_WIDTH+horzmod*
1014 ((((movelen<<10)*k)/8)>>10),
1015 y*TILE_HEIGHT+vertmod*
1016 ((((movelen<<10)*k)/8)>>10)+YOFS,
1017 TILE_WIDTH, TILE_HEIGHT);
1018 #else
1019 rb->lcd_bitmap_part(jewels,
1020 0, TILE_HEIGHT*(bj->playboard
1021 [y+1+vertmod][x+horzmod].type),
1022 STRIDE( SCREEN_MAIN,
1023 BMPWIDTH_jewels, BMPHEIGHT_jewels),
1024 (x+horzmod)*TILE_WIDTH-horzmod*
1025 ((((movelen<<10)*k)/8)>>10),
1026 (y+vertmod)*TILE_HEIGHT-vertmod*
1027 ((((movelen<<10)*k)/8)>>10)+YOFS,
1028 TILE_WIDTH, TILE_HEIGHT);
1029 rb->lcd_set_drawmode(DRMODE_FG);
1030 rb->lcd_bitmap_part(jewels,
1031 0, TILE_HEIGHT*(bj->playboard[y+1][x].type),
1032 STRIDE( SCREEN_MAIN,
1033 BMPWIDTH_jewels, BMPHEIGHT_jewels),
1034 x*TILE_WIDTH+horzmod*
1035 ((((movelen<<10)*k)/8)>>10),
1036 y*TILE_HEIGHT+vertmod*
1037 ((((movelen<<10)*k)/8)>>10)+YOFS,
1038 TILE_WIDTH, TILE_HEIGHT);
1039 rb->lcd_set_drawmode(DRMODE_SOLID);
1040 #endif
1042 rb->lcd_update_rect(0, 0, TILE_WIDTH*8, LCD_HEIGHT);
1043 jewels_setcolors();
1045 /* framerate limiting */
1046 currenttick = *rb->current_tick;
1047 if(currenttick-lasttick < HZ/MAX_FPS) {
1048 rb->sleep((HZ/MAX_FPS)-(currenttick-lasttick));
1049 } else {
1050 rb->yield();
1052 lasttick = currenttick;
1055 /* swap jewels */
1056 int temp = bj->playboard[y+1][x].type;
1057 bj->playboard[y+1][x].type =
1058 bj->playboard[y+1+vertmod][x+horzmod].type;
1059 bj->playboard[y+1+vertmod][x+horzmod].type = temp;
1061 if(undo) break;
1063 points = jewels_runboard(bj);
1064 if(points == 0) {
1065 undo = true;
1066 } else {
1067 break;
1071 return points;
1074 /*****************************************************************************
1075 * jewels_movesavail() uses pattern matching to see if there are any
1076 * available move left.
1077 ******************************************************************************/
1078 static bool jewels_movesavail(struct game_context* bj) {
1079 int i, j;
1080 bool moves = false;
1081 int mytype;
1083 for(i=1; i<BJ_HEIGHT; i++) {
1084 for(j=0; j<BJ_WIDTH; j++) {
1085 mytype = bj->playboard[i][j].type;
1086 if(mytype == 0 || mytype > MAX_NUM_JEWELS) continue;
1088 /* check horizontal patterns */
1089 if(j <= BJ_WIDTH-3) {
1090 if(i > 1) {
1091 if(bj->playboard[i-1][j+1].type == mytype) {
1092 if(bj->playboard[i-1][j+2].type == mytype)
1093 {moves = true; break;}
1094 if(bj->playboard[i][j+2].type == mytype)
1095 {moves = true; break;}
1097 if(bj->playboard[i][j+1].type == mytype) {
1098 if(bj->playboard[i-1][j+2].type == mytype)
1099 {moves = true; break;}
1103 if(j <= BJ_WIDTH-4) {
1104 if(bj->playboard[i][j+3].type == mytype) {
1105 if(bj->playboard[i][j+1].type == mytype)
1106 {moves = true; break;}
1107 if(bj->playboard[i][j+2].type == mytype)
1108 {moves = true; break;}
1112 if(i < BJ_HEIGHT-1) {
1113 if(bj->playboard[i][j+1].type == mytype) {
1114 if(bj->playboard[i+1][j+2].type == mytype)
1115 {moves = true; break;}
1117 if(bj->playboard[i+1][j+1].type == mytype) {
1118 if(bj->playboard[i][j+2].type == mytype)
1119 {moves = true; break;}
1120 if(bj->playboard[i+1][j+2].type == mytype)
1121 {moves = true; break;}
1126 /* check vertical patterns */
1127 if(i <= BJ_HEIGHT-3) {
1128 if(j > 0) {
1129 if(bj->playboard[i+1][j-1].type == mytype) {
1130 if(bj->playboard[i+2][j-1].type == mytype)
1131 {moves = true; break;}
1132 if(bj->playboard[i+2][j].type == mytype)
1133 {moves = true; break;}
1135 if(bj->playboard[i+1][j].type == mytype) {
1136 if(bj->playboard[i+2][j-1].type == mytype)
1137 {moves = true; break;}
1141 if(i <= BJ_HEIGHT-4) {
1142 if(bj->playboard[i+3][j].type == mytype) {
1143 if(bj->playboard[i+1][j].type == mytype)
1144 {moves = true; break;}
1145 if(bj->playboard[i+2][j].type == mytype)
1146 {moves = true; break;}
1150 if(j < BJ_WIDTH-1) {
1151 if(bj->playboard[i+1][j].type == mytype) {
1152 if(bj->playboard[i+2][j+1].type == mytype)
1153 {moves = true; break;}
1155 if(bj->playboard[i+1][j+1].type == mytype) {
1156 if(bj->playboard[i+2][j].type == mytype)
1157 {moves = true; break;}
1158 if (bj->playboard[i+2][j+1].type == mytype)
1159 {moves = true; break;}
1164 if(moves) break;
1166 return moves;
1169 /*****************************************************************************
1170 * jewels_puzzle_is_finished() checks if the puzzle is finished.
1171 ******************************************************************************/
1172 static bool jewels_puzzle_is_finished(struct game_context* bj) {
1173 unsigned int i, j;
1174 for(i=0; i<BJ_HEIGHT; i++) {
1175 for(j=0; j<BJ_WIDTH; j++) {
1176 int mytype = bj->playboard[i][j].type;
1177 if(mytype>MAX_NUM_JEWELS) {
1178 mytype -= MAX_NUM_JEWELS;
1179 if(mytype&PUZZLE_TILE_UP) {
1180 if(i==0 || bj->playboard[i-1][j].type<=MAX_NUM_JEWELS ||
1181 !((bj->playboard[i-1][j].type-MAX_NUM_JEWELS)
1182 &PUZZLE_TILE_DOWN))
1183 return false;
1185 if(mytype&PUZZLE_TILE_DOWN) {
1186 if(i==BJ_HEIGHT-1 ||
1187 bj->playboard[i+1][j].type<=MAX_NUM_JEWELS ||
1188 !((bj->playboard[i+1][j].type-MAX_NUM_JEWELS)
1189 &PUZZLE_TILE_UP))
1190 return false;
1192 if(mytype&PUZZLE_TILE_LEFT) {
1193 if(j==0 || bj->playboard[i][j-1].type<=MAX_NUM_JEWELS ||
1194 !((bj->playboard[i][j-1].type-MAX_NUM_JEWELS)
1195 &PUZZLE_TILE_RIGHT))
1196 return false;
1198 if(mytype&PUZZLE_TILE_RIGHT) {
1199 if(j==BJ_WIDTH-1 ||
1200 bj->playboard[i][j+1].type<=MAX_NUM_JEWELS ||
1201 !((bj->playboard[i][j+1].type-MAX_NUM_JEWELS)
1202 &PUZZLE_TILE_LEFT))
1203 return false;
1208 return true;
1211 /*****************************************************************************
1212 * jewels_initlevel() initialises a level.
1213 ******************************************************************************/
1214 static unsigned int jewels_initlevel(struct game_context* bj) {
1215 unsigned int points = 0;
1217 switch(bj->type) {
1218 case GAME_TYPE_NORMAL:
1219 bj->num_jewels = MAX_NUM_JEWELS;
1220 break;
1222 case GAME_TYPE_PUZZLE:
1224 unsigned int i, j;
1225 struct puzzle_tile *tile;
1227 bj->num_jewels = puzzle_levels[bj->level-1].num_jewels;
1229 for(i=0; i<BJ_HEIGHT; i++) {
1230 for(j=0; j<BJ_WIDTH; j++) {
1231 bj->playboard[i][j].type = (rb->rand()%bj->num_jewels)+1;
1232 bj->playboard[i][j].falling = false;
1233 bj->playboard[i][j].delete = false;
1236 jewels_runboard(bj);
1237 tile = puzzle_levels[bj->level-1].tiles;
1238 for(i=0; i<puzzle_levels[bj->level-1].num_tiles; i++, tile++) {
1239 bj->playboard[tile->y+1][tile->x].type = MAX_NUM_JEWELS
1240 +tile->tile_type;
1243 break;
1246 jewels_drawboard(bj);
1248 /* run the play board */
1249 jewels_putjewels(bj);
1250 points += jewels_runboard(bj);
1251 return points;
1254 /*****************************************************************************
1255 * jewels_init() initializes jewels data structures.
1256 ******************************************************************************/
1257 static void jewels_init(struct game_context* bj) {
1258 /* seed the rand generator */
1259 rb->srand(*rb->current_tick);
1261 bj->type = bj->tmp_type;
1262 bj->level = 1;
1263 bj->score = 0;
1264 bj->segments = 0;
1266 jewels_setcolors();
1268 /* clear playing board */
1269 rb->memset(bj->playboard, 0, sizeof(bj->playboard));
1270 do {
1271 bj->score += jewels_initlevel(bj);
1272 } while(!jewels_movesavail(bj));
1275 /*****************************************************************************
1276 * jewels_nextlevel() advances the game to the next bj->level and returns
1277 * points earned.
1278 ******************************************************************************/
1279 static void jewels_nextlevel(struct game_context* bj) {
1280 int i, x, y;
1281 unsigned int points = 0;
1283 switch(bj->type) {
1284 case GAME_TYPE_NORMAL:
1285 /* roll over score, change and display level */
1286 while(bj->score >= LEVEL_PTS) {
1287 bj->score -= LEVEL_PTS;
1288 bj->level++;
1289 rb->splashf(HZ*2, "Level %d", bj->level);
1290 jewels_drawboard(bj);
1293 /* randomly clear some jewels */
1294 for(i=0; i<16; i++) {
1295 x = rb->rand()%8;
1296 y = rb->rand()%8;
1298 if(bj->playboard[y][x].type != 0) {
1299 points++;
1300 bj->playboard[y][x].type = 0;
1303 break;
1305 case GAME_TYPE_PUZZLE:
1306 bj->level++;
1307 rb->splashf(HZ*2, "Level %d", bj->level);
1308 break;
1311 points += jewels_initlevel(bj);
1312 bj->score += points;
1315 static bool jewels_help(void)
1317 static char *help_text[] = {
1318 "Jewels", "", "Aim", "",
1319 "Swap", "pairs", "of", "jewels", "to", "form", "connected",
1320 "segments", "of", "three", "or", "more", "of", "the", "same",
1321 "type.", "",
1322 "The", "goal", "of", "the", "game", "is", "to", "score", "as", "many",
1323 "points", "as", "possible", "before", "running", "out", "of",
1324 "available", "moves.", "", "",
1325 "Controls", "",
1326 "Directions",
1327 #ifdef JEWELS_SCROLLWHEEL
1328 "or", "scroll",
1329 #endif
1330 "to", "move", "",
1331 HK_SELECT, "to", "select", "",
1332 HK_CANCEL, "to", "go", "to", "menu"
1334 static struct style_text formation[]={
1335 { 0, TEXT_CENTER|TEXT_UNDERLINE },
1336 { 2, C_RED },
1337 { 42, C_RED },
1338 LAST_STYLE_ITEM
1341 rb->lcd_setfont(FONT_UI);
1342 if (display_text(ARRAYLEN(help_text), help_text, formation, NULL, true))
1343 return true;
1344 rb->lcd_setfont(FONT_SYSFIXED);
1346 return false;
1349 static bool _ingame;
1350 static int jewels_menu_cb(int action, const struct menu_item_ex *this_item)
1352 int i = ((intptr_t)this_item);
1353 if(action == ACTION_REQUEST_MENUITEM
1354 && !_ingame && (i==0 || i==6))
1355 return ACTION_EXIT_MENUITEM;
1356 return action;
1358 /*****************************************************************************
1359 * jewels_game_menu() shows the game menu.
1360 ******************************************************************************/
1361 static int jewels_game_menu(struct game_context* bj, bool ingame)
1363 rb->button_clear_queue();
1364 int choice = 0;
1366 _ingame = ingame;
1368 static struct opt_items mode[] = {
1369 { "Normal", -1 },
1370 { "Puzzle", -1 },
1373 MENUITEM_STRINGLIST (main_menu, "Jewels Menu", jewels_menu_cb,
1374 "Resume Game",
1375 "Start New Game",
1376 "Mode",
1377 "Help",
1378 "High Scores",
1379 "Playback Control",
1380 "Quit without Saving",
1381 "Quit");
1383 while (1) {
1384 switch (rb->do_menu(&main_menu, &choice, NULL, false)) {
1385 case 0:
1386 jewels_setcolors();
1387 if(resume_file)
1388 rb->remove(SAVE_FILE);
1389 return 0;
1390 case 1:
1391 jewels_init(bj);
1392 return 0;
1393 case 2:
1394 rb->set_option("Mode", &bj->tmp_type, INT, mode, 2, NULL);
1395 break;
1396 case 3:
1397 if(jewels_help())
1398 return 1;
1399 break;
1400 case 4:
1401 highscore_show(-1, highscores, NUM_SCORES, true);
1402 break;
1403 case 5:
1404 playback_control(NULL);
1405 break;
1406 case 6:
1407 return 1;
1408 case 7:
1409 if (ingame) {
1410 rb->splash(HZ*1, "Saving game ...");
1411 jewels_savegame(bj);
1413 return 1;
1414 case MENU_ATTACHED_USB:
1415 return 1;
1416 default:
1417 break;
1422 static int jewels_main(struct game_context* bj) {
1423 int button;
1424 int position;
1425 bool selected = false;
1426 bool no_movesavail;
1427 int x=0, y=0;
1429 bool loaded = jewels_loadgame(bj);
1430 resume_file = loaded;
1431 if (jewels_game_menu(bj, loaded)!=0)
1432 return 0;
1434 resume_file = false;
1435 while(true) {
1436 no_movesavail = false;
1438 /* refresh the board */
1439 jewels_drawboard(bj);
1441 /* display the cursor */
1442 if(selected) {
1443 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1444 rb->lcd_fillrect(x*TILE_WIDTH, y*TILE_HEIGHT+YOFS,
1445 TILE_WIDTH, TILE_HEIGHT);
1446 rb->lcd_set_drawmode(DRMODE_SOLID);
1447 } else {
1448 rb->lcd_drawrect(x*TILE_WIDTH, y*TILE_HEIGHT+YOFS,
1449 TILE_WIDTH, TILE_HEIGHT);
1451 rb->lcd_update_rect(x*TILE_WIDTH, y*TILE_HEIGHT+YOFS,
1452 TILE_WIDTH, TILE_HEIGHT);
1454 /* handle game button presses */
1455 rb->yield();
1456 button = rb->button_get(true);
1457 switch(button){
1458 case JEWELS_LEFT: /* move cursor left */
1459 case (JEWELS_LEFT|BUTTON_REPEAT):
1460 if(selected) {
1461 bj->score += jewels_swapjewels(bj, x, y, SWAP_LEFT);
1462 selected = false;
1463 if (!jewels_movesavail(bj)) no_movesavail = true;
1464 } else {
1465 x = (x+BJ_WIDTH-1)%BJ_WIDTH;
1467 break;
1469 case JEWELS_RIGHT: /* move cursor right */
1470 case (JEWELS_RIGHT|BUTTON_REPEAT):
1471 if(selected) {
1472 bj->score += jewels_swapjewels(bj, x, y, SWAP_RIGHT);
1473 selected = false;
1474 if (!jewels_movesavail(bj)) no_movesavail = true;
1475 } else {
1476 x = (x+1)%BJ_WIDTH;
1478 break;
1480 case JEWELS_DOWN: /* move cursor down */
1481 case (JEWELS_DOWN|BUTTON_REPEAT):
1482 if(selected) {
1483 bj->score += jewels_swapjewels(bj, x, y, SWAP_DOWN);
1484 selected = false;
1485 if (!jewels_movesavail(bj)) no_movesavail = true;
1486 } else {
1487 y = (y+1)%(BJ_HEIGHT-1);
1489 break;
1491 case JEWELS_UP: /* move cursor up */
1492 case (JEWELS_UP|BUTTON_REPEAT):
1493 if(selected) {
1494 bj->score += jewels_swapjewels(bj, x, y, SWAP_UP);
1495 selected = false;
1496 if (!jewels_movesavail(bj)) no_movesavail = true;
1497 } else {
1498 y = (y+(BJ_HEIGHT-1)-1)%(BJ_HEIGHT-1);
1500 break;
1502 #ifdef JEWELS_SCROLLWHEEL
1503 case JEWELS_PREV: /* scroll backwards */
1504 case (JEWELS_PREV|BUTTON_REPEAT):
1505 if(!selected) {
1506 if(x == 0) {
1507 y = (y+(BJ_HEIGHT-1)-1)%(BJ_HEIGHT-1);
1509 x = (x+BJ_WIDTH-1)%BJ_WIDTH;
1511 break;
1513 case JEWELS_NEXT: /* scroll forwards */
1514 case (JEWELS_NEXT|BUTTON_REPEAT):
1515 if(!selected) {
1516 if(x == BJ_WIDTH-1) {
1517 y = (y+1)%(BJ_HEIGHT-1);
1519 x = (x+1)%BJ_WIDTH;
1521 break;
1522 #endif
1524 case JEWELS_SELECT: /* toggle selected */
1525 selected = !selected;
1526 break;
1528 #ifdef JEWELS_RC_CANCEL
1529 case JEWELS_RC_CANCEL:
1530 #endif
1531 case JEWELS_CANCEL: /* end game */
1532 if (jewels_game_menu(bj, true)!=0)
1533 return 0;
1534 break;
1536 default:
1537 if (rb->default_event_handler (button) == SYS_USB_CONNECTED)
1538 return PLUGIN_USB_CONNECTED;
1539 break;
1542 switch(bj->type) {
1543 case GAME_TYPE_NORMAL:
1544 if(bj->score >= LEVEL_PTS)
1545 jewels_nextlevel(bj);
1546 break;
1547 case GAME_TYPE_PUZZLE:
1548 if (jewels_puzzle_is_finished(bj)) {
1549 if (bj->level < NUM_PUZZLE_LEVELS) {
1550 jewels_nextlevel(bj);
1551 } else {
1552 rb->splash(2*HZ, "Congratulations!");
1553 rb->splash(2*HZ, "You have finished the game!");
1554 if (jewels_game_menu(bj, false)!=0) {
1555 return 0;
1558 break;
1562 if (no_movesavail) {
1563 switch(bj->type) {
1564 case GAME_TYPE_NORMAL:
1565 rb->splash(HZ*2, "Game Over!");
1566 rb->lcd_clear_display();
1567 bj->score += (bj->level-1)*LEVEL_PTS;
1568 position=highscore_update(bj->score, bj->level, "",
1569 highscores, NUM_SCORES);
1570 if (position != -1)
1572 if (position == 0)
1573 rb->splash(HZ*2, "New High Score");
1574 highscore_show(position, highscores, NUM_SCORES, true);
1576 break;
1577 case GAME_TYPE_PUZZLE:
1578 rb->splash(2*HZ, "Game Over");
1579 break;
1581 if (jewels_game_menu(bj, false)!=0) {
1582 return 0;
1588 /* this is the plugin entry point */
1589 enum plugin_status plugin_start(const void* parameter)
1591 (void)parameter;
1593 /* load high scores */
1594 highscore_load(SCORE_FILE, highscores, NUM_SCORES);
1596 rb->lcd_setfont(FONT_SYSFIXED);
1597 #if LCD_DEPTH > 1
1598 rb->lcd_set_backdrop(NULL);
1599 #endif
1601 struct game_context bj;
1602 bj.tmp_type = GAME_TYPE_NORMAL;
1603 jewels_main(&bj);
1604 highscore_save(SCORE_FILE, highscores, NUM_SCORES);
1605 rb->lcd_setfont(FONT_UI);
1607 return PLUGIN_OK;