Back to index

gcompris  8.2.2
erase.c
Go to the documentation of this file.
00001 /* gcompris - erase.c
00002  *
00003  * Copyright (C) 2001 Bruno Coudoin
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU General Public License as published by
00007  *   the Free Software Foundation; either version 2 of the License, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details.
00014  *
00015  *   You should have received a copy of the GNU General Public License
00016  *   along with this program; if not, write to the Free Software
00017  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #include <string.h>
00021 
00022 #include "gcompris/gcompris.h"
00023 
00024 #define SOUNDLISTFILE PACKAGE
00025 #define MAX_LAYERS 3
00026 
00027 static GcomprisBoard *gcomprisBoard = NULL;
00028 static gboolean board_paused = TRUE;
00029 
00030 static void    start_board (GcomprisBoard *agcomprisBoard);
00031 static void    pause_board (gboolean pause);
00032 static void    end_board (void);
00033 static gboolean       is_our_board (GcomprisBoard *gcomprisBoard);
00034 static void    set_level (guint level);
00035 static int     gamewon;
00036 static void    game_won(void);
00037 
00038 static GnomeCanvasGroup *boardRootItem = NULL;
00039 
00040 static GnomeCanvasItem      *erase_create_item(int layer);
00041 static void           erase_destroy_all_items(void);
00042 static void           erase_next_level(void);
00043 static gint           item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00044 static void           shuffle_image_list(char *list[], int size);
00045 
00046 static int number_of_item = 0;
00047 static int number_of_item_x = 0;
00048 static int number_of_item_y = 0;
00049 
00050 static gint timer_id = 0;
00051 
00052 // Default Double click distance to restore on exit.
00053 static gint DefaultDoubleClicDistance;
00054 
00055 static gint DoubleClicLevel[6]= {  1000, 750, 600, 500, 400, 250};
00056 
00057 #define NORMAL 0
00058 #define CLIC   1
00059 #define DOUBLECLIC 2
00060 
00061 static gint board_mode =  NORMAL;
00062 
00063 // List of images to use in the game
00064 static gchar *imageList[] =
00065   {
00066     "gcompris/animals/bear001.jpg",
00067     "gcompris/animals/black-headed-gull.jpg",
00068     "gcompris/animals/butterfly.jpg",
00069     "gcompris/animals/donkey.jpg",
00070     "gcompris/animals/elephanteauxgc.jpg",
00071     "gcompris/animals/flamentrosegc.jpg",
00072     "gcompris/animals/girafegc.jpg",
00073     "gcompris/animals/hypogc.jpg",
00074     "gcompris/animals/joybear001.jpg",
00075     "gcompris/animals/joybear002.jpg",
00076     "gcompris/animals/jumentmulassieregc.jpg",
00077     "gcompris/animals/malaybear002.jpg",
00078     "gcompris/animals/pigeon.jpg",
00079     "gcompris/animals/polabear011.jpg",
00080     "gcompris/animals/polarbear001.jpg",
00081     "gcompris/animals/poolbears001.jpg",
00082     "gcompris/animals/rhinogc.jpg",
00083     "gcompris/animals/singegc.jpg",
00084     "gcompris/animals/spectbear001.jpg",
00085     "gcompris/animals/tetegorillegc.jpg",
00086     "gcompris/animals/tiger1_by_Ralf_Schmode.jpg",
00087     "gcompris/animals/tigercub003.jpg",
00088     "gcompris/animals/tigerdrink001.jpg",
00089     "gcompris/animals/tigerplay001.jpg",
00090     "gcompris/animals/horses.jpg",
00091     "gcompris/animals/horses2.jpg",
00092     "gcompris/animals/squirrel.jpg",
00093     "gcompris/animals/sheep_irish.jpg",
00094     "gcompris/animals/sheep_irish2.jpg",
00095     "gcompris/animals/cow.jpg",
00096     "gcompris/animals/maki1.jpg",
00097     "gcompris/animals/maki2.jpg",
00098     "gcompris/animals/maki3.jpg",
00099     "gcompris/animals/maki4.jpg",
00100     "gcompris/animals/maki5.jpg",
00101     "gcompris/animals/maki6.jpg",
00102   };
00103 #define NUMBER_OF_IMAGES G_N_ELEMENTS(imageList)
00104 
00105 /* Store the image index to use */
00106 static int current_image;
00107 
00108 /* Description of this plugin */
00109 static BoardPlugin menu_bp =
00110   {
00111     NULL,
00112     NULL,
00113     N_("Move the mouse"),
00114     N_("Move the mouse to erase the area and discover the background"),
00115     "Bruno Coudoin <bruno.coudoin@free.fr>",
00116     NULL,
00117     NULL,
00118     NULL,
00119     NULL,
00120     start_board,
00121     pause_board,
00122     end_board,
00123     is_our_board,
00124     NULL,
00125     NULL,
00126     set_level,
00127     NULL,
00128     NULL,
00129     NULL,
00130     NULL
00131   };
00132 
00133 /*
00134  * Main entry point mandatory for each Gcompris's game
00135  * ---------------------------------------------------
00136  *
00137  */
00138 
00139 GET_BPLUGIN_INFO(erase)
00140 
00141 /*
00142  * in : boolean TRUE = PAUSE : FALSE = CONTINUE
00143  *
00144  */
00145 static void pause_board (gboolean pause)
00146 {
00147   if(gcomprisBoard==NULL)
00148     return;
00149 
00150   if (timer_id) {
00151     gtk_timeout_remove (timer_id);
00152     timer_id = 0;
00153   }
00154 
00155   if(gamewon == TRUE && pause == FALSE) /* the game is won */
00156     {
00157       game_won();
00158     }
00159 
00160   board_paused = pause;
00161 }
00162 
00163 /*
00164  */
00165 static void start_board (GcomprisBoard *agcomprisBoard)
00166 {
00167 
00168   if(agcomprisBoard!=NULL)
00169     {
00170       gcomprisBoard=agcomprisBoard;
00171       gcomprisBoard->level=1;
00172       gcomprisBoard->maxlevel=6;
00173       gcomprisBoard->sublevel=1;
00174       gcomprisBoard->number_of_sublevel=10; /* Go to next level after this number of 'play' */
00175       gc_score_start(SCORESTYLE_NOTE,
00176                         gcomprisBoard->width - 220,
00177                         gcomprisBoard->height - 50,
00178                         gcomprisBoard->number_of_sublevel);
00179       gc_bar_set(GC_BAR_LEVEL);
00180 
00181       if (strcmp(gcomprisBoard->mode,"double_clic")==0)
00182        board_mode = DOUBLECLIC;
00183       else if (strcmp(gcomprisBoard->mode,"clic")==0)
00184        board_mode = CLIC;
00185       else
00186        board_mode = NORMAL;
00187 
00188       if (board_mode == DOUBLECLIC){
00189        GtkSettings *DefaultsGtkSettings = gtk_settings_get_default ();
00190 
00191        if (DefaultsGtkSettings == NULL) {
00192          g_warning("Couldn't get GTK settings");
00193        } else {
00194          g_object_get(G_OBJECT(DefaultsGtkSettings),
00195                      "gtk-double-click-time", &DefaultDoubleClicDistance, NULL);
00196 
00197          g_warning("Double-click default value %d.",DefaultDoubleClicDistance);
00198        }
00199 
00200        gdk_display_set_double_click_time( gdk_display_get_default(),
00201                                       DoubleClicLevel[gcomprisBoard->level-1]);
00202        g_warning("Double-click value is now %d.",DoubleClicLevel[gcomprisBoard->level-1]);
00203       }
00204 
00205       current_image = 0;
00206       shuffle_image_list(imageList, NUMBER_OF_IMAGES);
00207 
00208       erase_next_level();
00209 
00210       gamewon = FALSE;
00211       pause_board(FALSE);
00212     }
00213 }
00214 /* ======================================= */
00215 static void end_board ()
00216 {
00217   if (board_mode == DOUBLECLIC){
00218     gdk_display_set_double_click_time( gdk_display_get_default(),
00219                                       DefaultDoubleClicDistance);
00220     g_warning("Double click value is now %d.",DefaultDoubleClicDistance);
00221   }
00222   if(gcomprisBoard!=NULL)
00223     {
00224       pause_board(TRUE);
00225       gc_score_end();
00226       erase_destroy_all_items();
00227     }
00228   gcomprisBoard = NULL;
00229 }
00230 
00231 /* ======================================= */
00232 static void set_level (guint level)
00233 {
00234 
00235   if(gcomprisBoard!=NULL)
00236     {
00237       gcomprisBoard->level=level;
00238       gcomprisBoard->sublevel=1;
00239       erase_next_level();
00240     }
00241   if (board_mode == DOUBLECLIC){
00242     gdk_display_set_double_click_time( gdk_display_get_default(),
00243                                    DoubleClicLevel[gcomprisBoard->level-1]);
00244     g_warning("Double click value is now %d.",DoubleClicLevel[gcomprisBoard->level-1]);
00245   }
00246 
00247 }
00248 /* ======================================= */
00249 static gboolean is_our_board (GcomprisBoard *gcomprisBoard)
00250 {
00251   if (gcomprisBoard)
00252     {
00253       if(g_strcasecmp(gcomprisBoard->type, "erase")==0)
00254        {
00255          /* Set the plugin entry */
00256          gcomprisBoard->plugin=&menu_bp;
00257 
00258          return TRUE;
00259        }
00260     }
00261   return FALSE;
00262 }
00263 
00264 /*-------------------------------------------------------------------------------*/
00265 /*-------------------------------------------------------------------------------*/
00266 /* set initial values for the next level */
00267 static void erase_next_level()
00268 {
00269   int layers = 1;
00270 
00271   gc_set_background(gnome_canvas_root(gcomprisBoard->canvas),
00272                        imageList[current_image++]);
00273 
00274   if(current_image>=NUMBER_OF_IMAGES)
00275     current_image=0;
00276 
00277   gc_bar_set_level(gcomprisBoard);
00278 
00279   erase_destroy_all_items();
00280   gamewon = FALSE;
00281 
00282   /* Select level difficulty */
00283 
00284   if (board_mode != NORMAL) {
00285     number_of_item_x = 5;
00286     number_of_item_y = 5;
00287   } else {
00288     number_of_item_x = ((gcomprisBoard->level+1)%2+1)*5;
00289     number_of_item_y = ((gcomprisBoard->level+1)%2+1)*5;
00290   }
00291 
00292   /* Select the number of layer depending on the level */
00293 
00294   if (board_mode != DOUBLECLIC){
00295     if(gcomprisBoard->level>4)
00296       layers = 3;
00297     else if(gcomprisBoard->level>2)
00298       layers = 2;
00299   }
00300 
00301   /* Try the next level */
00302   erase_create_item(layers);
00303 
00304   gc_score_set(gcomprisBoard->sublevel);
00305 
00306 }
00307 
00308 /* ==================================== */
00309 /* Destroy all the items */
00310 static void erase_destroy_all_items()
00311 {
00312   if (timer_id) {
00313     gtk_timeout_remove (timer_id);
00314     timer_id = 0;
00315   }
00316 
00317   if(boardRootItem!=NULL)
00318     gtk_object_destroy (GTK_OBJECT(boardRootItem));
00319 
00320   boardRootItem = NULL;
00321 }
00322 /* ==================================== */
00323 static GnomeCanvasItem *erase_create_item(int layer)
00324 {
00325   int i,j;
00326   int ix, jy;
00327   GnomeCanvasItem *item = NULL;
00328   GdkPixbuf *pixmap[MAX_LAYERS];
00329 
00330   g_assert(layer<=MAX_LAYERS);
00331 
00332   boardRootItem = GNOME_CANVAS_GROUP(
00333                                  gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
00334                                                      gnome_canvas_group_get_type (),
00335                                                      "x", (double) 0,
00336                                                      "y", (double) 0,
00337                                                      NULL));
00338 
00339   number_of_item = 0;
00340 
00341   for(i=0; i<MAX_LAYERS; i++)
00342     pixmap[i] = NULL;
00343 
00344   if(layer>0)
00345     pixmap[0] = gc_pixmap_load("images/transparent_square.png");
00346 
00347   if(layer>1)
00348     pixmap[1] = gc_pixmap_load("images/water_spot.png");
00349 
00350   if(layer>2)
00351     pixmap[2] = gc_pixmap_load("images/water_drop.png");
00352 
00353   for(i=0,ix=0; i<BOARDWIDTH; i+=BOARDWIDTH/number_of_item_x, ix++)
00354     {
00355       for(j=0, jy=0; j<BOARDHEIGHT; j+=BOARDHEIGHT/number_of_item_y, jy++)
00356        {
00357          int current_layer = layer;
00358 
00359          if ((board_mode != NORMAL) && ((ix+jy) %2 == 0))
00360            continue;
00361 
00362          while(current_layer--)
00363            {
00364              double w = (BOARDWIDTH/number_of_item_x) *  (1.0 - (0.3 * current_layer));
00365              double h = (BOARDHEIGHT/number_of_item_y) * (1.0 - (0.3 * current_layer));
00366              double x = i + ((BOARDWIDTH/number_of_item_x)  - w) / 2;
00367              double y = j + ((BOARDHEIGHT/number_of_item_y) - h) / 2;
00368 
00369              item = gnome_canvas_item_new (boardRootItem,
00370                                        gnome_canvas_pixbuf_get_type (),
00371                                        "pixbuf", pixmap[current_layer],
00372                                        "x", x,
00373                                        "y", y,
00374                                        "width", w,
00375                                        "height", h,
00376                                        "width_set", TRUE,
00377                                        "height_set", TRUE,
00378                                        "anchor", GTK_ANCHOR_NW,
00379                                        NULL);
00380 
00381              gtk_signal_connect(GTK_OBJECT(item), "event", (GtkSignalFunc) item_event, NULL);
00382              number_of_item++;
00383            }
00384        }
00385     }
00386 
00387   for(i=0; i<MAX_LAYERS; i++)
00388     if(pixmap[i])
00389       gdk_pixbuf_unref(pixmap[i]);
00390 
00391   return NULL;
00392 }
00393 
00394 static void bonus() {
00395   gc_bonus_display(gamewon, BONUS_SMILEY);
00396   timer_id = 0;
00397 }
00398 
00399 static void finished() {
00400   gc_bonus_end_display(BOARD_FINISHED_RANDOM);
00401   timer_id = 0;
00402 }
00403 
00404 /* ==================================== */
00405 static void game_won()
00406 {
00407   gcomprisBoard->sublevel++;
00408   gc_score_set(gcomprisBoard->sublevel);
00409 
00410   if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) {
00411     /* Try the next level */
00412     gcomprisBoard->sublevel=1;
00413     gcomprisBoard->level++;
00414     if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
00415       timer_id = gtk_timeout_add (2000, (GtkFunction) finished, NULL);
00416       return;
00417     }
00418     if (board_mode == DOUBLECLIC){
00419       gdk_display_set_double_click_time( gdk_display_get_default(),
00420                                     DoubleClicLevel[gcomprisBoard->level-1]);
00421       g_warning("Double click value is now %d.", DoubleClicLevel[gcomprisBoard->level-1]);
00422     }
00423 
00424     gc_sound_play_ogg ("sounds/bonus.ogg", NULL);
00425   }
00426   erase_next_level();
00427 }
00428 
00429 /* ==================================== */
00430 static gint
00431 item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
00432 {
00433 
00434   if(board_paused)
00435     return FALSE;
00436 
00437   if (event->type == GDK_MOTION_NOTIFY)
00438     return FALSE;
00439 
00440   if (board_mode == NORMAL)
00441     if (event->type != GDK_ENTER_NOTIFY)
00442       return FALSE;
00443 
00444   if (board_mode == CLIC)
00445     if (event->type != GDK_BUTTON_PRESS)
00446       return FALSE;
00447 
00448   if (board_mode == DOUBLECLIC)
00449     if ((event->type != GDK_BUTTON_PRESS) &
00450        (event->type != GDK_2BUTTON_PRESS) &
00451        (event->type != GDK_BUTTON_RELEASE))
00452       return FALSE;
00453 
00454 
00455   if (board_mode == DOUBLECLIC){
00456     if (event->type == GDK_BUTTON_PRESS){
00457       return FALSE;
00458     }
00459     if (event->type == GDK_BUTTON_RELEASE){
00460       return FALSE;
00461     }
00462   }
00463 
00464   gtk_object_destroy(GTK_OBJECT(item));
00465 
00466   if(--number_of_item == 0)
00467     {
00468       gamewon = TRUE;
00469       erase_destroy_all_items();
00470       timer_id = gtk_timeout_add (4000, (GtkFunction) bonus, NULL);
00471     }
00472 
00473   return FALSE;
00474 }
00475 
00484 void shuffle_image_list(char *list[], int size)
00485 {
00486   int i;
00487 
00488   for(i=0; i<size; i++)
00489     {
00490       int random1 = RAND(0, size-1);
00491       int random2 = RAND(0, size-1);
00492       char *olditem;
00493 
00494       olditem = list[random2];
00495       list[random2] = list[random1];
00496       list[random1] = olditem;
00497     }
00498 }