Back to index

gcompris  8.2.2
canal_lock.c
Go to the documentation of this file.
00001 /* gcompris - canal_lock.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 "gcompris/gcompris.h"
00021 
00022 #define SOUNDLISTFILE PACKAGE
00023 
00024 #define ANIMATE_SPEED 30
00025 
00026 #define CANAL_COLOR         0x0010FFFF
00027 #define LOCK_COLOR          0x8cc679FF
00028 #define LOCK_COLOR_H        0x71A65FFF
00029 #define CANALLOCK_COLOR            0xd1cd0cFF
00030 #define CANALLOCK_COLOR_H   0xf1ed1cFF
00031 #define GROUND_COLOR        0x9b5f5aFF
00032 #define BASE_LINE           400
00033 #define LEFT_CANAL_HEIGHT   100
00034 #define LEFT_CANAL_WIDTH    325
00035 #define RIGHT_CANAL_HEIGHT  200
00036 #define RIGHT_CANAL_WIDTH   325
00037 #define MIDDLE_CANAL_WIDTH  (BOARDWIDTH - RIGHT_CANAL_WIDTH -  LEFT_CANAL_WIDTH)
00038 
00039 #define LOCK_WIDTH          20
00040 #define LOCK_HEIGHT_MAX            (RIGHT_CANAL_HEIGHT + 40)
00041 #define LOCK_HEIGHT_MIN            20
00042 
00043 #define SUBCANAL_BASE_LINE  (BASE_LINE + 80)
00044 #define SUBCANAL_HEIGHT            40
00045 
00046 #define CANALLOCK_WIDTH            30
00047 #define CANALLOCK_HEIGHT_MAX       SUBCANAL_HEIGHT
00048 #define CANALLOCK_HEIGHT_MIN       15
00049 
00050 static GcomprisBoard *gcomprisBoard = NULL;
00051 static gboolean board_paused = TRUE;
00052 
00053 static void    start_board (GcomprisBoard *agcomprisBoard);
00054 static void    pause_board (gboolean pause);
00055 static void    end_board (void);
00056 static gboolean       is_our_board (GcomprisBoard *gcomprisBoard);
00057 static void    set_level (guint level);
00058 static int     gamewon;
00059 static void    game_won(void);
00060 
00061 static gint timer_id;
00062 static gboolean animation;
00063 
00064 static GnomeCanvasGroup *boardRootItem = NULL;
00065 
00066 static GnomeCanvasItem      *lock_left_item             = NULL;
00067 static GnomeCanvasItem      *lock_right_item     = NULL;
00068 
00069 static GnomeCanvasItem      *canallock_left_item = NULL;
00070 static GnomeCanvasItem      *canallock_right_item       = NULL;
00071 
00072 static GnomeCanvasItem      *canal_left_item     = NULL;
00073 static GnomeCanvasItem      *canal_middle_item   = NULL;
00074 static GnomeCanvasItem      *canal_right_item    = NULL;
00075 
00076 static GnomeCanvasItem      *tuxboat_item        = NULL;
00077 static double         tuxboat_width;
00078 
00079 #define BOAT_POS_LEFT              1
00080 #define BOAT_POS_MIDDLE            2
00081 #define BOAT_POS_RIGHT             3
00082 
00083 static guint boat_position;
00084 static gboolean right_way;
00085 static gboolean lock_left_up;
00086 static gboolean lock_right_up;
00087 static gboolean lock_water_low;
00088 static gboolean canallock_left_up;
00089 static gboolean canallock_right_up;
00090 
00091 static double timer_item_x1, timer_item_y1, timer_item_x2, timer_item_y2;
00092 static double timer_item_limit_y, timer_item_limit_x;
00093 static GnomeCanvasItem *timer_item;
00094 static gint timer_step_y1, timer_step_x1;
00095 
00096 static GnomeCanvasItem      *canal_lock_create_item(GnomeCanvasGroup *parent);
00097 static void           canal_lock_destroy_all_items(void);
00098 static void           canal_lock_next_level(void);
00099 static gint           item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00100 static gboolean              animate_step();
00101 static void           update_water();
00102 static void           toggle_lock(GnomeCanvasItem *item);
00103 
00104 /* Description of this plugin */
00105 static BoardPlugin menu_bp =
00106   {
00107     NULL,
00108     NULL,
00109     "Operate a canal lock",
00110     "Tux is in trouble in his ship. He needs to take it through a lock",
00111     "Bruno Coudoin <bruno.coudoin@free.fr>",
00112     NULL,
00113     NULL,
00114     NULL,
00115     NULL,
00116     start_board,
00117     pause_board,
00118     end_board,
00119     is_our_board,
00120     NULL,
00121     NULL,
00122     set_level,
00123     NULL,
00124     NULL,
00125     NULL,
00126     NULL
00127   };
00128 
00129 /*
00130  * Main entry point mandatory for each Gcompris's game
00131  * ---------------------------------------------------
00132  *
00133  */
00134 
00135 GET_BPLUGIN_INFO(canal_lock)
00136 
00137 /*
00138  * in : boolean TRUE = PAUSE : FALSE = CONTINUE
00139  *
00140  */
00141 static void pause_board (gboolean pause)
00142 {
00143   if(gcomprisBoard==NULL)
00144     return;
00145 
00146   if(gamewon == TRUE && pause == FALSE) /* the game is won */
00147     {
00148       game_won();
00149     }
00150 
00151   board_paused = pause;
00152 }
00153 
00154 /*
00155  */
00156 static void start_board (GcomprisBoard *agcomprisBoard)
00157 {
00158 
00159   if(agcomprisBoard!=NULL)
00160     {
00161       gcomprisBoard=agcomprisBoard;
00162       gcomprisBoard->level=1;
00163       gcomprisBoard->maxlevel=2;
00164       gcomprisBoard->sublevel=1;
00165       gcomprisBoard->number_of_sublevel=1; /* Go to next level after this number of 'play' */
00166 
00167       canal_lock_next_level();
00168 
00169       gc_bar_set(0);
00170 
00171       animation = FALSE;
00172 
00173       gamewon = FALSE;
00174       pause_board(FALSE);
00175     }
00176 }
00177 /* ======================================= */
00178 static void end_board ()
00179 {
00180   // If we don't stop animation, there may be a segfault if leaving while the animation is running
00181   if (timer_id) {
00182     gtk_timeout_remove (timer_id);
00183     timer_id = 0;
00184   }
00185   animation = FALSE;
00186 
00187   if(gcomprisBoard!=NULL)
00188     {
00189       pause_board(TRUE);
00190       canal_lock_destroy_all_items();
00191     }
00192   gcomprisBoard = NULL;
00193 }
00194 
00195 /* ======================================= */
00196 static void set_level (guint level)
00197 {
00198 
00199   if(gcomprisBoard!=NULL)
00200     {
00201       gcomprisBoard->level=level;
00202       gcomprisBoard->sublevel=1;
00203       canal_lock_next_level();
00204     }
00205 }
00206 /* ======================================= */
00207 static gboolean is_our_board (GcomprisBoard *gcomprisBoard)
00208 {
00209   if (gcomprisBoard)
00210     {
00211       if(g_strcasecmp(gcomprisBoard->type, "canal_lock")==0)
00212        {
00213          /* Set the plugin entry */
00214          gcomprisBoard->plugin=&menu_bp;
00215 
00216          return TRUE;
00217        }
00218     }
00219   return FALSE;
00220 }
00221 
00222 /*-------------------------------------------------------------------------------*/
00223 /*-------------------------------------------------------------------------------*/
00224 /* set initial values for the next level */
00225 static void canal_lock_next_level()
00226 {
00227 
00228   gc_set_background(gnome_canvas_root(gcomprisBoard->canvas),
00229                        "canal_lock/canal_lock_bg.png");
00230 
00231   gc_bar_set_level(gcomprisBoard);
00232 
00233   canal_lock_destroy_all_items();
00234   gamewon = FALSE;
00235 
00236   /* Original state of the lock */
00237   boat_position = BOAT_POS_LEFT;
00238   right_way = TRUE;
00239   lock_left_up = TRUE;
00240   lock_right_up = TRUE;
00241   lock_water_low = TRUE;
00242   canallock_left_up = TRUE;
00243   canallock_right_up = TRUE;
00244 
00245   /* Try the next level */
00246   canal_lock_create_item(gnome_canvas_root(gcomprisBoard->canvas));
00247 }
00248 /* ==================================== */
00249 /* Destroy all the items */
00250 static void canal_lock_destroy_all_items()
00251 {
00252   if(boardRootItem!=NULL)
00253     gtk_object_destroy (GTK_OBJECT(boardRootItem));
00254 
00255   boardRootItem = NULL;
00256 }
00257 /* ==================================== */
00258 static GnomeCanvasItem *canal_lock_create_item(GnomeCanvasGroup *parent)
00259 {
00260   GdkPixbuf *pixmap = NULL;
00261 
00262   boardRootItem = GNOME_CANVAS_GROUP(
00263                                  gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
00264                                                      gnome_canvas_group_get_type (),
00265                                                      "x", (double) 0,
00266                                                      "y", (double) 0,
00267 
00268                                                      NULL));
00269 
00270   /* The boat */
00271   pixmap = gc_pixmap_load("gcompris/misc/tuxboat.png");
00272 
00273   tuxboat_item = gnome_canvas_item_new (boardRootItem,
00274                                    gnome_canvas_pixbuf_get_type (),
00275                                    "pixbuf",  pixmap,
00276                                    "x", (double) (LEFT_CANAL_WIDTH - gdk_pixbuf_get_width(pixmap)) / 2,
00277                                    "y", (double) BASE_LINE - LEFT_CANAL_HEIGHT - gdk_pixbuf_get_height(pixmap)*0.9,
00278                                    NULL);
00279   gtk_signal_connect(GTK_OBJECT(tuxboat_item), "event",
00280                    (GtkSignalFunc) item_event,
00281                    NULL);
00282   gtk_signal_connect(GTK_OBJECT(tuxboat_item), "event",
00283                    (GtkSignalFunc) gc_item_focus_event,
00284                    NULL);
00285   tuxboat_width = gdk_pixbuf_get_width(pixmap);
00286   gdk_pixbuf_unref(pixmap);
00287 
00288   /* This is the ground canal */
00289   gnome_canvas_item_new (boardRootItem,
00290                       gnome_canvas_rect_get_type (),
00291                       "x1", (double) 0,
00292                       "y1", (double) BASE_LINE,
00293                       "x2", (double) BOARDWIDTH,
00294                       "y2", (double) BOARDHEIGHT,
00295                       "fill_color_rgba", GROUND_COLOR,
00296                       "width_units", (double) 0,
00297                       NULL);
00298 
00299   /* This is the left canal */
00300   canal_left_item = gnome_canvas_item_new (boardRootItem,
00301                                        gnome_canvas_rect_get_type (),
00302                                        "x1", (double) 0,
00303                                        "y1", (double) BASE_LINE - LEFT_CANAL_HEIGHT,
00304                                        "x2", (double) LEFT_CANAL_WIDTH,
00305                                        "y2", (double) BASE_LINE,
00306                                        "fill_color_rgba", CANAL_COLOR,
00307                                        "width_units", (double) 0,
00308                                        NULL);
00309 
00310   /* This is the middle canal */
00311   canal_middle_item = gnome_canvas_item_new (boardRootItem,
00312                                         gnome_canvas_rect_get_type (),
00313                                         "x1", (double) LEFT_CANAL_WIDTH,
00314                                         "y1", (double) BASE_LINE - LEFT_CANAL_HEIGHT,
00315                                         "x2", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH,
00316                                         "y2", (double) BASE_LINE,
00317                                         "fill_color_rgba", CANAL_COLOR,
00318                                         "width_units", (double) 0,
00319                                         NULL);
00320 
00321   /* This is the right canal */
00322   canal_right_item = gnome_canvas_item_new (boardRootItem,
00323                                        gnome_canvas_rect_get_type (),
00324                                        "x1", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH,
00325                                        "y1", (double) BASE_LINE - RIGHT_CANAL_HEIGHT,
00326                                        "x2", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH + RIGHT_CANAL_WIDTH,
00327                                        "y2", (double) BASE_LINE,
00328                                        "fill_color_rgba", CANAL_COLOR,
00329                                        "width_units", (double) 0,
00330                                        NULL);
00331 
00332   /* This is the left lock */
00333   lock_left_item = gnome_canvas_item_new (boardRootItem,
00334                                      gnome_canvas_rect_get_type (),
00335                                      "x1", (double) LEFT_CANAL_WIDTH - LOCK_WIDTH / 2,
00336                                      "y1", (double) BASE_LINE - LOCK_HEIGHT_MAX,
00337                                      "x2", (double) LEFT_CANAL_WIDTH + LOCK_WIDTH / 2,
00338                                      "y2", (double) BASE_LINE,
00339                                      "fill_color_rgba", LOCK_COLOR,
00340                                      "width_units", (double) 0,
00341                                      NULL);
00342   gtk_signal_connect(GTK_OBJECT(lock_left_item), "event",
00343                    (GtkSignalFunc) item_event,
00344                    NULL);
00345 
00346   /* This is the right lock */
00347   lock_right_item = gnome_canvas_item_new (boardRootItem,
00348                                       gnome_canvas_rect_get_type (),
00349                                       "x1", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH - LOCK_WIDTH / 2,
00350                                       "y1", (double) BASE_LINE - LOCK_HEIGHT_MAX,
00351                                       "x2", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH + LOCK_WIDTH / 2,
00352                                       "y2", (double) BASE_LINE,
00353                                       "fill_color_rgba", LOCK_COLOR,
00354                                       "width_units", (double) 0,
00355                                       NULL);
00356   gtk_signal_connect(GTK_OBJECT(lock_right_item), "event",
00357                    (GtkSignalFunc) item_event,
00358                    NULL);
00359 
00360   /* This is the water conduit under the canal */
00361   gnome_canvas_item_new (boardRootItem,
00362                       gnome_canvas_rect_get_type (),
00363                       "x1", (double) LEFT_CANAL_WIDTH/2,
00364                       "y1", (double) SUBCANAL_BASE_LINE - SUBCANAL_HEIGHT,
00365                       "x2", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH + RIGHT_CANAL_WIDTH / 2 + SUBCANAL_HEIGHT,
00366                       "y2", (double) SUBCANAL_BASE_LINE,
00367                       "fill_color_rgba", CANAL_COLOR,
00368                       "width_units", (double) 0,
00369                       NULL);
00370 
00371   /* Left conduit */
00372   gnome_canvas_item_new (boardRootItem,
00373                       gnome_canvas_rect_get_type (),
00374                       "x1", (double) LEFT_CANAL_WIDTH/2,
00375                       "y1", (double) BASE_LINE,
00376                       "x2", (double) LEFT_CANAL_WIDTH/2 + SUBCANAL_HEIGHT,
00377                       "y2", (double) SUBCANAL_BASE_LINE,
00378                       "fill_color_rgba", CANAL_COLOR,
00379                       "width_units", (double) 0,
00380                       NULL);
00381 
00382   /* Middle conduit */
00383   gnome_canvas_item_new (boardRootItem,
00384                       gnome_canvas_rect_get_type (),
00385                       "x1", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH/2 - SUBCANAL_HEIGHT/2,
00386                       "y1", (double) BASE_LINE,
00387                       "x2", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH/2 + SUBCANAL_HEIGHT/2,
00388                       "y2", (double) SUBCANAL_BASE_LINE,
00389                       "fill_color_rgba", CANAL_COLOR,
00390                       "width_units", (double) 0,
00391                       NULL);
00392 
00393   /* Right conduit */
00394   gnome_canvas_item_new (boardRootItem,
00395                       gnome_canvas_rect_get_type (),
00396                       "x1", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH + RIGHT_CANAL_WIDTH/2,
00397                       "y1", (double) BASE_LINE,
00398                       "x2", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH + RIGHT_CANAL_WIDTH/2 + SUBCANAL_HEIGHT,
00399                       "y2", (double) SUBCANAL_BASE_LINE,
00400                       "fill_color_rgba", CANAL_COLOR,
00401                       "width_units", (double) 0,
00402                       NULL);
00403 
00404   /* And to finish, the 2 canal locks */
00405   canallock_left_item =
00406     gnome_canvas_item_new (boardRootItem,
00407                         gnome_canvas_rect_get_type (),
00408                         "x1", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH * 0.1,
00409                         "y1", (double) SUBCANAL_BASE_LINE - SUBCANAL_HEIGHT,
00410                         "x2", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH * 0.1 + LOCK_WIDTH / 2,
00411                         "y2", (double) SUBCANAL_BASE_LINE,
00412                         "fill_color_rgba", CANALLOCK_COLOR,
00413                         "width_units", (double) 0,
00414                         NULL);
00415   gtk_signal_connect(GTK_OBJECT(canallock_left_item), "event",
00416                    (GtkSignalFunc) item_event,
00417                    NULL);
00418 
00419   canallock_right_item =
00420     gnome_canvas_item_new (boardRootItem,
00421                         gnome_canvas_rect_get_type (),
00422                         "x1", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH * 0.9,
00423                         "y1", (double) SUBCANAL_BASE_LINE - SUBCANAL_HEIGHT,
00424                         "x2", (double) LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH * 0.9 + LOCK_WIDTH / 2,
00425                         "y2", (double) SUBCANAL_BASE_LINE,
00426                         "fill_color_rgba", CANALLOCK_COLOR,
00427                         "width_units", (double) 0,
00428                         NULL);
00429     gtk_signal_connect(GTK_OBJECT(canallock_right_item), "event",
00430                    (GtkSignalFunc) item_event,
00431                    NULL);
00432 
00433 
00434 
00435   return NULL;
00436 }
00437 /* ==================================== */
00438 static void game_won()
00439 {
00440   gcomprisBoard->sublevel++;
00441 
00442   if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) {
00443     /* Try the next level */
00444     gcomprisBoard->sublevel=1;
00445     gcomprisBoard->level++;
00446     if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
00447       gc_bonus_end_display(BOARD_FINISHED_RANDOM);
00448       return;
00449     }
00450     gc_sound_play_ogg ("sounds/bonus.ogg", NULL);
00451   }
00452   canal_lock_next_level();
00453 }
00454 
00455 /* ==================================== */
00456 /* Move the boat to the next possible position */
00457 static void move_boat()
00458 {
00459 
00460   /* If there is already an animation do nothing else set animation to avoid deadlock */
00461   if(animation)
00462     return;
00463   animation = TRUE;
00464 
00465   if(boat_position == BOAT_POS_LEFT && !lock_left_up)
00466     {
00467       boat_position = BOAT_POS_MIDDLE;
00468       timer_item_limit_x = LEFT_CANAL_WIDTH + (MIDDLE_CANAL_WIDTH - tuxboat_width)/2;
00469       timer_step_x1 = 2;
00470     }
00471   else if(boat_position == BOAT_POS_MIDDLE && !lock_left_up)
00472     {
00473       boat_position = BOAT_POS_LEFT;
00474       timer_item_limit_x = (LEFT_CANAL_WIDTH - tuxboat_width)/2;
00475       timer_step_x1 = -2;
00476     }
00477   else if(boat_position == BOAT_POS_MIDDLE && !lock_right_up)
00478     {
00479       boat_position = BOAT_POS_RIGHT;
00480       timer_item_limit_x = LEFT_CANAL_WIDTH + MIDDLE_CANAL_WIDTH + (RIGHT_CANAL_WIDTH - tuxboat_width)/2;
00481       timer_step_x1 = 2;
00482     }
00483   else if(boat_position == BOAT_POS_RIGHT && !lock_right_up)
00484     {
00485       boat_position = BOAT_POS_MIDDLE;
00486       timer_item_limit_x = LEFT_CANAL_WIDTH + (MIDDLE_CANAL_WIDTH - tuxboat_width)/2;
00487       timer_step_x1 = -2;
00488     }
00489   else
00490     {
00491       /* No possible move */
00492       gc_sound_play_ogg ("sounds/crash.ogg", NULL);
00493       animation = FALSE;
00494       return;
00495     }
00496 
00497   gnome_canvas_item_get_bounds(tuxboat_item, &timer_item_x1, &timer_item_y1,
00498                             &timer_item_x2, &timer_item_y2);
00499 
00500   timer_item = tuxboat_item;
00501   timer_step_y1 = 0;
00502 
00503   timer_id = gtk_timeout_add (ANIMATE_SPEED, (GtkFunction) animate_step, NULL);
00504 }
00505 
00506 /* ==================================== */
00507 /* Update the water level if necessary */
00508 static void update_water()
00509 {
00510   gboolean status = TRUE;
00511   double y1 = 0;
00512   gint min = LEFT_CANAL_HEIGHT;
00513 
00514   /* If there is already an animation do nothing else set animation to avoid deadlock */
00515   if(animation)
00516     return;
00517   animation = TRUE;
00518 
00519   if((!canallock_left_up && !lock_water_low) ||
00520      (!canallock_right_up && lock_water_low))
00521     {
00522       status = !lock_water_low;
00523       lock_water_low = !lock_water_low;
00524       y1 = BASE_LINE - RIGHT_CANAL_HEIGHT;
00525     }
00526   else
00527     {
00528       /* The water level is correct */
00529       animation = FALSE;
00530       return;
00531     }
00532 
00533   gnome_canvas_item_get_bounds(canal_middle_item, &timer_item_x1, &timer_item_y1,
00534                             &timer_item_x2, &timer_item_y2);
00535 
00536   timer_item = canal_middle_item;
00537   timer_item_limit_y = (status ? timer_item_y2 - min :
00538                      y1);
00539   timer_step_y1 = (status ? 2 : -2);
00540   timer_step_x1 = 0;
00541 
00542   timer_id = gtk_timeout_add (ANIMATE_SPEED, (GtkFunction) animate_step, NULL);
00543 }
00544 
00545 /* ==================================== */
00546 /* Toggle the given lock */
00547 static void toggle_lock(GnomeCanvasItem *item)
00548 {
00549   gboolean status = TRUE;
00550   double y1 = 0;
00551   gint min = 0;
00552   guint animate_speed = 0;
00553 
00554   /* If there is already an animation do nothing else set animation to avoid deadlock */
00555   if(animation)
00556     return;
00557   animation = TRUE;
00558 
00559   gnome_canvas_item_get_bounds(item, &timer_item_x1, &timer_item_y1,
00560                             &timer_item_x2, &timer_item_y2);
00561 
00562   if(item == lock_left_item)
00563     {
00564       status = lock_left_up;
00565       lock_left_up = !lock_left_up;
00566       y1 = BASE_LINE - LOCK_HEIGHT_MAX;
00567       min = LOCK_HEIGHT_MIN;
00568       animate_speed = ANIMATE_SPEED;
00569     }
00570   else if(item == lock_right_item)
00571     {
00572       status = lock_right_up;
00573       lock_right_up = !lock_right_up;
00574       y1 = BASE_LINE - LOCK_HEIGHT_MAX;
00575       min = LOCK_HEIGHT_MIN;
00576       animate_speed = ANIMATE_SPEED;
00577     }
00578   else if(item == canallock_left_item)
00579     {
00580       status = canallock_left_up;
00581       canallock_left_up = !canallock_left_up;
00582       y1 = SUBCANAL_BASE_LINE - SUBCANAL_HEIGHT;
00583       min = CANALLOCK_HEIGHT_MIN;
00584       animate_speed = ANIMATE_SPEED;
00585     }
00586   else if(item == canallock_right_item)
00587     {
00588       status = canallock_right_up;
00589       canallock_right_up = !canallock_right_up;
00590       y1 = SUBCANAL_BASE_LINE - SUBCANAL_HEIGHT;
00591       min = CANALLOCK_HEIGHT_MIN;
00592       animate_speed = ANIMATE_SPEED;
00593     }
00594 
00595   timer_item = item;
00596   timer_item_limit_y = (status ? timer_item_y2 - min :
00597                      y1);
00598   timer_step_y1 = (status ? 2 : -2);
00599   timer_step_x1 = 0;
00600 
00601   timer_id = gtk_timeout_add (animate_speed, (GtkFunction) animate_step, NULL);
00602 
00603 }
00604 
00605 
00606 /* ==================================== */
00607 static gboolean animate_step()
00608 {
00609 
00610   if(!gcomprisBoard)
00611     return FALSE;
00612 
00613   timer_item_x1 += timer_step_x1;
00614   timer_item_y1 += timer_step_y1;
00615 
00616   if(GNOME_IS_CANVAS_PIXBUF(timer_item))
00617     gnome_canvas_item_set(timer_item,
00618                        "x", timer_item_x1,
00619                        "y", timer_item_y1,
00620                        NULL);
00621   else if(GNOME_IS_CANVAS_RECT(timer_item))
00622     gnome_canvas_item_set(timer_item,
00623                        "x1", timer_item_x1,
00624                        "y1", timer_item_y1,
00625                        NULL);
00626 
00627   /* Special case for raising/lowering the boat */
00628   if(boat_position==BOAT_POS_MIDDLE && timer_item==canal_middle_item)
00629     {
00630       double item_x1, item_y1, item_x2, item_y2;
00631 
00632       gnome_canvas_item_get_bounds(tuxboat_item, &item_x1, &item_y1,
00633                                &item_x2, &item_y2);
00634 
00635       gnome_canvas_item_set(tuxboat_item,
00636                          "y", item_y1 + timer_step_y1,
00637                          NULL);
00638     }
00639 
00640   if((timer_item_y1 >= timer_item_limit_y && timer_step_y1 > 0) ||
00641      (timer_item_y1 <= timer_item_limit_y && timer_step_y1 < 0))
00642     {
00643       gtk_timeout_remove (timer_id);
00644       timer_id = 0;
00645       animation = FALSE;
00646       update_water();
00647     }
00648   else if((timer_item_x1 >= timer_item_limit_x && timer_step_x1 > 0) ||
00649      (timer_item_x1 <= timer_item_limit_x && timer_step_x1 < 0))
00650     {
00651       gtk_timeout_remove (timer_id);
00652       timer_id = 0;
00653       animation = FALSE;
00654       update_water();
00655     }
00656 
00657   gnome_canvas_update_now(gcomprisBoard->canvas);
00658 
00659   return TRUE;
00660 }
00661 
00662 /* ==================================== */
00663 /* Highlight the given item */
00664 static void hightlight(GnomeCanvasItem *item, gboolean status)
00665 {
00666   guint color = 0;
00667 
00668   /* This is an image, not a rectangle */
00669   if(item == tuxboat_item)
00670     return;
00671 
00672   if(item == lock_left_item ||
00673      item == lock_right_item)
00674     {
00675       color   = (status ? LOCK_COLOR_H : LOCK_COLOR);
00676     }
00677   else if (item == canallock_left_item ||
00678           item == canallock_right_item)
00679     {
00680       color   = (status ? CANALLOCK_COLOR_H : CANALLOCK_COLOR);
00681     }
00682 
00683 
00684     gnome_canvas_item_set(item,
00685                        "fill_color_rgba", color,
00686                        NULL);
00687 
00688 }
00689 
00690 /* ==================================== */
00691 static gint
00692 item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
00693 {
00694   double item_x, item_y;
00695   item_x = event->button.x;
00696   item_y = event->button.y;
00697   gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
00698 
00699   if(board_paused)
00700     return FALSE;
00701 
00702   switch (event->type)
00703     {
00704     case GDK_ENTER_NOTIFY:
00705       hightlight(item, TRUE);
00706       break;
00707     case GDK_LEAVE_NOTIFY:
00708       hightlight(item, FALSE);
00709       break;
00710     case GDK_BUTTON_PRESS:
00711 
00712       /* If there is already an animation do nothing */
00713       if(animation)
00714        return FALSE;
00715 
00716       if(item == lock_left_item)
00717        {
00718          if(lock_water_low && canallock_right_up)
00719              toggle_lock(item);
00720          else
00721            gc_sound_play_ogg ("sounds/crash.ogg", NULL);
00722 
00723        }
00724       else if(item == lock_right_item)
00725        {
00726          if(!lock_water_low && canallock_left_up)
00727              toggle_lock(item);
00728          else
00729            gc_sound_play_ogg ("sounds/crash.ogg", NULL);
00730        }
00731       else if(item == canallock_left_item && canallock_right_up)
00732        {
00733          if(lock_right_up)
00734              toggle_lock(item);
00735          else
00736            gc_sound_play_ogg ("sounds/crash.ogg", NULL);
00737        }
00738       else if(item == canallock_right_item && canallock_left_up)
00739        {
00740          if(lock_left_up)
00741              toggle_lock(item);
00742          else
00743            gc_sound_play_ogg ("sounds/crash.ogg", NULL);
00744        }
00745       else if(item == tuxboat_item)
00746        {
00747          move_boat();
00748        }
00749       else
00750        {
00751          gc_sound_play_ogg ("sounds/crash.ogg", NULL);
00752        }
00753       break;
00754     default:
00755       break;
00756     }
00757   return FALSE;
00758 
00759 
00760   /*
00761     gamewon = TRUE;
00762     canal_lock_destroy_all_items();
00763     gc_bonus_display(gamewon, BONUS_SMILEY);
00764   */
00765   return FALSE;
00766 }
00767