Back to index

gcompris  8.2.2
crane.c
Go to the documentation of this file.
00001 /* gcompris - crane.c
00002  *
00003  * Copyright (C) 2005 Marc BRUN
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
00025 #define SOUNDLISTFILE PACKAGE
00026 
00027 #define CRANE_BUTTON_SPACE  60     // Space between a pair (left/right or up/down)
00028 #define CRANE_BUTTON_LEFT_X 85
00029 #define CRANE_BUTTON_LEFT_Y 447
00030 #define CRANE_BUTTON_RIGHT_X (CRANE_BUTTON_LEFT_X + CRANE_BUTTON_SPACE)
00031 #define CRANE_BUTTON_RIGHT_Y CRANE_BUTTON_LEFT_Y + 2
00032 #define CRANE_BUTTON_UP_X   220
00033 #define CRANE_BUTTON_UP_Y   CRANE_BUTTON_LEFT_Y - 5
00034 #define CRANE_BUTTON_DOWN_X CRANE_BUTTON_UP_X + CRANE_BUTTON_SPACE
00035 #define CRANE_BUTTON_DOWN_Y CRANE_BUTTON_UP_Y
00036 
00037 #define CRANE_FRAME_X 38
00038 #define CRANE_FRAME_Y 137
00039 #define CRANE_ROPE_Y  CRANE_FRAME_Y - 32
00040 #define CRANE_FRAME_COLUMN 6
00041 #define CRANE_FRAME_LINE 5
00042 #define CRANE_FRAME_CELL 52
00043 #define CRANE_FRAME_BORDER 6
00044 #define CRANE_FRAME_IMAGE_SIZE 40
00045 
00046 #define CRANE_FRAME_MODEL_X 460
00047 #define CRANE_FRAME_MODEL_Y 50
00048 
00049 
00050 #define DOWN  0             /* Warning ordering is important */
00051 #define UP    1
00052 #define LEFT  2
00053 #define RIGHT 3
00054 
00055 #define MAX_LEVEL 6  /* Don't raise this number except if putting more values
00056                       * in pixmap[] array, in place_item function
00057                       */
00058 
00059 // List of images to use in the game
00060 static gchar *imageList[] =
00061   {
00062     "crane/water_spot1.png",
00063     "crane/water_spot2.png",
00064     "crane/water_drop1.png",
00065     "crane/water_drop2.png",
00066     "crane/tux.png",
00067     "crane/triangle1.png",
00068     "crane/triangle2.png",
00069     "crane/rectangle1.png",
00070     "crane/rectangle2.png",
00071     "crane/square1.png",
00072     "crane/square2.png",
00073     "crane/bulb.png",
00074     "crane/letter-a.png",
00075     "crane/letter-b.png"
00076   };
00077 
00078 #define NB_ELEMENT G_N_ELEMENTS(imageList)
00079 
00080 // Types
00081 
00082 // Structure describes the objects of the frames
00083 typedef struct {
00084   GdkPixbuf *pixmap;
00085   double x;
00086   double y;
00087   double h;
00088   double w;
00089 } crane_object;
00090 
00091 // Structure decribes a movement
00092 typedef struct {
00093   int x;             // x movement
00094   int y;             // y movement
00095   int nb;            // how much of x/y movement (to give a smooth effect) ?
00096 } move_object;
00097 
00098 // Global variables
00099 static GcomprisBoard *gcomprisBoard = NULL;
00100 static gboolean board_paused = TRUE;
00101 static GnomeCanvasGroup *boardRootItem = NULL;
00102 static GnomeCanvasItem *selected_item = NULL;
00103 static GnomeCanvasItem *red_hands = NULL;
00104 static GnomeCanvasItem *crane_rope_item = NULL;
00105 static gint timer_id = 0;
00106 static gint nb_move = 0;
00107 static gboolean moving = FALSE;
00108 static move_object my_move;
00109 static int list_answer[CRANE_FRAME_LINE * CRANE_FRAME_COLUMN];
00110 static int list_game[CRANE_FRAME_LINE * CRANE_FRAME_COLUMN];
00111 static GnomeCanvasPoints *crane_rope;
00112 
00113 // gcompris functions
00114 static void    start_board (GcomprisBoard *agcomprisBoard);
00115 static void    pause_board (gboolean pause);
00116 static void    end_board (void);
00117 static gboolean       is_our_board (GcomprisBoard *gcomprisBoard);
00118 static void    set_level (guint level);
00119 static int     gamewon;
00120 static void    game_won(void);
00121 
00122 static GnomeCanvasItem      *crane_create_item();
00123 static void           crane_destroy_all_items(void);
00124 static void           crane_next_level(void);
00125 
00126 // crane functions
00127 static gint           item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00128 static gint           arrow_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00129 static guint          smooth_move(move_object *);
00130 static int            is_allowed_move (double, double, int);
00131 static void           shuffle_list(int list[], int);
00132 static void           select_item(GnomeCanvasItem *, int);
00133 static int            get_item_index (double, double);
00134 
00135 static void draw_arrow(void);
00136 static void draw_frame(int, int);
00137 static void draw_redhands(void);
00138 static void place_item(int, int, int);
00139 
00140 /* Description of this plugin */
00141 static BoardPlugin menu_bp =
00142   {
00143     NULL,
00144     NULL,
00145     "Duplicate the top right model.",
00146     "Select item in the bottom left frame and move them with the crane's arrows.",
00147     "Marc BRUN",
00148     NULL,
00149     NULL,
00150     NULL,
00151     NULL,
00152     start_board,
00153     pause_board,
00154     end_board,
00155     is_our_board,
00156     NULL,
00157     NULL,
00158     set_level,
00159     NULL,
00160     NULL,
00161     NULL,
00162     NULL
00163   };
00164 
00165 /*
00166  * Main entry point mandatory for each Gcompris's game
00167  * ---------------------------------------------------
00168  *
00169  */
00170 
00171 GET_BPLUGIN_INFO(crane)
00172 
00173 static void pause_board (gboolean pause)
00174 {
00175   if (gcomprisBoard == NULL)
00176     return;
00177 
00178   if (timer_id) {
00179     gtk_timeout_remove (timer_id);
00180     timer_id = 0;
00181   }
00182 
00183   /* the game is won */
00184   if (gamewon == TRUE && pause == FALSE)
00185        game_won();
00186 
00187   board_paused = pause;
00188 }
00189 
00190 static void start_board (GcomprisBoard *agcomprisBoard)
00191 {
00192 
00193   if (agcomprisBoard != NULL) {
00194         gchar *img;
00195 
00196        gcomprisBoard = agcomprisBoard;
00197        gcomprisBoard->level = 1;
00198        gcomprisBoard->maxlevel = MAX_LEVEL;
00199        gcomprisBoard->sublevel = 1;
00200        gcomprisBoard->number_of_sublevel = 1; /* Go to next level after this number of 'play' */
00201        gc_bar_set(GC_BAR_LEVEL);
00202 
00203        img = gc_skin_image_get("gcompris-bg.jpg");
00204        gc_set_background(gnome_canvas_root(gcomprisBoard->canvas),
00205                             img);
00206        g_free(img);
00207 
00208 
00209        crane_next_level();
00210 
00211        gamewon = FALSE;
00212        pause_board(FALSE);
00213   }
00214 }
00215 
00216 static void end_board () {
00217 
00218   if (timer_id) {
00219        gtk_timeout_remove (timer_id);
00220        timer_id = 0;
00221   }
00222 
00223   if (gcomprisBoard != NULL) {
00224        pause_board(TRUE);
00225        crane_destroy_all_items();
00226   }
00227 
00228   gcomprisBoard = NULL;
00229 }
00230 
00231 /* ======================================= */
00232 static void set_level (guint level) {
00233 
00234   if (gcomprisBoard != NULL) {
00235 
00236       gcomprisBoard->level = level;
00237       gcomprisBoard->sublevel = 1;
00238       crane_next_level();
00239   }
00240 }
00241 /* ======================================= */
00242 static gboolean is_our_board (GcomprisBoard *gcomprisBoard) {
00243 
00244   if (gcomprisBoard) {
00245 
00246       if (g_strcasecmp(gcomprisBoard->type, "crane") == 0) {
00247 
00248          /* Set the plugin entry */
00249          gcomprisBoard->plugin = &menu_bp;
00250          return TRUE;
00251        }
00252   }
00253 
00254   return FALSE;
00255 }
00256 
00257 /*-------------------------------------------------------------------------------*/
00258 /*-------------------------------------------------------------------------------*/
00259 /* set initial values for the next level */
00260 static void crane_next_level() {
00261 
00262   gc_bar_set_level(gcomprisBoard);
00263 
00264   crane_destroy_all_items();
00265   gamewon = FALSE;
00266 
00267   /* Try the next level */
00268   crane_create_item();
00269 }
00270 
00271 /* ==================================== */
00272 /* Destroy all the items */
00273 static void crane_destroy_all_items()
00274 {
00275   if (timer_id) {
00276     gtk_timeout_remove (timer_id);
00277     timer_id = 0;
00278   }
00279 
00280   gnome_canvas_points_free(crane_rope);
00281 
00282   if(boardRootItem != NULL)
00283        gtk_object_destroy (GTK_OBJECT(boardRootItem));
00284 
00285   boardRootItem = NULL;
00286 }
00287 
00288 /* ==================================== */
00289 static GnomeCanvasItem *crane_create_item()
00290 {
00291   int i;
00292   int nb_element;
00293   GdkPixbuf *pixmap;
00294 
00295   boardRootItem = GNOME_CANVAS_GROUP(gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
00296                                  gnome_canvas_group_get_type (),
00297                                  "x", (double) 0,
00298                                  "y", (double) 0,
00299                                  NULL));
00300 
00301 
00302   pixmap = gc_pixmap_load("crane/crane-bg.png");
00303   gnome_canvas_item_new (boardRootItem,
00304                       gnome_canvas_pixbuf_get_type(),
00305                       "pixbuf", pixmap,
00306                       "x", 0.0,
00307                       "y", 0.0,
00308                       "anchor", GTK_ANCHOR_NW,
00309                       NULL);
00310   gdk_pixbuf_unref(pixmap);
00311 
00312   // The four arrows on the crane
00313   draw_arrow();
00314 
00315   // The leading frames on both model (answer) and boardgame, only for first levels
00316   if (gcomprisBoard->level < 5) {
00317        draw_frame(CRANE_FRAME_X, CRANE_FRAME_Y);        // Boardgame
00318        draw_frame(CRANE_FRAME_MODEL_X, CRANE_FRAME_MODEL_Y);   // Model
00319   }
00320 
00321   // The red corners (hands) that show the selected item
00322   draw_redhands();
00323 
00324   nb_element = gcomprisBoard->level * 2 + 2;
00325 
00326   // Answer frame => the unmovable items of the model
00327   for (i = 0 ; i < nb_element ; i++) list_answer[i] = i;
00328   for ( ; i < CRANE_FRAME_LINE * CRANE_FRAME_COLUMN ; i ++) list_answer[i] = -1;
00329   shuffle_list(list_answer, CRANE_FRAME_LINE * CRANE_FRAME_COLUMN);
00330   place_item(CRANE_FRAME_MODEL_X, CRANE_FRAME_MODEL_Y, 0);
00331 
00332   // Game frame => the playable items
00333   for (i = 0 ; i < nb_element ; i++) list_game[i] = i;
00334   for ( ; i < CRANE_FRAME_LINE * CRANE_FRAME_COLUMN ; i ++) list_game[i] = -1;
00335   shuffle_list(list_game, CRANE_FRAME_LINE * CRANE_FRAME_COLUMN);
00336   place_item(CRANE_FRAME_X, CRANE_FRAME_Y, 1);
00337 
00338   return NULL;
00339 }
00340 
00341 // Display an happy face for end of level
00342 static void bonus() {
00343 
00344   gc_bonus_display(gamewon, BONUS_SMILEY);
00345   gc_sound_play_ogg ("sounds/bonus.ogg", NULL);
00346   timer_id = 0;
00347 }
00348 
00349 // Display a 'end of game' animation
00350 static void finished() {
00351 
00352   gc_bonus_end_display(BOARD_FINISHED_RANDOM);
00353   timer_id = 0;
00354 }
00355 
00356 // One more level completed
00357 static void game_won() {
00358 
00359   gcomprisBoard->sublevel++;
00360 
00361   if (gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) {
00362        /* Try the next level */
00363        gcomprisBoard->sublevel = 1;
00364        gcomprisBoard->level++;
00365 
00366        if (gcomprisBoard->level>gcomprisBoard->maxlevel) { // all levels completed : the current board is finished
00367               timer_id = g_timeout_add (2000, (GtkFunction) finished, NULL);
00368               return;
00369        }
00370   }
00371   crane_next_level();
00372 }
00373 
00374 // Event on item
00375 static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
00376 
00377   if(board_paused)
00378        return FALSE;
00379 
00380   if (event->type == GDK_MOTION_NOTIFY) // Mouse moved
00381        return FALSE;
00382 
00383   // Select item if left click on it
00384   if (event->type == GDK_BUTTON_PRESS && event->button.button == 1)
00385        select_item(item, TRUE);
00386 
00387   return FALSE;
00388 }
00389 
00390 // Event on arrow
00391 static gint arrow_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
00392 
00393   int success;
00394   double x,y;
00395   double dx1, dy1, dx2, dy2;
00396   int direction = GPOINTER_TO_INT(data);
00397   int i;
00398   int index, new_index;
00399 
00400   if (board_paused)
00401        return FALSE;
00402 
00403   if (moving) // An object is already moving
00404        return FALSE;
00405 
00406   if (gamewon)
00407        return FALSE;
00408 
00409   if (event->type == GDK_MOTION_NOTIFY) // Mouse moved
00410        return FALSE;
00411 
00412   if (selected_item == NULL)
00413        return FALSE;
00414 
00415   // Left click on an arrow move the selected item
00416   if (event->type == GDK_BUTTON_PRESS && event->button.button == 1) {
00417        x = event->button.x;
00418        y = event->button.y;
00419 
00420        gnome_canvas_item_get_bounds(selected_item, &dx1, &dy1, &dx2, &dy2);
00421 
00422        switch (direction) {
00423        case LEFT:
00424          my_move.x = -1;
00425          my_move.y = 0;
00426          break;
00427        case RIGHT:
00428          my_move.x = 1;
00429          my_move.y = 0;
00430          break;
00431        case UP:
00432          my_move.x = 0;
00433          my_move.y = -1;
00434          break;
00435        case DOWN:
00436          my_move.x = 0;
00437          my_move.y = 1;
00438          break;
00439        }
00440 
00441        // Check if the move doesn't go out of the frame
00442        if (is_allowed_move(dx1, dy1, direction)) {
00443 
00444               index = get_item_index(dx1, dy1);
00445               new_index = index + my_move.x + (my_move.y * CRANE_FRAME_COLUMN);
00446 
00447               // Check if no object is already here
00448               if (list_game[new_index] == -1) {
00449 
00450                      // Do a smooth move
00451                      my_move.nb = 52;
00452                      timer_id = g_timeout_add(10,  (GtkFunction) smooth_move, &my_move);
00453                      list_game[new_index] = list_game[index];
00454                      list_game[index] = -1;
00455               }
00456        }
00457   }
00458 
00459   // Check if the level is won
00460   success = 1;
00461   for (i = 0 ; i < CRANE_FRAME_LINE * CRANE_FRAME_COLUMN ; i++) {
00462          if (list_answer[i] != list_game[i]) success = 0;
00463   }
00464 
00465   if (success) {
00466       gamewon = TRUE;
00467       timer_id = g_timeout_add (1200, (GtkFunction) bonus, NULL);
00468   }
00469 
00470   return FALSE;
00471 }
00472 
00473 // Draw the four arrows on the crane
00474 static void draw_arrow() {
00475 
00476   GnomeCanvasItem *item_arrow = NULL;
00477 
00478   int i;
00479   crane_object arrow[4];
00480 
00481   arrow[0].pixmap = gc_pixmap_load("crane/arrow_down.png");
00482   arrow[0].x = CRANE_BUTTON_DOWN_X;
00483   arrow[0].y = CRANE_BUTTON_DOWN_Y;
00484 
00485   arrow[1].pixmap = gc_pixmap_load("crane/arrow_up.png");
00486   arrow[1].x = CRANE_BUTTON_UP_X;
00487   arrow[1].y = CRANE_BUTTON_UP_Y;
00488 
00489   arrow[2].pixmap = gc_pixmap_load("crane/arrow_left.png");
00490   arrow[2].x = CRANE_BUTTON_LEFT_X;
00491   arrow[2].y = CRANE_BUTTON_LEFT_Y + 2;
00492 
00493   arrow[3].pixmap = gc_pixmap_load("crane/arrow_right.png");
00494   arrow[3].x = CRANE_BUTTON_RIGHT_X;
00495   arrow[3].y = CRANE_BUTTON_RIGHT_Y - 2;
00496 
00497   for (i = 0 ; i < 4 ; i++) {
00498        item_arrow = gnome_canvas_item_new (boardRootItem,
00499                                 gnome_canvas_pixbuf_get_type(),
00500                                 "pixbuf", arrow[i].pixmap,
00501                                 "x", arrow[i].x,
00502                                 "y", arrow[i].y,
00503                                 "anchor", GTK_ANCHOR_NW,
00504                                 NULL);
00505        gtk_signal_connect(GTK_OBJECT(item_arrow), "event",
00506                         (GtkSignalFunc) arrow_event, GINT_TO_POINTER(i));
00507        gtk_signal_connect(GTK_OBJECT(item_arrow), "event",
00508                       (GtkSignalFunc) gc_item_focus_event,
00509                       NULL);
00510        gdk_pixbuf_unref( arrow[i].pixmap);
00511 
00512   }
00513 
00514 }
00515 
00516 // Draw the red hands object which highlight the selected object
00517 static void draw_redhands() {
00518 
00519   GdkPixbuf *pixmap;
00520 
00521   /* Initialize the rope (Warning, it's static and freed in crane_destroy_all_items) */
00522   crane_rope = gnome_canvas_points_new(2);
00523 
00524   crane_rope->coords[0] = 5;
00525   crane_rope->coords[1] = CRANE_BUTTON_LEFT_Y;
00526   crane_rope->coords[2] = 5;
00527   crane_rope->coords[3] = CRANE_BUTTON_LEFT_Y;
00528 
00529   crane_rope_item = gnome_canvas_item_new (boardRootItem,
00530                                       gnome_canvas_line_get_type(),
00531                                      "points", crane_rope,
00532                                      "fill_color", "darkblue",
00533                                      "width_units", (double) 1,
00534                                      "width_pixels", (guint) 7,
00535                                      NULL);
00536 
00537   pixmap = gc_pixmap_load("crane/selected.png");
00538 
00539   red_hands = gnome_canvas_item_new (boardRootItem,
00540        gnome_canvas_pixbuf_get_type(),
00541        "pixbuf", pixmap,
00542        "x", (double) 5,
00543        "y", (double) 5,
00544        "width", (double) (CRANE_FRAME_IMAGE_SIZE + 5),
00545        "height", (double) (CRANE_FRAME_IMAGE_SIZE + 5),
00546        "width_set", TRUE,
00547        "height_set", TRUE,
00548        "anchor", GTK_ANCHOR_NW,
00549        NULL);
00550 
00551   gdk_pixbuf_unref(pixmap);
00552 
00553   gnome_canvas_item_hide(red_hands);
00554 
00555 }
00556 
00557 // Draw the drak frame (horizontal and vertical lines) that helps positionning elements
00558 static void draw_frame(int x, int y) {
00559 
00560   GnomeCanvasItem *item_frame = NULL;
00561   int i;
00562   GnomeCanvasPoints *track;
00563 
00564   track = gnome_canvas_points_new(2);
00565 
00566   for (i = 1 ; i < CRANE_FRAME_COLUMN ; i++) {
00567 
00568        track->coords[0] = x + (i * CRANE_FRAME_CELL);
00569        track->coords[1] = y + CRANE_FRAME_BORDER;
00570        track->coords[2] = x + i * CRANE_FRAME_CELL;
00571        track->coords[3] = y + (CRANE_FRAME_LINE * CRANE_FRAME_CELL) - CRANE_FRAME_BORDER;
00572 
00573        item_frame = gnome_canvas_item_new (boardRootItem,
00574                                    gnome_canvas_line_get_type (),
00575                                    "points", track,
00576                                    "width_pixels", 1,
00577                                    "fill_color", "black",
00578                                    NULL);
00579   }
00580 
00581   for (i = 1 ; i < CRANE_FRAME_LINE ; i++) {
00582 
00583        track->coords[0] = x + CRANE_FRAME_BORDER;
00584        track->coords[1] = y + (i * CRANE_FRAME_CELL);
00585        track->coords[2] = x + (CRANE_FRAME_COLUMN * CRANE_FRAME_CELL) - CRANE_FRAME_BORDER;
00586        track->coords[3] = y + (i * CRANE_FRAME_CELL);
00587 
00588        item_frame = gnome_canvas_item_new (boardRootItem,
00589                                    gnome_canvas_line_get_type (),
00590                                    "points", track,
00591                                    "width_pixels", 1,
00592                                    "fill_color", "black",
00593                                    NULL);
00594   }
00595 
00596   gnome_canvas_points_free(track);
00597 
00598 }
00599 
00600 // Place randomly nb_element (depending on the level) elements on the frame.
00601 // if active is set, the elements are connected to their function, that's for the bottom left frame
00602 // if active is off, the elements are unmovable, that's for the top right model
00603 static void place_item(int x, int y, int active) {
00604 
00605   GdkPixbuf *pixmap;
00606   GnomeCanvasItem *item_image = NULL;
00607   int i;
00608   int valeur;
00609 
00610   for (i = 0 ; i < CRANE_FRAME_LINE * CRANE_FRAME_COLUMN ; i ++) {
00611 
00612        if (active) {
00613               valeur = list_game[i];
00614        } else {
00615               valeur = list_answer[i];
00616        }
00617 
00618        // Empty cell
00619        if (valeur == -1)
00620               continue;
00621 
00622        pixmap = gc_pixmap_load(imageList[valeur]);
00623        item_image = gnome_canvas_item_new (boardRootItem,
00624                                 gnome_canvas_pixbuf_get_type (),
00625                                 "pixbuf", pixmap,
00626                                 "x", (double) (x + 5 + ((i % CRANE_FRAME_COLUMN) * CRANE_FRAME_CELL)),
00627                                 "y", (double) (y + 5 + (floor(i / CRANE_FRAME_COLUMN) * CRANE_FRAME_CELL)),
00628                                 NULL);
00629        gdk_pixbuf_unref( pixmap);
00630 
00631        if (active)
00632               gtk_signal_connect(GTK_OBJECT(item_image), "event", (GtkSignalFunc) item_event, NULL);
00633 
00634   }
00635 
00636   // 'Focus' given to the last one
00637   if (active)
00638        select_item(item_image, FALSE);
00639 
00640 }
00641 
00642 static guint smooth_move(move_object *move) {
00643   double dx1, dy1, dx2, dy2;
00644 
00645   if (nb_move == 0) {
00646        moving = TRUE;
00647        nb_move = move->nb;
00648   }
00649 
00650   gnome_canvas_item_get_bounds(red_hands, &dx1, &dy1, &dx2, &dy2);
00651   crane_rope->coords[0] = (dx1 + dx2) / 2;
00652   crane_rope->coords[1] = CRANE_ROPE_Y;
00653   crane_rope->coords[2] = (dx1 + dx2) / 2;
00654   crane_rope->coords[3] = (dy1 + dy2) / 2;
00655 
00656   gnome_canvas_item_set (crane_rope_item,
00657                       "points", crane_rope,
00658                       NULL);
00659 
00660   gnome_canvas_item_move(selected_item, move->x, move->y);
00661   gnome_canvas_item_move(red_hands, move->x, move->y);
00662   nb_move--;
00663 
00664   if (nb_move == 0) {
00665        moving = FALSE;
00666        return FALSE;
00667   }
00668 
00669   return TRUE;
00670 }
00671 
00672 int is_allowed_move (double dx, double dy, int direction) {
00673 
00674   if ((direction == LEFT) && (dx > (CRANE_FRAME_X + CRANE_FRAME_CELL)))
00675        return 1;
00676   else if ((direction == RIGHT) && (dx < (CRANE_FRAME_X + ((CRANE_FRAME_COLUMN - 1) * CRANE_FRAME_CELL))))
00677        return 1;
00678   else if ((direction == UP) && (dy > (CRANE_FRAME_Y + CRANE_FRAME_CELL)))
00679        return 1;
00680   else if ((direction == DOWN) && (dy < (CRANE_FRAME_Y + ((CRANE_FRAME_LINE - 1) * CRANE_FRAME_CELL))))
00681        return 1;
00682 
00683   return 0;
00684 }
00685 
00686 int get_item_index (double dx, double dy) {
00687 
00688   return (((dx - CRANE_FRAME_X - 5) / CRANE_FRAME_CELL) + ((dy - CRANE_FRAME_Y - 5) / CRANE_FRAME_CELL * CRANE_FRAME_COLUMN));
00689 
00690 }
00691 
00692 void shuffle_list(int list[], int size) {
00693 
00694   int i;
00695   int rand1, rand2, buffer;
00696 
00697   for (i = 0 ; i < size ; i++) {
00698 
00699        rand1 = RAND(0, size-1);
00700        rand2 = RAND(0, size-1);
00701 
00702        buffer = list[rand2];
00703        list[rand2] = list[rand1];
00704        list[rand1] = buffer;
00705   }
00706 }
00707 
00708 static void select_item(GnomeCanvasItem *item, int sound) {
00709 
00710   double dx1, dy1, dx2, dy2;
00711 
00712   // Use of gnome_canvas_item_affine_absolute must be better
00713 
00714   gnome_canvas_item_hide(red_hands);
00715 
00716   // Place redhands in (O;O)
00717   gnome_canvas_item_get_bounds(red_hands, &dx1, &dy1, &dx2, &dy2);
00718   gnome_canvas_item_move(red_hands, -(dx1), -(dy1));
00719 
00720   // Place redhands 'around' the selected item
00721   gnome_canvas_item_get_bounds(item, &dx1, &dy1, &dx2, &dy2);
00722   gnome_canvas_item_move(red_hands, dx1 - 1 , dy1 - 1);
00723 
00724   gnome_canvas_item_show(red_hands);
00725 
00726   crane_rope->coords[0] = (dx1 + dx2) / 2;
00727   crane_rope->coords[1] = CRANE_ROPE_Y;
00728   crane_rope->coords[2] = (dx1 + dx2) / 2;
00729   crane_rope->coords[3] = (dy1 + dy2) / 2;
00730 
00731   gnome_canvas_item_set (crane_rope_item,
00732                       "points", crane_rope,
00733                       NULL);
00734 
00735   if (sound) gc_sound_play_ogg ("sounds/gobble.ogg", NULL);
00736 
00737   selected_item = item;
00738 }
00739