Back to index

gcompris  8.2.2
clickgame.c
Go to the documentation of this file.
00001 /* gcompris - clickgame.c
00002  *
00003  * Time-stamp: <2006/08/21 23:30:07 bruno>
00004  *
00005  * Copyright (C) 2000 Bruno Coudoin
00006  *
00007  *   This program is free software; you can redistribute it and/or modify
00008  *   it under the terms of the GNU General Public License as published by
00009  *   the Free Software Foundation; either version 2 of the License, or
00010  *   (at your option) any later version.
00011  *
00012  *   This program is distributed in the hope that it will be useful,
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *   GNU General Public License for more details.
00016  *
00017  *   You should have received a copy of the GNU General Public License
00018  *   along with this program; if not, write to the Free Software
00019  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  */
00021 
00022 #ifdef __APPLE__
00023 #   include <sys/types.h>
00024 #endif
00025 #include <string.h>
00026 
00027 #include "gcompris/gcompris.h"
00028 #include "gcompris/pixbuf_util.h"
00029 
00030 #include <libart_lgpl/art_affine.h>
00031 
00032 #define SOUNDLISTFILE PACKAGE
00033 
00034 static gboolean board_paused = TRUE;
00035 
00036 static GList *item_list = NULL;     // onscreen fish
00037 static GList *item2del_list = NULL;
00038 
00039 static GcomprisBoard *gcomprisBoard = NULL;
00040 
00041 static gulong event_handle_id;
00042 static gint move_items_id = 0;
00043 static gint animate_id = 0;
00044 static gint drop_items_id = 0;
00045 
00046 typedef struct {
00047   double speed;
00048   gint fright;
00049   gint stun;
00050   gint currentItem;
00051   GnomeCanvasItem *rootitem;
00052   GSList *fwd_frames;
00053   GSList *rev_frames;
00054   GSList *cur_frames;  // points to fwd_frames or rev_frames
00055 } FishItem;
00056 
00057 static void    clickgame_start (GcomprisBoard *agcomprisBoard);
00058 static void    clickgame_pause (gboolean pause);
00059 static void    clickgame_end (void);
00060 static gboolean       clickgame_is_our_board (GcomprisBoard *gcomprisBoard);
00061 static void    clickgame_set_level (guint level);
00062 static void    clickgame_config(void);
00063 
00064 static FishItem *clickgame_create_item();
00065 static gint    clickgame_drop_items (GtkWidget *widget, gpointer data);
00066 static gint    clickgame_move_items (GtkWidget *widget, gpointer data);
00067 static gint    clickgame_animate_items (GtkWidget *widget, gpointer data);
00068 static void    clickgame_destroy_item(FishItem *fishitem);
00069 static void    clickgame_destroy_items(void);
00070 static void    clickgame_destroy_all_items(void);
00071 static void    clickgame_next_level(void);
00072 
00073 static int gamewon;
00074 static void    game_won(void);
00075 
00076 static  guint32              fallSpeed = 0;
00077 static  double               moveSpeed = 0.0;
00078 static  double               imageZoom = 0.0;
00079 
00080 
00081 static const gchar *smallFish[] =
00082   {
00083     "%s/cichlid1_%d.png",
00084     "%s/cichlid4_%d.png",
00085     "%s/collaris_%d.png",
00086     "%s/discus3_%d.png",
00087     "%s/eel_%d.png",
00088     "%s/teeth_%d.png",
00089     "%s/f02_%d.png",
00090   };
00091 #define NUM_SMALLFISH G_N_ELEMENTS(smallFish)
00092 
00093 static const gchar *medFish[] =
00094   {
00095     "%s/f00_%d.png",
00096     "%s/f01_%d.png",
00097     "%s/f03_%d.png",
00098     "%s/f04_%d.png",
00099     "%s/f05_%d.png",
00100     "%s/f06_%d.png",
00101     "%s/f11_%d.png",
00102     "%s/f12_%d.png",
00103     "%s/f13_%d.png",
00104     "%s/QueenAngel_%d.png",
00105     "%s/six_barred_%d.png",
00106     "%s/shark1_%d.png",
00107   };
00108 #define NUM_MEDFISH G_N_ELEMENTS(medFish)
00109 
00110 static const gchar *bigFish[] =
00111   {
00112     "%s/blueking2_%d.png",
00113     "%s/butfish_%d.png",
00114     "%s/discus2_%d.png",
00115     "%s/f07_%d.png",
00116     "%s/f08_%d.png",
00117     "%s/f09_%d.png",
00118     "%s/f10_%d.png",
00119     "%s/manta_%d.png",
00120     "%s/newf1_%d.png",
00121   };
00122 #define NUM_BIGFISH G_N_ELEMENTS(bigFish)
00123 
00124 /* Description of this plugin */
00125 static BoardPlugin menu_bp =
00126 {
00127    NULL,
00128    NULL,
00129    "Click On Me",
00130    "Click with the mouse on all swimming fish before they leave the fishtank",
00131    "Bruno Coudoin <bruno.coudoin@free.fr>",
00132    NULL,
00133    NULL,
00134    NULL,
00135    NULL,
00136    clickgame_start,
00137    clickgame_pause,
00138    clickgame_end,
00139    clickgame_is_our_board,
00140    NULL,
00141    NULL,
00142    clickgame_set_level,
00143    clickgame_config,
00144    NULL,
00145    NULL,
00146    NULL
00147 };
00148 
00149 /*
00150  * Main entry point mandatory for each Gcompris's game
00151  * ---------------------------------------------------
00152  *
00153  */
00154 
00155 GET_BPLUGIN_INFO(clickgame)
00156 
00157 /*
00158  * in : boolean TRUE = PAUSE : FALSE = CONTINUE
00159  *
00160  */
00161 static void clickgame_pause (gboolean pause)
00162 {
00163   if(gcomprisBoard==NULL)
00164     return;
00165 
00166   if(gamewon == TRUE && pause == FALSE) /* the game is won */
00167     {
00168       game_won();
00169     }
00170 
00171   if(pause)
00172     {
00173       if (move_items_id) {
00174        gtk_timeout_remove (move_items_id);
00175        move_items_id = 0;
00176       }
00177       if (animate_id) {
00178        gtk_timeout_remove (animate_id);
00179        animate_id = 0;
00180       }
00181       if (drop_items_id) {
00182        gtk_timeout_remove (drop_items_id);
00183        drop_items_id = 0;
00184       }
00185     }
00186   else
00187     {
00188       if(!drop_items_id) {
00189        drop_items_id = gtk_timeout_add (200,
00190                                     (GtkFunction) clickgame_drop_items, NULL);
00191       }
00192       if(!move_items_id) {
00193        move_items_id = gtk_timeout_add (200, (GtkFunction) clickgame_move_items, NULL);
00194       }
00195       if(!animate_id) {
00196        animate_id = gtk_timeout_add (200, (GtkFunction) clickgame_animate_items, NULL);
00197       }
00198     }
00199 
00200   board_paused = pause;
00201 }
00202 
00203 static void
00204 fish_reverse_direction (FishItem *fish)
00205 {
00206   fish->speed = -fish->speed;
00207 
00208   gnome_canvas_item_hide(g_slist_nth_data(fish->cur_frames,
00209                                      fish->currentItem));
00210 
00211   fish->cur_frames =
00212     fish->speed<0? fish->rev_frames : fish->fwd_frames;
00213 
00214   gnome_canvas_item_show(g_slist_nth_data(fish->cur_frames,
00215                                      fish->currentItem));
00216 }
00217 
00218 static void
00219 fish_gobble (FishItem *fishitem)
00220 {
00221   clickgame_destroy_item(fishitem);
00222   gc_sound_play_ogg ("sounds/gobble.ogg", NULL);
00223 
00224   gcomprisBoard->sublevel++;
00225   gc_score_set(gcomprisBoard->sublevel);
00226 
00227   if(gcomprisBoard->sublevel>=gcomprisBoard->number_of_sublevel) {
00228     gamewon = TRUE;
00229     clickgame_destroy_all_items();
00230     gc_bonus_display(gamewon, BONUS_FLOWER);
00231     return;
00232   }
00233   /* Drop a new item now to speed up the game */
00234   if(g_list_length(item_list)==0)
00235     {
00236       /* Remove any pending new item creation to sync the falls */
00237       if (drop_items_id)
00238        gtk_timeout_remove (drop_items_id);
00239       drop_items_id =
00240        gtk_timeout_add (0, (GtkFunction) clickgame_drop_items, NULL);
00241     }
00242 }
00243 
00244 static gint
00245 canvas_event(GnomeCanvas *canvas, GdkEvent *event)
00246 {
00247   FishItem *fish;
00248   double mouse_x = event->button.x;
00249   double mouse_y = event->button.y;
00250   int ii;
00251 
00252   switch (event->type)
00253      {
00254      case GDK_BUTTON_PRESS:
00255        switch(event->button.button)
00256          {
00257          case 1:
00258          case 2:
00259          case 3:
00260            if (gcomprisBoard->level >= 3 &&
00261               !(event->button.state & GDK_SHIFT_MASK)) {
00262             for (ii=0; (fish=g_list_nth_data(item_list, ii)); ii++) {
00263               double dx, dy, near;
00264               double x1,x2,y1,y2;
00265               int react;
00266               gnome_canvas_item_get_bounds (fish->rootitem, &x1, &y1, &x2, &y2);
00267               //printf("fish %d\n", ii);
00268 
00269               dy = (mouse_y - (y1 + (y2 - y1) / 2)) / ((y2 - y1) / 2);
00270               //printf("dy = %.2f\n", dy);
00271               if (fabs(dy) > 3) continue;
00272 
00273               dx = (mouse_x - (x1 + (x2 - x1) / 2)) / ((x2 - x1) / 2);
00274               //printf("dx = %.2f\n", dx);
00275               if (fabs(dx) > 3) continue;
00276 
00277               // 0 to .9
00278               near = (sqrt(2*3*3) - sqrt(dx*dx + dy*dy))/(1.11 * sqrt(2*3*3));
00279               //printf("near = %.2f\n", near);
00280 
00281               react = ((rand() % 1000 < near * 1000) +
00282                      (rand() % 1000 < near * 1000));
00283               if (react) {
00284                if (gnome_canvas_get_item_at (canvas, mouse_x, mouse_y) !=
00285                    g_slist_nth_data (fish->cur_frames, fish->currentItem) &&
00286                    (dx > 0) ^ (fish->speed < 0))
00287                  fish_reverse_direction (fish);
00288                else
00289                  react += 1;
00290               }
00291               if (react >= 2)
00292                fish->fright +=
00293                  (1000 + rand() % (int)(near * 2000)) / moveSpeed;
00294             }
00295           }
00296           break;
00297         default: break;
00298         }
00299        break;
00300      default:
00301        break;
00302      }
00303 
00304   return FALSE;
00305 }
00306 
00307 static gint
00308 item_event(GnomeCanvasItem *item, GdkEvent *event, FishItem *fishitem)
00309 {
00310    static double x, y;
00311    double new_x, new_y;
00312    GdkCursor *fleur;
00313    static int dragging;
00314    double item_x, item_y;
00315 
00316    if(!gcomprisBoard)
00317      return FALSE;
00318 
00319    if(board_paused)
00320      return FALSE;
00321 
00322    item_x = event->button.x;
00323    item_y = event->button.y;
00324    gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
00325 
00326    switch (event->type)
00327      {
00328      case GDK_BUTTON_PRESS:
00329        switch(event->button.button)
00330          {
00331          case 1:
00332          case 2:
00333          case 3:
00334            if (event->button.state & GDK_SHIFT_MASK)
00335              {
00336                x = item_x;
00337                y = item_y;
00338 
00339                fleur = gdk_cursor_new(GDK_FLEUR);
00340                gc_canvas_item_grab(item,
00341                                       GDK_POINTER_MOTION_MASK |
00342                                       GDK_BUTTON_RELEASE_MASK,
00343                                       fleur,
00344                                       event->button.time);
00345                gdk_cursor_destroy(fleur);
00346                dragging = TRUE;
00347              }
00348            else
00349              {
00350               if (gcomprisBoard->level >= 5 && !fishitem->stun) {
00351                fishitem->stun = 500 * (1 + gcomprisBoard->maxlevel - gcomprisBoard->level) / moveSpeed;
00352                fishitem->fright += 500 / moveSpeed;
00353               } else {
00354                fish_gobble (fishitem);
00355               }
00356              }
00357            break;
00358 
00359          case 4:
00360           /* fish up */
00361           gnome_canvas_item_move(item, 0.0, -3.0);
00362           break;
00363 
00364          case 5:
00365           /* fish down */
00366           gnome_canvas_item_move(item, 0.0, 3.0);
00367           break;
00368 
00369          default:
00370            break;
00371          }
00372        break;
00373 
00374      case GDK_MOTION_NOTIFY:
00375        if (dragging && (event->motion.state & GDK_BUTTON1_MASK))
00376          {
00377            new_x = item_x;
00378            new_y = item_y;
00379 
00380            gnome_canvas_item_move(item, new_x - x, new_y - y);
00381            x = new_x;
00382            y = new_y;
00383          }
00384        break;
00385 
00386      case GDK_BUTTON_RELEASE:
00387        if(dragging)
00388         {
00389           gc_canvas_item_ungrab(item, event->button.time);
00390           dragging = FALSE;
00391         }
00392        break;
00393 
00394      default:
00395        break;
00396      }
00397 
00398    return FALSE;
00399  }
00400 
00401 /*
00402  */
00403 static void clickgame_start (GcomprisBoard *agcomprisBoard)
00404 {
00405   if (!agcomprisBoard)
00406     return;
00407 
00408   gcomprisBoard = agcomprisBoard;
00409 
00410   /* set initial values for this level */
00411   gcomprisBoard->level = 1;
00412   gcomprisBoard->maxlevel=6;
00413   gcomprisBoard->number_of_sublevel=10; /* Go to next level after this number of 'play' */
00414   gc_score_start(SCORESTYLE_NOTE,
00415                gcomprisBoard->width - 220,
00416                gcomprisBoard->height - 50,
00417                gcomprisBoard->number_of_sublevel);
00418   gc_bar_set(GC_BAR_LEVEL);
00419 
00420   event_handle_id =
00421     gtk_signal_connect(GTK_OBJECT(gcomprisBoard->canvas), "event",
00422                      (GtkSignalFunc) canvas_event, 0);
00423   clickgame_next_level();
00424 
00425   clickgame_pause(FALSE);
00426 }
00427 
00428 static void
00429 clickgame_end ()
00430 {
00431   if(gcomprisBoard!=NULL)
00432     {
00433       clickgame_pause(TRUE);
00434       gc_score_end();
00435       clickgame_destroy_all_items();
00436       gtk_signal_disconnect(GTK_OBJECT(gcomprisBoard->canvas),
00437                          event_handle_id);
00438       gcomprisBoard->level = 1;       // Restart this game to zero
00439     }
00440   gcomprisBoard = NULL;
00441 }
00442 
00443 static void
00444 clickgame_set_level (guint level)
00445 {
00446 
00447   if(gcomprisBoard!=NULL)
00448     {
00449       gcomprisBoard->level=level;
00450       clickgame_next_level();
00451     }
00452 }
00453 
00454 static gboolean
00455 clickgame_is_our_board (GcomprisBoard *board)
00456 {
00457   if (board)
00458     {
00459       if(g_strcasecmp(board->type, "clickgame")==0)
00460        {
00461          /* Set the plugin entry */
00462          board->plugin=&menu_bp;
00463 
00464          return TRUE;
00465        }
00466     }
00467   return FALSE;
00468 }
00469 
00470 static void
00471 clickgame_config ()
00472 {
00473   if(gcomprisBoard!=NULL)
00474     {
00475       clickgame_pause(TRUE);
00476     }
00477 }
00478 
00479 /*-------------------------------------------------------------------------------*/
00480 /*-------------------------------------------------------------------------------*/
00481 /*-------------------------------------------------------------------------------*/
00482 /*-------------------------------------------------------------------------------*/
00483 
00484 /* set initial values for the next level */
00485 static void clickgame_next_level()
00486 {
00487   static /*const*/ gchar *bglist[] =
00488     {
00489       "clickgame/nur00523.jpg",
00490       "clickgame/nur03006.jpg",
00491       "clickgame/nur03011.jpg",
00492       "clickgame/nur03010.jpg",
00493       "clickgame/nur03013.jpg",
00494       "clickgame/nur03505.jpg"
00495     };
00496 
00497   int bgx = gcomprisBoard->level - 1;
00498 
00499   if (bgx < 0 || G_N_ELEMENTS(bglist) <= bgx)
00500     bgx = G_N_ELEMENTS(bglist) - 1;
00501 
00502   gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), bglist[bgx]);
00503 
00504   gc_bar_set_level(gcomprisBoard);
00505 
00506   /* Try the next level */
00507   moveSpeed=100+(40/(gcomprisBoard->level));
00508   fallSpeed=5000-gcomprisBoard->level*200;
00509   imageZoom = 0.75 + 0.25 * ((gcomprisBoard->maxlevel - gcomprisBoard->level + 1) / gcomprisBoard->maxlevel);
00510   gcomprisBoard->sublevel=0;
00511   gc_score_set(gcomprisBoard->sublevel);
00512 
00513   while (g_list_length (item_list) < 3) {
00514     FishItem *fish = clickgame_create_item();
00515     if (!fish) break;
00516     gnome_canvas_item_move(fish->rootitem,
00517                           fish->speed * (rand() % 200), 0.0);
00518   }
00519 }
00520 
00521 
00522 static void clickgame_animate_item(FishItem *fishitem)
00523 {
00524   gint currentItem;
00525 
00526   /* Manage the animation */
00527   currentItem = fishitem->currentItem;
00528   fishitem->currentItem++;
00529   if(fishitem->currentItem >= g_slist_length(fishitem->cur_frames))
00530     fishitem->currentItem=0;
00531 
00532   gnome_canvas_item_show((GnomeCanvasItem *)g_slist_nth_data(fishitem->cur_frames,
00533                                                       fishitem->currentItem));
00534 
00535   gnome_canvas_item_hide((GnomeCanvasItem *)g_slist_nth_data(fishitem->cur_frames,
00536                                                       currentItem));
00537 }
00538 
00539 static void clickgame_move_item(FishItem *fishitem)
00540 {
00541   double sp = fishitem->speed;
00542   double x1, y1, x2, y2;
00543 
00544   GnomeCanvasItem *item = fishitem->rootitem;
00545 
00546   if (fishitem->stun) {
00547     --fishitem->stun;
00548     sp *= .1 + (rand() % 100) / 1000.0;
00549   } else if (fishitem->fright) {
00550     --fishitem->fright;
00551     sp *= 3 + (rand() % 3000) / 1000.0;
00552   }
00553   gnome_canvas_item_move(item, sp, 0.0);
00554 
00555 
00556   gnome_canvas_item_get_bounds    (item,
00557                                &x1,
00558                                &y1,
00559                                &x2,
00560                                &y2);
00561 
00562   if(fishitem->speed>0)
00563     {
00564       if(x1>gcomprisBoard->width) {
00565        item2del_list = g_list_append (item2del_list, fishitem);
00566        gc_sound_play_ogg ("crash", NULL);
00567       }
00568     }
00569   else
00570     {
00571       if(x2<0) {
00572        item2del_list = g_list_append (item2del_list, fishitem);
00573        gc_sound_play_ogg ("crash", NULL);
00574       }
00575     }
00576 
00577   while (g_list_length (item_list) < 3) {
00578     FishItem *fish = clickgame_create_item();
00579     if (!fish) break;
00580     gnome_canvas_item_move(fish->rootitem,
00581                           fish->speed * (rand() % 200), 0.0);
00582   }
00583 }
00584 
00585 static void clickgame_destroy_item(FishItem *fishitem)
00586 {
00587   GnomeCanvasItem *item = fishitem->rootitem;
00588 
00589   item_list = g_list_remove (item_list, fishitem);
00590   item2del_list = g_list_remove (item2del_list, fishitem);
00591   gtk_object_destroy (GTK_OBJECT(item));
00592 
00593   g_slist_free (fishitem->fwd_frames);
00594   g_slist_free (fishitem->rev_frames);
00595   g_free(fishitem);
00596 }
00597 
00598 /* Destroy items that falls out of the canvas */
00599 static void clickgame_destroy_items()
00600 {
00601   FishItem *fishitem;
00602 
00603   while(g_list_length(item2del_list)>0)
00604     {
00605       fishitem = g_list_nth_data(item2del_list, 0);
00606       clickgame_destroy_item(fishitem);
00607     }
00608 }
00609 
00610 /* Destroy all the items */
00611 static void clickgame_destroy_all_items()
00612 {
00613   while(item_list)
00614     {
00615       FishItem *fishitem = g_list_nth_data(item_list, 0);
00616       clickgame_destroy_item(fishitem);
00617     }
00618 }
00619 
00620 /*
00621  * This does the moves of the game items on the play canvas
00622  *
00623  */
00624 static gint clickgame_move_items (GtkWidget *widget, gpointer data)
00625 {
00626   g_list_foreach (item_list, (GFunc) clickgame_move_item, NULL);
00627 
00628   /* Destroy items that falls out of the canvas */
00629   clickgame_destroy_items();
00630 
00631   move_items_id = gtk_timeout_add (moveSpeed,
00632                                (GtkFunction) clickgame_move_items, NULL);
00633 
00634   return(FALSE);
00635 }
00636 
00637 /*
00638  * This does the icon animation
00639  *
00640  */
00641 static gint clickgame_animate_items (GtkWidget *widget, gpointer data)
00642 {
00643   g_list_foreach (item_list, (GFunc) clickgame_animate_item, NULL);
00644 
00645   animate_id = gtk_timeout_add (1000,
00646                            (GtkFunction) clickgame_animate_items, NULL);
00647 
00648   return(FALSE);
00649 }
00650 
00651 static GSList *load_random_fish(gboolean smallish)
00652 {
00653   int fish;
00654   const gchar **extraFish;
00655   const gchar **surpriseFish;
00656   int num_extra;
00657   int num_surprise;
00658 
00659   if (smallish) {
00660     extraFish = smallFish;
00661     num_extra = NUM_SMALLFISH;
00662     surpriseFish = bigFish;
00663     num_surprise = NUM_BIGFISH;
00664   } else {
00665     extraFish = bigFish;
00666     num_extra = NUM_BIGFISH;
00667     surpriseFish = smallFish;
00668     num_surprise = NUM_SMALLFISH;
00669   }
00670 
00671   fish = rand() % (NUM_MEDFISH + num_extra + 2);
00672 
00673   const gchar *path;
00674   if (fish < NUM_MEDFISH) {
00675     path = medFish[fish];
00676   } else if (fish < NUM_MEDFISH + num_extra) {
00677     path = extraFish[fish - NUM_MEDFISH];
00678   } else {
00679     fish = rand() % num_surprise;
00680     path = surpriseFish[fish];
00681   }
00682 
00683   int frame = 0;
00684   GSList *ilist = 0;
00685   while(1)
00686     {
00687       if (frame) {
00688        gchar *exists = gc_file_find_absolute (path, "fishes", frame);
00689        g_free (exists);
00690        if (!exists) break;
00691       }
00692 
00693       GdkPixbuf *pixmap = gc_pixmap_load (path, "fishes", frame);
00694       if (!pixmap) break;
00695 
00696       ilist = g_slist_prepend (ilist, pixmap);
00697       ++frame;
00698     }
00699   return g_slist_reverse (ilist);
00700 }
00701 
00702 static FishItem *
00703 clickgame_create_item()
00704 {
00705   GnomeCanvasGroup *parent = gnome_canvas_root(gcomprisBoard->canvas);
00706   GdkPixbuf *pixmap = NULL;
00707   GdkPixbuf *pixmap2 = NULL;
00708   GnomeCanvasItem *rootitem;
00709   FishItem *fishitem;
00710   double x;
00711   gint i, length;
00712   GSList *ilist;
00713 
00714   /* Avoid to have too much items displayed */
00715   if(g_list_length(item_list)>5)
00716     return NULL;
00717 
00718   // select smallish fish on even levels, also see imageZoom
00719   ilist = load_random_fish (!(gcomprisBoard->level & 1));
00720 
00721   fishitem = g_malloc(sizeof(FishItem));
00722   fishitem->currentItem   = 0;
00723   fishitem->speed = (double)(rand()%(60))/10 - 3;
00724   fishitem->fright = 0;
00725   fishitem->stun = 0;
00726   fishitem->fwd_frames = NULL;
00727   fishitem->rev_frames = NULL;
00728 
00729   pixmap = (GdkPixbuf *)g_slist_nth_data(ilist, 0);
00730 
00731   if(pixmap==NULL)
00732     return NULL;
00733 
00734   if(fishitem->speed<0)
00735     {
00736       x = (double) gcomprisBoard->width;
00737       fishitem->speed=MIN(fishitem->speed, -1);
00738     }
00739   else
00740     {
00741       x = (double) -gdk_pixbuf_get_width(pixmap)*imageZoom;
00742       fishitem->speed=MAX(fishitem->speed, 1);
00743     }
00744 
00745   rootitem = \
00746     gnome_canvas_item_new (parent,
00747                         gnome_canvas_group_get_type (),
00748                         "x", x,
00749                         "y", (double)(rand()%(gcomprisBoard->height-
00750                                            (guint)(gdk_pixbuf_get_height(pixmap)*
00751                                                   imageZoom))),
00752                         NULL);
00753 
00754   gtk_signal_connect(GTK_OBJECT(rootitem), "event",
00755                    (GtkSignalFunc) item_event, fishitem);
00756 
00757   fishitem->rootitem = rootitem;
00758 
00759   length = g_slist_length(ilist);
00760   for(i=0; i<length; i++)
00761     {
00762       GnomeCanvasItem *fwd, *rev;
00763 
00764       pixmap = (GdkPixbuf *)g_slist_nth_data(ilist, i);
00765       pixmap2 = pixbuf_copy_mirror(pixmap, TRUE, FALSE);
00766 
00767       fwd = gnome_canvas_item_new (GNOME_CANVAS_GROUP(rootitem),
00768                                gnome_canvas_pixbuf_get_type (),
00769                                "pixbuf", pixmap,
00770                                "x", 0.0,
00771                                "y", 0.0,
00772                                "width", (double) gdk_pixbuf_get_width(pixmap)*imageZoom,
00773                                "height", (double) gdk_pixbuf_get_height(pixmap)*imageZoom,
00774                                "width_set", TRUE,
00775                                "height_set", TRUE,
00776                                NULL);
00777       rev = gnome_canvas_item_new (GNOME_CANVAS_GROUP(rootitem),
00778                                gnome_canvas_pixbuf_get_type (),
00779                                "pixbuf", pixmap2,
00780                                "x", 0.0,
00781                                "y", 0.0,
00782                                "width", (double) gdk_pixbuf_get_width(pixmap2)*imageZoom,
00783                                "height", (double) gdk_pixbuf_get_height(pixmap2)*imageZoom,
00784                                "width_set", TRUE,
00785                                "height_set", TRUE,
00786                                NULL);
00787       gdk_pixbuf_unref(pixmap);
00788       gdk_pixbuf_unref(pixmap2);
00789 
00790       fishitem->fwd_frames = g_slist_prepend (fishitem->fwd_frames, fwd);
00791       fishitem->rev_frames = g_slist_prepend (fishitem->rev_frames, rev);
00792 
00793       gnome_canvas_item_hide (fwd);
00794       gnome_canvas_item_hide (rev);
00795     }
00796 
00797   g_slist_free (ilist);
00798 
00799   fishitem->fwd_frames = g_slist_reverse (fishitem->fwd_frames);
00800   fishitem->rev_frames = g_slist_reverse (fishitem->rev_frames);
00801 
00802   fishitem->cur_frames =
00803     fishitem->speed<0? fishitem->rev_frames : fishitem->fwd_frames;
00804 
00805   gnome_canvas_item_show(g_slist_nth_data(fishitem->cur_frames,
00806                                      fishitem->currentItem));
00807 
00808   item_list = g_list_append (item_list, fishitem);
00809 
00810   return (fishitem);
00811 }
00812 
00813 /*
00814  * This is called on a low frequency and is used to drop new items
00815  *
00816  */
00817 static gint clickgame_drop_items (GtkWidget *widget, gpointer data)
00818 {
00819   clickgame_create_item();
00820 
00821   drop_items_id = gtk_timeout_add (fallSpeed,
00822                                (GtkFunction) clickgame_drop_items, NULL);
00823   return (FALSE);
00824 }
00825 
00826 /* ==================================== */
00827 static void game_won()
00828 {
00829   gcomprisBoard->sublevel++;
00830 
00831   if(gcomprisBoard->sublevel>=gcomprisBoard->number_of_sublevel) {
00832     /* Try the next level */
00833     gcomprisBoard->sublevel=0;
00834     gcomprisBoard->level++;
00835     if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
00836       gc_bonus_end_display(BOARD_FINISHED_RANDOM);
00837       return;
00838     }
00839     gc_sound_play_ogg ("sounds/bonus.ogg", NULL);
00840   }
00841   clickgame_next_level();
00842 }
00843