/* SQUAREBLOXX v0.8 by Andreas Kruschinski*/ #include "plugin.h" #ifdef HAVE_LCD_BITMAP PLUGIN_HEADER void draw_mark(int x, int y, int markx, int marky, bool color, bool check); /*This is the return of sqb()*/ enum sqb_status { SQB_NEXT, SQB_LOSE, SQB_QUIT, SQB_USB }; /* key configurations*/ #if CONFIG_KEYPAD == RECORDER_PAD # define SQ_UP BUTTON_UP # define SQ_DOWN BUTTON_DOWN # define SQ_QUIT BUTTON_OFF # define SQ_START BUTTON_ON # define SQ_MARK BUTTON_ON # define SQ_RIGHT (BUTTON_F1 | BUTTON_RIGHT) # define SQ_LEFT (BUTTON_F1 | BUTTON_LEFT) #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \ (CONFIG_KEYPAD == IRIVER_H300_PAD) # define SQ_UP BUTTON_UP # define SQ_DOWN BUTTON_DOWN # define SQ_QUIT BUTTON_OFF # define SQ_MARK BUTTON_SELECT # define SQ_RIGHT (BUTTON_ON | BUTTON_RIGHT) # define SQ_LEFT (BUTTON_ON | BUTTON_LEFT) #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \ (CONFIG_KEYPAD == IPOD_3G_PAD) # define SQ_UP BUTTON_SCROLL_BACK # define SQ_DOWN BUTTON_SCROLL_FWD # define SQ_QUIT BUTTON_MENU # define SQ_MARK BUTTON_SELECT # define SQ_RIGHT (BUTTON_SELECT | BUTTON_RIGHT) # define SQ_LEFT (BUTTON_SELECT | BUTTON_LEFT) #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD) # define SQ_UP BUTTON_UP # define SQ_DOWN BUTTON_DOWN # define SQ_QUIT BUTTON_POWER # define SQ_START BUTTON_REC # define SQ_MARK BUTTON_SELECT # define SQ_RIGHT (BUTTON_PLAY | BUTTON_RIGHT) # define SQ_LEFT (BUTTON_PLAY | BUTTON_LEFT) #elif (CONFIG_KEYPAD == GIGABEAT_PAD) # define SQ_UP BUTTON_UP # define SQ_DOWN BUTTON_DOWN # define SQ_QUIT BUTTON_A # define SQ_START BUTTON_SELECT # define SQ_MARK BUTTON_SELECT # define SQ_RIGHT (BUTTON_SELECT | BUTTON_RIGHT) # define SQ_LEFT (BUTTON_SELECT | BUTTON_LEFT) #elif (CONFIG_KEYPAD == SANSA_E200_PAD) # define SQ_UP BUTTON_UP # define SQ_DOWN BUTTON_DOWN # define SQ_QUIT BUTTON_POWER # define SQ_START BUTTON_SELECT # define SQ_MARK BUTTON_SELECT # define SQ_RIGHT (BUTTON_SELECT | BUTTON_RIGHT) # define SQ_LEFT (BUTTON_SELECT | BUTTON_LEFT) #elif (CONFIG_KEYPAD == IRIVER_H10_PAD) # define SQ_UP BUTTON_SCROLL_UP # define SQ_DOWN BUTTON_SCROLL_DOWN # define SQ_QUIT BUTTON_POWER # define SQ_START BUTTON_FF # define SQ_MARK BUTTON_PLAY # define SQ_RIGHT (BUTTON_RIGHT | BUTTON_PLAY) # define SQ_LEFT (BUTTON_LEFT | BUTTON_PLAY) #else # warning Missing key definitions for this keypad #endif static struct plugin_api *rb; #ifdef HAVE_LCD_COLOR # define Blue LCD_RGBPACK( 10, 10, 200 ) # define Red LCD_RGBPACK( 200, 10, 10 ) # define Green LCD_RGBPACK( 10, 200, 10 ) # define Yellow LCD_RGBPACK( 200, 200, 10 ) # define White LCD_RGBPACK( 220, 220, 220 ) # define BackgroundColor LCD_RGBPACK( 128, 128, 128 ) /*the tilesize in dependency of the lcd size*/ # if LCD_HEIGHT == 176 # define tilesize 15 # define textpos 20 # elif LCD_HEIGHT == 240 # define tilesize 22 # define textpos 28 # elif LCD_HEIGHT == 320 # define tilesize 22 # define textpos 28 # else # define tilesize 11 # define textpos 14 # endif #elif LCD_DEPTH > 1 # define tilesize 12 #else # define tilesize 8 #endif typedef struct tile { unsigned char done : 1; unsigned char color : 4; } tile; #define MAX_HEIGHT (10) #define MAX_WIDTH (10) /* number of tiles*/ int nt = 5; /* number of colors*/ int nc = 2; int level = 1; int tiles_left; int points = 0; /*the time left for this level*/ int timemax; int timeact; int leveltime = 5000; /*possibibilities*/ int possies = 0; /*starts a userdefined game*/ bool user; tile field[MAX_HEIGHT][MAX_WIDTH]; /*This one checks the possibilities in the game*/ void check_possi() { possies = 0; int i,j,x,y; for( i = 0; i < (nt - 1); i++ ) { for( j = 0; j < (nt - 1); j++ ) { for( x = i + 1; x < nt; x++ ) { for( y = j + 1; y < nt; y++ ) { if ( ( field[i][j].color == field[x][y].color ) && ( field[i][y].color == field[x][j].color ) && ( field[i][j].color == field[i][y].color )) possies = possies + 1; } } } } } /*this one initializes the array of tiles*/ void sqb_init( void ) { int i,j; int c; for( i = 0; i < nt; i++ ) { for( j = 0; j < nt; j++ ) { c = ( rb->rand()%nc ); field[i][j].done = 0; field[i][j].color = c; } } } /*The levels*/ void levels() { switch (level){ case 1: leveltime = 6000; nt = 5; nc = 2; points = 0; break; case 2: leveltime = 5000; nt = 6; nc = 2; break; case 3: leveltime = 4000; nt = 7; nc = 2; break; case 4: leveltime = 5000; nt = 5; nc = 3; break; case 5: leveltime = 5000; nt = 6; nc = 3; break; case 6: leveltime = 4000; nt = 8; nc = 2; break; case 7: leveltime = 5000; nt = 10; nc = 2; break; case 8: leveltime = 3000; nt = 8; nc = 3; break; case 9: leveltime = 5000; nt = 5; nc = 4; break; case 10: leveltime = 5000; nt = 7; nc = 4; break; case 11: leveltime = 3000; nt = 10; nc = 3; break; } } /*The main menu of the game*/ enum sqb_status menu( void ) { int selection, result = SQB_QUIT; bool menu_quit = false; MENUITEM_STRINGLIST(menu, "Squarebloxx Menu",NULL,"Play Squarebloxx", "Play Userdefined Game", "Number of Tiles", "Number of Colors", "Quit"); #ifdef HAVE_LCD_COLOR rb->lcd_set_foreground(rb->global_settings->fg_color); rb->lcd_set_background(rb->global_settings->bg_color); #endif while (!menu_quit) { selection=rb->do_menu(&menu,&selection); switch(selection) { case 0: user = false; result = SQB_NEXT; /* start playing */ menu_quit = true; break; case 1: user = true; points = 0; result = SQB_NEXT; menu_quit = true; break; case 2: rb->set_int("Number of Tiles", "%", UNIT_INT, &nt, NULL, 1, 5, 10, NULL ); break; case 3: rb->set_int("Number of Colors", "", UNIT_INT, &nc, NULL, 1, 2, 4, NULL ); break; default: result = SQB_QUIT; /* quit program */ menu_quit = true; break; } } return result; } /*this is the progress bar of the time*/ void draw_progress(void) { int x; x = ((timemax - timeact) * (LCD_HEIGHT - 1) /leveltime); rb->lcd_set_foreground( Blue ); rb->lcd_fillrect((LCD_WIDTH - 4), 0, 3, (LCD_HEIGHT - 1)); rb->lcd_set_foreground( White ); rb->lcd_fillrect((LCD_WIDTH - 4), (LCD_HEIGHT - 1) - x, 3, (LCD_HEIGHT - 1)); } /*draws the array on the screen*/ void sqb_draw_field( void ) { int i, j; for( i = 0; i < nt; i++ ) { for( j = 0; j < nt; j++ ) { switch( field[i][j].color) { case 0: rb->lcd_set_foreground( Red ); break; case 1: rb->lcd_set_foreground( Yellow ); break; case 2: rb->lcd_set_foreground( Blue ); break; case 3: rb->lcd_set_foreground( Green ); break; default: rb->lcd_set_foreground( White ); break; } rb->lcd_fillrect((i * (1 + tilesize) + 1), (j * (1 + tilesize) + 1), tilesize, tilesize); if (field[i][j].done == 0) { rb->lcd_set_foreground( White ); rb->lcd_hline( 3 + ( i * (tilesize + 1) ) , 8 + ( i * (tilesize + 1) ), 3 + ( j * (tilesize + 1) ) ); rb->lcd_vline( 3 + ( i * (tilesize + 1) ), 3 + ( j * (tilesize + 1) ), 8 + ( j * (tilesize + 1) ) ); } } } } void draw_cursor(int x, int y, bool color) { if(color) rb->lcd_set_foreground( White ); else rb->lcd_set_foreground( BackgroundColor ); rb->lcd_drawrect( ( x * ( tilesize + 1)), ( y * ( tilesize + 1)), ( tilesize + 2 ), ( tilesize + 2)); } /* this checks if the selected area is valid*/ void check_mark(int x1, int y1, int x2, int y2) { int i, j, c, num; num = 0; if ( ( field[x1][y1].color == field[x1][y2].color ) && ( field[x2][y1].color == field[x2][y2].color ) && ( field[x1][y1].color == field[x2][y2].color ) && ( ( x1 - x2) != 0) && (( y1 - y2) != 0)) { do{ for( i = x1; i <= x2; i++ ) { for( j = y1; j <= y2; j++ ) { if ( field[i][j].done == 0) num = num + 1; c = ( rb->rand()%nc ); field[i][j].done = 1; field[i][j].color = c; } } check_possi(); } while(possies == 0); /*the points and left time and tiles are calculated here*/ tiles_left = tiles_left - num; points = points + (9 * num) + ((x2-x1)*(y2-y1)); if (timemax < (timeact + leveltime - ((x2-x1)*(y2-y1)*100))) timemax = timemax + ((x2-x1)*(y2-y1)*100); else timemax = timeact + leveltime; } /*after the selected area is checked and randomized, the field is drawn*/ sqb_draw_field(); draw_mark(x1, y1, x2, y2, false, false); } /* draws the current selection of tiles*/ void draw_mark(int x, int y, int markx, int marky, bool color, bool check) { int x1, x2, y1, y2, i, j; if (x > markx) { x1 = markx; x2 = x; } else { x1 = x; x2 = markx; } if (y > marky) { y1 = marky; y2 = y; } else { y1 = y; y2 = marky; } if (!check) { for (i = x1; i <= x2; i++) for (j = y1; j <= y2; j++) draw_cursor(i, j, color); } else check_mark(x1, y1, x2, y2); } /*The main function*/ enum sqb_status sqb( void ) { int x, y, i; int button, lastbutton = BUTTON_NONE; /*coordinates of the cursor and the flag*/ int oldx, oldy; bool mark = false; int markx, marky; char string[17]; if (level == 1 || user) if( ( i = menu() ) != SQB_NEXT ) return i; x = y = 0; /* if user is true, there are no levels*/ if (user == false) levels(); tiles_left = nt*nt; rb->lcd_set_background( BackgroundColor ); rb->lcd_clear_display(); possies = 0; while (possies == 0) { sqb_init(); check_possi(); } sqb_draw_field(); draw_cursor(x, y, true); timeact = *rb->current_tick; timemax = timeact + leveltime; /* MAIN LOOP*/ while (true) { rb->snprintf(string,sizeof(string),"Left:%d",tiles_left); rb->lcd_puts(0,textpos,string); rb->snprintf(string,sizeof(string),"Points:%d",points); rb->lcd_puts(10,textpos,string); timeact = *rb->current_tick; draw_progress(); rb->lcd_update(); if (timeact >= timemax) return SQB_LOSE; switch (button = rb->button_get(false)) { case SQ_QUIT: return SQB_QUIT; case BUTTON_RIGHT: if (x < nt - 1) { oldx = x; x = x + 1; } break; case SQ_DOWN: if (y < nt - 1) { oldy = y; y = y + 1; } break; case BUTTON_LEFT: if (x > 0) { oldx = x; x = x - 1; } break; case SQ_UP: if (y > 0) { oldy = y; y = y - 1; } break; case SQ_MARK: if (mark){ mark = false; draw_mark(x,y, markx, marky, false, true); check_possi(); if (tiles_left == 0){ level = level + 1; return SQB_NEXT; } draw_cursor(x, y, true); } else { mark = true; markx = x; marky = y; } break; default: break; } if (button != BUTTON_NONE) lastbutton = button; if (oldx != x || oldy != y) { if (mark){ draw_mark(oldx, oldy, markx, marky, false, false); draw_mark(x,y, markx, marky, true, false); } else { draw_cursor(oldx, oldy, false); draw_cursor(x, y, true); } } oldx = x; oldy = y; } } enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { bool exit = false; (void)parameter; rb = api; while( !exit ) { switch( sqb() ) { case SQB_NEXT: if (level == 12 || user == true) { rb->splash( HZ, "You win! %d", points); level = 1; } else rb->splash( HZ, "LEVEL %d", level); rb->lcd_clear_display(); break; case SQB_LOSE: rb->splash( HZ, "Game Over! %d", points); level = 1; rb->lcd_clear_display(); break; case SQB_USB: return PLUGIN_USB_CONNECTED; case SQB_QUIT: exit = true; break; default: break; } } return PLUGIN_OK; } #endif