Back to index

gcompris  8.2.2
submarine.c
Go to the documentation of this file.
00001 /* gcompris - submarine.c
00002  *
00003  * Copyright (C) 2003 Pascal Georges
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 DEG_TO_RAD(x) M_PI*(x)/180.0
00023 
00024 #define SOUNDLISTFILE PACKAGE
00025 
00026 static GcomprisBoard *gcomprisBoard = NULL;
00027 static gboolean board_paused = TRUE;
00028 
00029 static void start_board (GcomprisBoard *agcomprisBoard);
00030 static void pause_board (gboolean pause);
00031 static void end_board (void);
00032 static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
00033 static void set_level (guint level);
00034 static int gamewon;
00035 
00036 static void ok(void);
00037 static void game_won();
00038 
00039 #define PURGE_AR 225
00040 #define PURGE_AV 438
00041 #define REGLEUR 330
00042 #define CHASSE_BALLAST_AR_X 227
00043 #define CHASSE_BALLAST_AR_Y 97
00044 #define CHASSE_BALLAST_AV_X 440
00045 #define CHASSE_BALLAST_AV_Y 98
00046 #define CHASSE_REGLEUR_X 331
00047 #define CHASSE_REGLEUR_Y 72
00048 #define BARRE_AR_X 100
00049 #define BARRE_AR_Y 50
00050 #define BARRE_AV_X 530
00051 #define BARRE_AV_Y 100
00052 
00053 #define BALLAST_AV_AIR_TEXT_X 440
00054 #define BALLAST_AV_AIR_TEXT_Y 50
00055 #define BALLAST_AV_AIR_X1 393
00056 #define BALLAST_AV_AIR_Y1 20
00057 #define BALLAST_AV_AIR_X2 483
00058 #define BALLAST_AV_AIR_Y2 80
00059 
00060 #define BALLAST_AR_AIR_TEXT_X 220
00061 #define BALLAST_AR_AIR_TEXT_Y 50
00062 #define BALLAST_AR_AIR_X1 180
00063 #define BALLAST_AR_AIR_Y1 20
00064 #define BALLAST_AR_AIR_X2 270
00065 #define BALLAST_AR_AIR_Y2 80
00066 
00067 // taken from submarine.png
00068 #define SUBMARINE_WIDTH 122
00069 #define SUBMARINE_HEIGHT 29
00070 
00071 #define SURFACE_IN_BACKGROUND 30
00072 #define SURFACE_DEPTH 7.0
00073 #define IP_DEPTH 13.0
00074 #define SECURITY_DEPTH 55.0
00075 #define MAX_DEPTH 250.0
00076 #define SPEED_MAX 10
00077 #define SPEED_STEP 1
00078 #define AIR_INITIAL 30000
00079 #define BATTERY_INITIAL 3000
00080 #define MAX_BALLAST 10000
00081 #define MAX_REGLEUR 800
00082 #define REGLEUR_INITIAL 500.0
00083 #define WEIGHT_INITIAL -300.0
00084 
00085 #define SUBMARINE_INITIAL_X 150
00086 #define WRAP_X 800
00087 #define SUBMARINE_INITIAL_DEPTH SURFACE_DEPTH
00088 
00089 #define RUDDER_STEP 5
00090 #define RUDDER_MAX 15
00091 #define RUDDER_CENTER_X 72
00092 #define RUDDER_CENTER_Y 7
00093 #define ENGINE_DOWN_X 42
00094 #define ENGINE_DOWN_Y 104
00095 #define ENGINE_UP_X 124
00096 #define ENGINE_UP_Y 104
00097 #define AIR_X 328
00098 #define AIR_Y 109
00099 #define BATTERY_X 285
00100 #define BATTERY_Y 156
00101 
00102 #define REGLEUR_TEXT_X 330
00103 #define REGLEUR_TEXT_Y 37
00104 #define REGLEUR_X1 325
00105 #define REGLEUR_Y1 18
00106 #define REGLEUR_X2 337
00107 #define REGLEUR_Y2 56
00108 
00109 #define AIR_TRIGGER_X 154
00110 #define AIR_TRIGGER_Y 108
00111 #define BATTERY_TRIGGER_X 184
00112 #define BATTERY_TRIGGER_Y 108
00113 #define TRIGGER_CENTER_X 7
00114 #define TRIGGER_CENTER_Y 23
00115 #define ALERT_SUBMARINE_X 719
00116 #define ALERT_SUBMARINE_Y 368
00117 
00118 #define UP 1
00119 #define DOWN 0
00120 
00121 #define FRIGATE_SPEED 5.0
00122 #define WHALE_DETECTION_RADIUS 30.0
00123 
00124 #define UPDATE_DELAY 200
00125 #define UPDATE_DELAY_SLOW 300
00126 #define UPDATE_DELAY_VERY_SLOW 1500
00127 
00128 #define TEXT_COLOR_FRONT "red"
00129 #define TEXT_COLOR_BACK "orange"
00130 
00131 /* ================================================================ */
00132 static GnomeCanvasGroup *boardRootItem = NULL;
00133 
00134 static GnomeCanvasItem *sub_schema_image_item, *submarine_item,
00135   *ballast_av_purge_item, *ballast_ar_purge_item, *regleur_purge_item;
00136 static GnomeCanvasItem *ballast_av_chasse_item, *ballast_ar_chasse_item, *regleur_chasse_item;
00137 gboolean ballast_av_purge_open, ballast_ar_purge_open, regleur_purge_open;
00138 gboolean ballast_av_chasse_open, ballast_ar_chasse_open, regleur_chasse_open;
00139 gboolean air_charging, battery_charging;
00140 gboolean submarine_destroyed;
00141 
00142 static GnomeCanvasItem *barre_av_item, *barre_ar_item,
00143   *barre_av_up_item, *barre_av_down_item, *barre_ar_up_item, *barre_ar_down_item,
00144   *engine_up_item, *engine_down_item,
00145   *speed_item_back, *speed_item_front,
00146   *air_item_back, *air_item_front,
00147   *regleur_item_back, *regleur_item_front,
00148   *regleur_item_rect,
00149   *battery_item_back, *battery_item_front,
00150   *ballast_av_air_item_back, *ballast_av_air_item_front,
00151   *ballast_ar_air_item_back, *ballast_ar_air_item_front,
00152   *ballast_av_air_item_rect, *ballast_ar_air_item_rect,
00153   *air_compressor_item, *battery_charger_item, *alert_submarine,
00154   *bubbling[3], *frigate_item, *big_explosion, *whale;
00155 
00156 /* submarine parameters */
00157 static double barre_av_angle, barre_ar_angle, depth, weight, resulting_weight, submarine_x, air, battery, regleur;
00158 static double submarine_horizontal_speed, submarine_vertical_speed, speed_ordered, assiette;
00159 static double ballast_av_air, ballast_ar_air;
00160 
00161 static double whale_x, whale_y;
00162 static guint schema_x, schema_y;
00163 
00164 static GnomeCanvasItem *submarine_create_item(GnomeCanvasGroup *parent);
00165 static void submarine_destroy_all_items(void);
00166 static void submarine_next_level(void);
00167 static gint ballast_av_purge_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00168 static gint ballast_ar_purge_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00169 static gint regleur_purge_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00170 static gint ballast_ar_chasse_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00171 static gint ballast_av_chasse_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00172 static gint regleur_chasse_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00173 static gint barre_av_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00174 static gint barre_ar_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00175 static gint engine_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00176 static gint air_compressor_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00177 static gint battery_charger_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00178 
00179 static void setSpeed(double value);
00180 static void setBattery(double value);
00181 static void setAir(double value);
00182 static void setRegleur(double value);
00183 static void setBallastAV(double value);
00184 static void setBallastAR(double value);
00185 
00186 static void submarine_explosion();
00187 
00188 static gboolean update_timeout();
00189 static gboolean update_timeout_slow();
00190 static gboolean update_timeout_very_slow();
00191 static guint timer_id, timer_slow_id, timer_very_slow_id;
00192 
00193 /* Description of this plugin */
00194 static BoardPlugin menu_bp =
00195   {
00196     NULL,
00197     NULL,
00198     N_("Submarine"),
00199     N_("Control the depth of a submarine"),
00200     "Pascal Georges pascal.georges1@free.fr>",
00201     NULL,
00202     NULL,
00203     NULL,
00204     NULL,
00205     start_board,
00206     pause_board,
00207     end_board,
00208     is_our_board,
00209     NULL,
00210     NULL,
00211     set_level,
00212     NULL,
00213     NULL,
00214     NULL,
00215     NULL
00216   };
00217 
00218 /* =====================================================================
00219  *
00220  * =====================================================================*/
00221 GET_BPLUGIN_INFO(submarine)
00222 
00223 /* =====================================================================
00224  * in : boolean TRUE = PAUSE : FALSE = CONTINUE
00225  * =====================================================================*/
00226 static void pause_board (gboolean pause)
00227 {
00228   if(gcomprisBoard==NULL)
00229     return;
00230 
00231   if(gamewon == TRUE && pause == FALSE) /* the game is won */
00232     game_won();
00233 
00234   board_paused = pause;
00235 }
00236 
00237 /* =====================================================================
00238  *
00239  * =====================================================================*/
00240 static void start_board (GcomprisBoard *agcomprisBoard) {
00241   if(agcomprisBoard!=NULL) {
00242     gcomprisBoard=agcomprisBoard;
00243     gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), "submarine/sub_bg.jpg");
00244     gcomprisBoard->level=1;
00245     gcomprisBoard->sublevel=1;
00246     submarine_next_level();
00247     gamewon = FALSE;
00248     pause_board(FALSE);
00249   }
00250 }
00251 
00252 /* =====================================================================
00253  *
00254  * =====================================================================*/
00255 static void end_board () {
00256   if(gcomprisBoard!=NULL){
00257     pause_board(TRUE);
00258     submarine_destroy_all_items();
00259   }
00260   /* kill pending timers */
00261   g_source_remove(timer_id);
00262   g_source_remove(timer_slow_id);
00263   g_source_remove(timer_very_slow_id);
00264 
00265   gcomprisBoard = NULL;
00266 }
00267 
00268 /* =====================================================================
00269  *
00270  * =====================================================================*/
00271 static void set_level (guint level) {
00272   if(gcomprisBoard!=NULL) {
00273     gcomprisBoard->level=level;
00274     gcomprisBoard->sublevel=1;
00275     submarine_next_level();
00276   }
00277 }
00278 
00279 /* =====================================================================
00280  *
00281  * =====================================================================*/
00282 static gboolean is_our_board (GcomprisBoard *gcomprisBoard) {
00283   if (gcomprisBoard) {
00284     if(g_strcasecmp(gcomprisBoard->type, "submarine")==0) {
00285       /* Set the plugin entry */
00286       gcomprisBoard->plugin=&menu_bp;
00287       return TRUE;
00288     }
00289   }
00290   return FALSE;
00291 }
00292 /* =====================================================================
00293  * set initial values for the next level
00294  * =====================================================================*/
00295 static void submarine_next_level() {
00296   ballast_av_purge_open = ballast_ar_purge_open = regleur_purge_open = FALSE;
00297   ballast_av_chasse_open = ballast_ar_chasse_open = regleur_chasse_open = FALSE;
00298   air_charging = battery_charging = FALSE;
00299   barre_av_angle = barre_ar_angle = 0.0;
00300   depth = SUBMARINE_INITIAL_DEPTH;
00301   submarine_horizontal_speed = speed_ordered = 0.0;
00302   submarine_x = SUBMARINE_INITIAL_X;
00303   weight = WEIGHT_INITIAL;
00304   regleur = REGLEUR_INITIAL;
00305   air = AIR_INITIAL;
00306   battery = BATTERY_INITIAL;
00307   ballast_av_air = ballast_ar_air = MAX_BALLAST/10.0;
00308   submarine_destroyed = FALSE;
00309 
00310   gc_bar_set(0);
00311 
00312   submarine_destroy_all_items();
00313   gamewon = FALSE;
00314 
00315   /* Try the next level */
00316   submarine_create_item(gnome_canvas_root(gcomprisBoard->canvas));
00317 
00318 }
00319 /* =====================================================================
00320  * Destroy all the items
00321  * =====================================================================*/
00322 static void submarine_destroy_all_items() {
00323   if(boardRootItem!=NULL)
00324     gtk_object_destroy (GTK_OBJECT(boardRootItem));
00325 
00326   boardRootItem = NULL;
00327 }
00328 
00329 /* =====================================================================
00330  *
00331  * =====================================================================*/
00332 static GnomeCanvasItem *submarine_create_item(GnomeCanvasGroup *parent) {
00333   GdkPixbuf *pixmap = NULL;
00334   char *str = NULL;
00335   char s12[12];
00336   int i, w, h;
00337 
00338   boardRootItem = GNOME_CANVAS_GROUP(
00339                                  gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
00340                                                      gnome_canvas_group_get_type (),
00341                                                      "x", (double) 0,
00342                                                      "y", (double) 0,
00343                                                      NULL));
00344 
00345   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "submarine.png");
00346   pixmap = gc_pixmap_load(str);
00347   submarine_item = gnome_canvas_item_new (boardRootItem,
00348                                      gnome_canvas_pixbuf_get_type (),
00349                                      "pixbuf", pixmap,
00350                                      "x", (double) 0.0,//SUBMARINE_INITIAL_X,
00351                                      "y", (double) 0.0,//SUBMARINE_INITIAL_DEPTH + SURFACE_IN_BACKGROUND - SUBMARINE_HEIGHT,
00352                                      "width", (double) gdk_pixbuf_get_width(pixmap),
00353                                      "height", (double) gdk_pixbuf_get_height(pixmap),
00354                                      "width_set", TRUE,
00355                                      "height_set", TRUE,
00356                                      "anchor", GTK_ANCHOR_CENTER,
00357                                      NULL);
00358 
00359   g_free(str);
00360   gdk_pixbuf_unref(pixmap);
00361 
00362   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "sub_schema.png");
00363   pixmap = gc_pixmap_load(str);
00364 
00365   w = gdk_pixbuf_get_width(pixmap);
00366   h = gdk_pixbuf_get_height(pixmap);
00367 
00368   schema_x = (gcomprisBoard->width - w)/2 ;
00369   schema_y = gcomprisBoard->height - h;
00370   sub_schema_image_item = gnome_canvas_item_new (boardRootItem,
00371                                            gnome_canvas_pixbuf_get_type (),
00372                                            "pixbuf", pixmap,
00373                                            "x", (double) schema_x + w/2.0,
00374                                            "y", (double) schema_y + h/2.0,
00375                                            "width", (double) w,
00376                                            "height", (double) h,
00377                                            "width_set", TRUE,
00378                                            "height_set", TRUE,
00379                                            "anchor", GTK_ANCHOR_CENTER,
00380                                            NULL);
00381 
00382   g_free(str);
00383   gdk_pixbuf_unref(pixmap);
00384 
00385   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "vanne.png");
00386   pixmap = gc_pixmap_load(str);
00387   w = gdk_pixbuf_get_width(pixmap);
00388   h = gdk_pixbuf_get_height(pixmap);
00389   ballast_ar_purge_item = gnome_canvas_item_new (boardRootItem,
00390                                            gnome_canvas_pixbuf_get_type (),
00391                                            "pixbuf", pixmap,
00392                                            "x", (double) PURGE_AR + schema_x,
00393                                            "y", (double) schema_y + h/2.0 -1.0,
00394                                            "width", (double) w,
00395                                            "height", (double) h,
00396                                            "width_set", TRUE,
00397                                            "height_set", TRUE,
00398                                            "anchor", GTK_ANCHOR_CENTER,
00399                                            NULL);
00400   gtk_signal_connect(GTK_OBJECT(ballast_ar_purge_item), "event",  (GtkSignalFunc) ballast_ar_purge_event, NULL);
00401 
00402   ballast_av_purge_item = gnome_canvas_item_new (boardRootItem,
00403                                            gnome_canvas_pixbuf_get_type (),
00404                                            "pixbuf", pixmap,
00405                                            "x", (double) PURGE_AV + schema_x,
00406                                            "y", (double) schema_y + h/2.0 -1.0,
00407                                            "width", (double) gdk_pixbuf_get_width(pixmap),
00408                                            "height", (double) gdk_pixbuf_get_height(pixmap),
00409                                            "width_set", TRUE,
00410                                            "height_set", TRUE,
00411                                            "anchor", GTK_ANCHOR_CENTER,
00412                                            NULL);
00413   gtk_signal_connect(GTK_OBJECT(ballast_av_purge_item), "event",  (GtkSignalFunc) ballast_av_purge_event, NULL);
00414 
00415   regleur_purge_item = gnome_canvas_item_new (boardRootItem,
00416                                          gnome_canvas_pixbuf_get_type (),
00417                                          "pixbuf", pixmap,
00418                                          "x", (double) REGLEUR + schema_x,
00419                                          "y", (double) schema_y + h/2.0 -2.0,
00420                                          "width", (double) gdk_pixbuf_get_width(pixmap),
00421                                          "height", (double) gdk_pixbuf_get_height(pixmap),
00422                                          "width_set", TRUE,
00423                                          "height_set", TRUE,
00424                                          "anchor", GTK_ANCHOR_CENTER,
00425                                          NULL);
00426   gtk_signal_connect(GTK_OBJECT(regleur_purge_item), "event",  (GtkSignalFunc) regleur_purge_event, NULL);
00427 
00428   ballast_av_chasse_item = gnome_canvas_item_new (boardRootItem,
00429                                             gnome_canvas_pixbuf_get_type (),
00430                                             "pixbuf", pixmap,
00431                                             "x", (double) schema_x + CHASSE_BALLAST_AV_X,
00432                                             "y", (double) schema_y +  CHASSE_BALLAST_AV_Y,
00433                                             "width", (double) gdk_pixbuf_get_width(pixmap),
00434                                             "height", (double) gdk_pixbuf_get_height(pixmap),
00435                                             "width_set", TRUE,
00436                                             "height_set", TRUE,
00437                                             "anchor", GTK_ANCHOR_CENTER,
00438                                             NULL);
00439   gtk_signal_connect(GTK_OBJECT(ballast_av_chasse_item), "event",  (GtkSignalFunc) ballast_av_chasse_event, NULL);
00440 
00441   ballast_ar_chasse_item = gnome_canvas_item_new (boardRootItem,
00442                                             gnome_canvas_pixbuf_get_type (),
00443                                             "pixbuf", pixmap,
00444                                             "x", (double) schema_x + CHASSE_BALLAST_AR_X,
00445                                             "y", (double) schema_y +  CHASSE_BALLAST_AR_Y,
00446                                             "width", (double) gdk_pixbuf_get_width(pixmap),
00447                                             "height", (double) gdk_pixbuf_get_height(pixmap),
00448                                             "width_set", TRUE,
00449                                             "height_set", TRUE,
00450                                             "anchor", GTK_ANCHOR_CENTER,
00451                                             NULL);
00452   gtk_signal_connect(GTK_OBJECT(ballast_ar_chasse_item), "event",  (GtkSignalFunc) ballast_ar_chasse_event, NULL);
00453 
00454   regleur_chasse_item = gnome_canvas_item_new (boardRootItem,
00455                                           gnome_canvas_pixbuf_get_type (),
00456                                           "pixbuf", pixmap,
00457                                           "x", (double) schema_x + CHASSE_REGLEUR_X,
00458                                           "y", (double) schema_y + CHASSE_REGLEUR_Y,
00459                                           "width", (double) gdk_pixbuf_get_width(pixmap),
00460                                           "height", (double) gdk_pixbuf_get_height(pixmap),
00461                                           "width_set", TRUE,
00462                                           "height_set", TRUE,
00463                                           "anchor", GTK_ANCHOR_CENTER,
00464                                           NULL);
00465   gtk_signal_connect(GTK_OBJECT(regleur_chasse_item), "event",  (GtkSignalFunc) regleur_chasse_event, NULL);
00466 
00467   g_free(str);
00468   gdk_pixbuf_unref(pixmap);
00469 
00470   // DEPTH RUDDERS
00471   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "rudder.png");
00472   pixmap = gc_pixmap_load(str);
00473   barre_av_item = gnome_canvas_item_new (boardRootItem,
00474                                     gnome_canvas_pixbuf_get_type (),
00475                                     "pixbuf", pixmap,
00476                                     "x", (double) schema_x + BARRE_AV_X,
00477                                     "y", (double) schema_y + BARRE_AV_Y,
00478                                     "width", (double) gdk_pixbuf_get_width(pixmap),
00479                                     "height", (double) gdk_pixbuf_get_height(pixmap),
00480                                     "width_set", TRUE,
00481                                     "height_set", TRUE,
00482                                     "anchor", GTK_ANCHOR_CENTER,
00483                                     NULL);
00484   barre_ar_item = gnome_canvas_item_new (boardRootItem,
00485                                     gnome_canvas_pixbuf_get_type (),
00486                                     "pixbuf", pixmap,
00487                                     "x", (double) schema_x + BARRE_AR_X,
00488                                     "y", (double) schema_y + BARRE_AR_Y,
00489                                     "width", (double) gdk_pixbuf_get_width(pixmap),
00490                                     "height", (double) gdk_pixbuf_get_height(pixmap),
00491                                     "width_set", TRUE,
00492                                     "height_set", TRUE,
00493                                     "anchor", GTK_ANCHOR_CENTER,
00494                                     NULL);
00495   g_free(str);
00496   gdk_pixbuf_unref(pixmap);
00497 
00498 #define COMMAND_OFFSET 20.0
00499   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "up.png");
00500   pixmap = gc_pixmap_load(str);
00501   barre_av_up_item = gnome_canvas_item_new (boardRootItem,
00502                                        gnome_canvas_pixbuf_get_type (),
00503                                        "pixbuf", pixmap,
00504                                        "x", (double) schema_x + BARRE_AV_X + COMMAND_OFFSET,
00505                                        "y", (double) schema_y + BARRE_AV_Y - COMMAND_OFFSET,
00506                                        "width", (double) gdk_pixbuf_get_width(pixmap),
00507                                        "height", (double) gdk_pixbuf_get_height(pixmap),
00508                                        "width_set", TRUE,
00509                                        "height_set", TRUE,
00510                                        "anchor", GTK_ANCHOR_CENTER,
00511                                        NULL);
00512   barre_ar_up_item = gnome_canvas_item_new (boardRootItem,
00513                                        gnome_canvas_pixbuf_get_type (),
00514                                        "pixbuf", pixmap,
00515                                        "x", (double) schema_x + BARRE_AR_X + COMMAND_OFFSET,
00516                                        "y", (double) schema_y + BARRE_AR_Y - COMMAND_OFFSET,
00517                                        "width", (double) gdk_pixbuf_get_width(pixmap),
00518                                        "height", (double) gdk_pixbuf_get_height(pixmap),
00519                                        "width_set", TRUE,
00520                                        "height_set", TRUE,
00521                                        "anchor", GTK_ANCHOR_CENTER,
00522                                        NULL);
00523   engine_up_item = gnome_canvas_item_new (boardRootItem,
00524                                      gnome_canvas_pixbuf_get_type (),
00525                                      "pixbuf", pixmap,
00526                                      "x", (double) schema_x + ENGINE_UP_X,
00527                                      "y", (double) schema_y + ENGINE_UP_Y,
00528                                      "width", (double) gdk_pixbuf_get_width(pixmap),
00529                                      "height", (double) gdk_pixbuf_get_height(pixmap),
00530                                      "width_set", TRUE,
00531                                      "height_set", TRUE,
00532                                      "anchor", GTK_ANCHOR_CENTER,
00533                                      NULL);
00534   g_free(str);
00535   gdk_pixbuf_unref(pixmap);
00536 
00537   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "down.png");
00538   pixmap = gc_pixmap_load(str);
00539   barre_av_down_item = gnome_canvas_item_new (boardRootItem,
00540                                          gnome_canvas_pixbuf_get_type (),
00541                                          "pixbuf", pixmap,
00542                                          "x", (double) schema_x + BARRE_AV_X + COMMAND_OFFSET,
00543                                          "y", (double) schema_y + BARRE_AV_Y + COMMAND_OFFSET,
00544                                          "width", (double) gdk_pixbuf_get_width(pixmap),
00545                                          "height", (double) gdk_pixbuf_get_height(pixmap),
00546                                          "width_set", TRUE,
00547                                          "height_set", TRUE,
00548                                          "anchor", GTK_ANCHOR_CENTER,
00549                                          NULL);
00550   barre_ar_down_item = gnome_canvas_item_new (boardRootItem,
00551                                          gnome_canvas_pixbuf_get_type (),
00552                                          "pixbuf", pixmap,
00553                                          "x", (double) schema_x + BARRE_AR_X + COMMAND_OFFSET,
00554                                          "y", (double) schema_y + BARRE_AR_Y + COMMAND_OFFSET,
00555                                          "width", (double) gdk_pixbuf_get_width(pixmap),
00556                                          "height", (double) gdk_pixbuf_get_height(pixmap),
00557                                          "width_set", TRUE,
00558                                          "height_set", TRUE,
00559                                          "anchor", GTK_ANCHOR_CENTER,
00560                                          NULL);
00561   engine_down_item = gnome_canvas_item_new (boardRootItem,
00562                                        gnome_canvas_pixbuf_get_type (),
00563                                        "pixbuf", pixmap,
00564                                        "x", (double) schema_x + ENGINE_DOWN_X,
00565                                        "y", (double) schema_y + ENGINE_DOWN_Y,
00566                                        "width", (double) gdk_pixbuf_get_width(pixmap),
00567                                        "height", (double) gdk_pixbuf_get_height(pixmap),
00568                                        "width_set", TRUE,
00569                                        "height_set", TRUE,
00570                                        "anchor", GTK_ANCHOR_CENTER,
00571                                        NULL);
00572   g_free(str);
00573   gdk_pixbuf_unref(pixmap);
00574 
00575   gtk_signal_connect(GTK_OBJECT(barre_av_up_item), "event",  (GtkSignalFunc) barre_av_event, GINT_TO_POINTER(UP));
00576   gtk_signal_connect(GTK_OBJECT(barre_ar_up_item), "event",  (GtkSignalFunc) barre_ar_event, GINT_TO_POINTER(UP));
00577   gtk_signal_connect(GTK_OBJECT(barre_av_down_item), "event",  (GtkSignalFunc) barre_av_event, GINT_TO_POINTER(DOWN));
00578   gtk_signal_connect(GTK_OBJECT(barre_ar_down_item), "event",  (GtkSignalFunc) barre_ar_event, GINT_TO_POINTER(DOWN));
00579   gtk_signal_connect(GTK_OBJECT(engine_up_item), "event",  (GtkSignalFunc) engine_event, GINT_TO_POINTER(UP));
00580   gtk_signal_connect(GTK_OBJECT(engine_down_item), "event",  (GtkSignalFunc) engine_event, GINT_TO_POINTER(DOWN));
00581 
00582   // displays the speed on the engine
00583   sprintf(s12,"%d",(int)submarine_horizontal_speed);
00584   speed_item_back = gnome_canvas_item_new (boardRootItem,
00585                                       gnome_canvas_text_get_type (),
00586                                       "text", s12,
00587                                       "font", gc_skin_font_board_title_bold,
00588                                       "x", (double) schema_x + (ENGINE_UP_X + ENGINE_DOWN_X)/2 +1,
00589                                       "y", (double) schema_y + ENGINE_UP_Y + 1,
00590                                       "anchor", GTK_ANCHOR_CENTER,
00591                                       "fill_color", TEXT_COLOR_BACK,
00592                                       NULL);
00593   speed_item_front = gnome_canvas_item_new (boardRootItem,
00594                                        gnome_canvas_text_get_type (),
00595                                        "text", s12,
00596                                        "font", gc_skin_font_board_title_bold,
00597                                        "x", (double) schema_x + (ENGINE_UP_X + ENGINE_DOWN_X)/2,
00598                                        "y", (double) schema_y + ENGINE_UP_Y,
00599                                        "anchor", GTK_ANCHOR_CENTER,
00600                                        "fill_color", TEXT_COLOR_FRONT,
00601                                        NULL);
00602 
00603   // displays the ballast_av_air value
00604   ballast_av_air_item_rect = gnome_canvas_item_new (boardRootItem,
00605                                               gnome_canvas_rect_get_type (),
00606                                               "x1", (double) schema_x + BALLAST_AV_AIR_X1,
00607                                               "y1", (double) schema_y + BALLAST_AV_AIR_Y2,
00608                                               "x2", (double) schema_x + BALLAST_AV_AIR_X2,
00609                                               "y2", (double) schema_y + BALLAST_AV_AIR_Y2,
00610                                               "fill_color", "blue",
00611                                               "width_pixels", 0,
00612                                               NULL);
00613 
00614   sprintf(s12,"%d",(int)ballast_av_air);
00615   ballast_av_air_item_back = gnome_canvas_item_new (boardRootItem,
00616                                               gnome_canvas_text_get_type (),
00617                                               "text", s12,
00618                                               "font", gc_skin_font_board_title_bold,
00619                                               "x", (double) schema_x + BALLAST_AV_AIR_TEXT_X + 1,
00620                                               "y", (double) schema_y + BALLAST_AV_AIR_TEXT_Y + 1,
00621                                               "anchor", GTK_ANCHOR_CENTER,
00622                                               "fill_color", TEXT_COLOR_BACK,
00623                                               NULL);
00624   ballast_av_air_item_front = gnome_canvas_item_new (boardRootItem,
00625                                                gnome_canvas_text_get_type (),
00626                                                "text", s12,
00627                                                "font", gc_skin_font_board_title_bold,
00628                                                "x", (double) schema_x + BALLAST_AV_AIR_TEXT_X,
00629                                                "y", (double) schema_y + BALLAST_AV_AIR_TEXT_Y,
00630                                                "anchor", GTK_ANCHOR_CENTER,
00631                                                "fill_color", TEXT_COLOR_FRONT,
00632                                                NULL);
00633   setBallastAV(ballast_av_air);
00634 
00635   // displays the ballast_ar_air value
00636   ballast_ar_air_item_rect = gnome_canvas_item_new (boardRootItem,
00637                                               gnome_canvas_rect_get_type (),
00638                                               "x1", (double) schema_x + BALLAST_AR_AIR_X1,
00639                                               "y1", (double) schema_y + BALLAST_AR_AIR_Y2,
00640                                               "x2", (double) schema_x + BALLAST_AR_AIR_X2,
00641                                               "y2", (double) schema_y + BALLAST_AR_AIR_Y2,
00642                                               "fill_color", "blue",
00643                                               "width_pixels", 0,
00644                                               NULL);
00645 
00646   sprintf(s12,"%d",(int)ballast_ar_air);
00647   ballast_ar_air_item_back = gnome_canvas_item_new (boardRootItem,
00648                                               gnome_canvas_text_get_type (),
00649                                               "text", s12,
00650                                               "font", gc_skin_font_board_title_bold,
00651                                               "x", (double) schema_x + BALLAST_AR_AIR_TEXT_X + 1,
00652                                               "y", (double) schema_y + BALLAST_AR_AIR_TEXT_Y + 1,
00653                                               "anchor", GTK_ANCHOR_CENTER,
00654                                               "fill_color", TEXT_COLOR_BACK,
00655                                               NULL);
00656   ballast_ar_air_item_front = gnome_canvas_item_new (boardRootItem,
00657                                                gnome_canvas_text_get_type (),
00658                                                "text", s12,
00659                                                "font", gc_skin_font_board_title_bold,
00660                                                "x", (double) schema_x + BALLAST_AR_AIR_TEXT_X,
00661                                                "y", (double) schema_y + BALLAST_AR_AIR_TEXT_Y,
00662                                                "anchor", GTK_ANCHOR_CENTER,
00663                                                "fill_color", TEXT_COLOR_FRONT,
00664                                                NULL);
00665     setBallastAR(ballast_ar_air);
00666 
00667   // displays the remaining air value
00668   sprintf(s12,"%d", (int)air);
00669   air_item_back = gnome_canvas_item_new (boardRootItem,
00670                                     gnome_canvas_text_get_type (),
00671                                     "text", s12,
00672                                     "font", gc_skin_font_board_title_bold,
00673                                     "x", (double) schema_x + AIR_X +1,
00674                                     "y", (double) schema_y + AIR_Y + 1,
00675                                     "anchor", GTK_ANCHOR_CENTER,
00676                                     "fill_color", TEXT_COLOR_BACK,
00677                                     NULL);
00678   air_item_front = gnome_canvas_item_new (boardRootItem,
00679                                      gnome_canvas_text_get_type (),
00680                                      "text", s12,
00681                                      "font", gc_skin_font_board_title_bold,
00682                                      "x", (double) schema_x + AIR_X,
00683                                      "y", (double) schema_y + AIR_Y,
00684                                      "anchor", GTK_ANCHOR_CENTER,
00685                                      "fill_color", TEXT_COLOR_FRONT,
00686                                      NULL);
00687 
00688   // displays the remaining battery value
00689   sprintf(s12,"%d", (int)battery);
00690   battery_item_back = gnome_canvas_item_new (boardRootItem,
00691                                         gnome_canvas_text_get_type (),
00692                                         "text", s12,
00693                                         "font", gc_skin_font_board_title_bold,
00694                                         "x", (double) schema_x + BATTERY_X +1,
00695                                         "y", (double) schema_y + BATTERY_Y + 1,
00696                                         "anchor", GTK_ANCHOR_CENTER,
00697                                         "fill_color", TEXT_COLOR_BACK,
00698                                         NULL);
00699   battery_item_front = gnome_canvas_item_new (boardRootItem,
00700                                          gnome_canvas_text_get_type (),
00701                                          "text", s12,
00702                                          "font", gc_skin_font_board_title_bold,
00703                                          "x", (double) schema_x + BATTERY_X,
00704                                          "y", (double) schema_y + BATTERY_Y,
00705                                          "anchor", GTK_ANCHOR_CENTER,
00706                                          "fill_color", TEXT_COLOR_FRONT,
00707                                          NULL);
00708 
00709   // displays the remaining regleur value
00710   regleur_item_rect = gnome_canvas_item_new (boardRootItem,
00711                                         gnome_canvas_rect_get_type (),
00712                                         "x1", (double) schema_x + REGLEUR_X1,
00713                                         "y1", (double) schema_y + REGLEUR_Y2,
00714                                         "x2", (double) schema_x + REGLEUR_X2,
00715                                         "y2", (double) schema_y + REGLEUR_Y2,
00716                                         "fill_color", "blue",
00717                                         "width_pixels", 0,
00718                                         NULL);
00719 
00720   sprintf(s12,"%d", (int)regleur);
00721   regleur_item_back = gnome_canvas_item_new (boardRootItem,
00722                                         gnome_canvas_text_get_type (),
00723                                         "text", s12,
00724                                         "font", gc_skin_font_board_title_bold,
00725                                         "x", (double) schema_x + REGLEUR_TEXT_X +1,
00726                                         "y", (double) schema_y + REGLEUR_TEXT_Y + 1,
00727                                         "anchor", GTK_ANCHOR_CENTER,
00728                                         "fill_color", TEXT_COLOR_BACK,
00729                                         NULL);
00730   regleur_item_front = gnome_canvas_item_new (boardRootItem,
00731                                          gnome_canvas_text_get_type (),
00732                                          "text", s12,
00733                                          "font", gc_skin_font_board_title_bold,
00734                                          "x", (double) schema_x + REGLEUR_TEXT_X,
00735                                          "y", (double) schema_y + REGLEUR_TEXT_Y,
00736                                          "anchor", GTK_ANCHOR_CENTER,
00737                                          "fill_color", TEXT_COLOR_FRONT,
00738                                          NULL);
00739   setRegleur(regleur);
00740 
00741   // displays an alert when some parameters are bad
00742   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "alert_submarine.png");
00743   pixmap = gc_pixmap_load(str);
00744   alert_submarine = gnome_canvas_item_new (boardRootItem,
00745                                       gnome_canvas_pixbuf_get_type (),
00746                                       "pixbuf", pixmap,
00747                                       "x", (double) ALERT_SUBMARINE_X,
00748                                       "y", (double) ALERT_SUBMARINE_Y,
00749                                       "width", (double) gdk_pixbuf_get_width(pixmap),
00750                                       "height", (double) gdk_pixbuf_get_height(pixmap),
00751                                       "width_set", TRUE,
00752                                       "height_set", TRUE,
00753                                       "anchor", GTK_ANCHOR_CENTER,
00754                                       NULL);
00755   g_free(str);
00756   gdk_pixbuf_unref(pixmap);
00757   gnome_canvas_item_hide(alert_submarine);
00758 
00759   // when the submarine makes some bubbles ...
00760   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "bubbling.png");
00761   pixmap = gc_pixmap_load(str);
00762   for (i=0; i<3; i++) {
00763     bubbling[i] = gnome_canvas_item_new (boardRootItem,
00764                                     gnome_canvas_pixbuf_get_type (),
00765                                     "pixbuf", pixmap,
00766                                     "x", (double) 0.0,
00767                                     "y", (double) 0.0,
00768                                     "width", (double) gdk_pixbuf_get_width(pixmap),
00769                                     "height", (double) gdk_pixbuf_get_height(pixmap),
00770                                     "width_set", TRUE,
00771                                     "height_set", TRUE,
00772                                     "anchor", GTK_ANCHOR_CENTER,
00773                                     NULL);
00774     gnome_canvas_item_hide(bubbling[i]);
00775   }
00776   g_free(str);
00777   gdk_pixbuf_unref(pixmap);
00778 
00779   // whale item
00780   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "whale.png");
00781   pixmap = gc_pixmap_load(str);
00782   whale_x = RAND((int)(gdk_pixbuf_get_width(pixmap)), (int)(gcomprisBoard->width-gdk_pixbuf_get_width(pixmap)));
00783   whale_y = RAND((int)(SURFACE_IN_BACKGROUND + gdk_pixbuf_get_height(pixmap)),(int)MAX_DEPTH);
00784   whale = gnome_canvas_item_new (boardRootItem,
00785                             gnome_canvas_pixbuf_get_type (),
00786                             "pixbuf", pixmap,
00787                             "x", (double) whale_x,
00788                             "y", (double) whale_y,
00789                             "width", (double) gdk_pixbuf_get_width(pixmap),
00790                             "height", (double) gdk_pixbuf_get_height(pixmap),
00791                             "width_set", TRUE,
00792                             "height_set", TRUE,
00793                             "anchor", GTK_ANCHOR_CENTER,
00794                             NULL);
00795   g_free(str);
00796   gdk_pixbuf_unref(pixmap);
00797 
00798   // big explosion item (only for the whale)
00799   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "whale_hit.png");
00800   pixmap = gc_pixmap_load(str);
00801   big_explosion = gnome_canvas_item_new (boardRootItem,
00802                                     gnome_canvas_pixbuf_get_type (),
00803                                     "pixbuf", pixmap,
00804                                     "x", (double) whale_x,
00805                                     "y", (double) whale_y,
00806                                     "width", (double) gdk_pixbuf_get_width(pixmap),
00807                                     "height", (double) gdk_pixbuf_get_height(pixmap),
00808                                     "width_set", TRUE,
00809                                     "height_set", TRUE,
00810                                     "anchor", GTK_ANCHOR_CENTER,
00811                                     NULL);
00812   gnome_canvas_item_hide(big_explosion);
00813 
00814   g_free(str);
00815   gdk_pixbuf_unref(pixmap);
00816 
00817   // the triggers for air compressor and battery charger
00818   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "manette.png");
00819   pixmap = gc_pixmap_load(str);
00820   air_compressor_item = gnome_canvas_item_new (boardRootItem,
00821                                           gnome_canvas_pixbuf_get_type (),
00822                                           "pixbuf", pixmap,
00823                                           "x", (double) schema_x + AIR_TRIGGER_X,
00824                                           "y", (double) schema_y + AIR_TRIGGER_Y,
00825                                           "width", (double) gdk_pixbuf_get_width(pixmap),
00826                                           "height", (double) gdk_pixbuf_get_height(pixmap),
00827                                           "width_set", TRUE,
00828                                           "height_set", TRUE,
00829                                           "anchor", GTK_ANCHOR_CENTER,
00830                                           NULL);
00831   battery_charger_item = gnome_canvas_item_new (boardRootItem,
00832                                           gnome_canvas_pixbuf_get_type (),
00833                                           "pixbuf", pixmap,
00834                                           "x", (double) schema_x + BATTERY_TRIGGER_X,
00835                                           "y", (double) schema_y + BATTERY_TRIGGER_Y,
00836                                           "width", (double) gdk_pixbuf_get_width(pixmap),
00837                                           "height", (double) gdk_pixbuf_get_height(pixmap),
00838                                           "width_set", TRUE,
00839                                           "height_set", TRUE,
00840                                           "anchor", GTK_ANCHOR_CENTER,
00841                                           NULL);
00842   g_free(str);
00843   gdk_pixbuf_unref(pixmap);
00844 
00845   // the antisubmarine warfare frigate
00846   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "asw_frigate.png");
00847   pixmap = gc_pixmap_load(str);
00848   frigate_item = gnome_canvas_item_new (boardRootItem,
00849                                    gnome_canvas_pixbuf_get_type (),
00850                                    "pixbuf", pixmap,
00851                                    "x", (double) 700.0,
00852                                    "y", (double) 2.0,
00853                                    "width", (double) gdk_pixbuf_get_width(pixmap),
00854                                    "height", (double) gdk_pixbuf_get_height(pixmap),
00855                                    "width_set", TRUE,
00856                                    "height_set", TRUE,
00857                                    //"anchor", GTK_ANCHOR_CENTER,
00858                                    NULL);
00859   g_free(str);
00860   gdk_pixbuf_unref(pixmap);
00861 
00862   gtk_signal_connect(GTK_OBJECT(air_compressor_item), "event",  (GtkSignalFunc) air_compressor_event, NULL);
00863   gtk_signal_connect(GTK_OBJECT(battery_charger_item), "event",  (GtkSignalFunc) battery_charger_event, NULL);
00864 
00865   timer_id = g_timeout_add(UPDATE_DELAY, update_timeout, NULL);
00866   timer_slow_id = g_timeout_add(UPDATE_DELAY_SLOW, update_timeout_slow, NULL);
00867   timer_very_slow_id = g_timeout_add(UPDATE_DELAY_VERY_SLOW, update_timeout_very_slow, NULL);
00868 
00869   return NULL;
00870 }
00871 /* =====================================================================
00872  * Periodically recalculate the submarine parameters
00873  * =====================================================================*/
00874 static gboolean update_timeout() {
00875   double delta_air;
00876   gboolean regleur_dirty = FALSE;
00877   gboolean air_dirty = FALSE;
00878 
00879   if(board_paused)
00880     return FALSE;
00881 
00882   /* air in ballasts */
00883   if (ballast_av_purge_open) {
00884     ballast_av_air -= UPDATE_DELAY/1000.0 *500.0; // 500 liters go out per second
00885     if (ballast_av_air < 0.0)
00886       ballast_av_air = 0.0;
00887     setBallastAV(ballast_av_air);
00888   }
00889   if (ballast_ar_purge_open) {
00890     ballast_ar_air -= UPDATE_DELAY/1000.0 *500.0;
00891     if (ballast_ar_air < 0.0)
00892       ballast_ar_air = 0.0;
00893     setBallastAR(ballast_ar_air);
00894   }
00895   if (ballast_av_chasse_open && air>0.0) {
00896     delta_air = UPDATE_DELAY/1000.0 *500.0; // 200 liters are injected each second
00897     ballast_av_air += delta_air;
00898     air -= delta_air;
00899     if (air<0.0)
00900       air = 0.0;
00901     if (ballast_av_air > MAX_BALLAST)
00902       ballast_av_air = MAX_BALLAST;
00903     air_dirty = TRUE;
00904     setBallastAV(ballast_av_air);
00905   }
00906   if (ballast_ar_chasse_open && air>0.0) {
00907     delta_air = UPDATE_DELAY/1000.0 *500.0;
00908     ballast_ar_air += delta_air;
00909     air -= delta_air;
00910     if (air<0.0)
00911       air = 0.0;
00912     if (ballast_ar_air > MAX_BALLAST)
00913       ballast_ar_air = MAX_BALLAST;
00914     air_dirty = TRUE;
00915     setBallastAR(ballast_ar_air);
00916   }
00917 
00918   if (air_dirty)
00919     setAir(air);
00920 
00921   /* air in "regleur" (small ballast to finely balance the submarine) */
00922   if (regleur_purge_open) {
00923     regleur += UPDATE_DELAY/1000.0 *50.0; // 100 liters enter per second
00924     if (regleur > MAX_REGLEUR)
00925       regleur = MAX_REGLEUR;
00926     regleur_dirty = TRUE;
00927   }
00928   if (regleur_chasse_open && air>0.0 && regleur > 0.0) {
00929     delta_air = UPDATE_DELAY/1000.0 *50.0; // 50 liters are injected each second
00930     regleur -= delta_air;
00931     air -= delta_air;
00932     if (air<0.0)
00933       air = 0.0;
00934     if (regleur < 0.0)
00935       regleur = 0.0;
00936     regleur_dirty = TRUE;
00937     setAir(air);
00938   }
00939 
00940   if (regleur_dirty)
00941     setRegleur(regleur);
00942 
00943   return TRUE;
00944 }
00945 /* =====================================================================
00946  * Periodically recalculate some submarine parameters, with a larger delay
00947  * =====================================================================*/
00948 static gboolean update_timeout_slow() {
00949   double delta_assiette;
00950 
00951   if(board_paused)
00952     return FALSE;
00953 
00954   /* speed : don't reach instantly the ordered speed */
00955   if (speed_ordered != submarine_horizontal_speed) {
00956     submarine_horizontal_speed += (speed_ordered-submarine_horizontal_speed)/10.0;
00957     if (fabs(speed_ordered - submarine_horizontal_speed) < 0.1)
00958       submarine_horizontal_speed = speed_ordered;
00959   }
00960 
00961   /* assiette */
00962   delta_assiette = (ballast_ar_air - ballast_av_air)/200.0 +
00963     (barre_av_angle - barre_ar_angle)/5.0*submarine_horizontal_speed;
00964   assiette -= delta_assiette*UPDATE_DELAY/10000.0;
00965   if (assiette < -30.0)
00966     assiette = -30.0;
00967   if (assiette > 30.0)
00968     assiette = 30.0;
00969 
00970   /* If surfacing, diminish the 'assiette' */
00971   if ( depth <= 5.0 + SURFACE_DEPTH) {
00972     assiette *= depth/(depth+1.0);
00973   }
00974 
00975   /* update some dynamic parameters */
00976   /* resulting_weight > 0 ==> the sub goes deeper
00977      regleur : this is the qty of water */
00978   resulting_weight = weight - ballast_av_air - ballast_ar_air + regleur;
00979   submarine_vertical_speed = resulting_weight/300.0 + submarine_horizontal_speed*sin(DEG_TO_RAD(-assiette));
00980 
00981   /* if depth rudders are in the same direction */
00982   if (barre_ar_angle != 0.0 && barre_av_angle != 0.0) {
00983     if (fabs(barre_ar_angle)/barre_ar_angle == fabs(barre_av_angle)/barre_av_angle) {
00984       double a = (fabs(barre_ar_angle) > fabs(barre_av_angle)) ? barre_av_angle : barre_ar_angle;
00985       submarine_vertical_speed += a * submarine_horizontal_speed/30.0;
00986     }
00987   }
00988 
00989   /* position & depth */
00990   submarine_x += submarine_horizontal_speed * cos(DEG_TO_RAD(assiette)) * UPDATE_DELAY_SLOW/1000.0;
00991   depth += submarine_vertical_speed * UPDATE_DELAY_SLOW/1000.0;
00992   if (depth < SURFACE_DEPTH)
00993     depth = SURFACE_DEPTH;
00994   if (depth > MAX_DEPTH)
00995     depth = MAX_DEPTH;
00996 
00997   // show an alert if some parameters reach the limit
00998   if (depth >= MAX_DEPTH-20.0 || assiette == -30.0 || assiette == 30.0 || air == 0.0 || battery == 0.0)
00999     gnome_canvas_item_show(alert_submarine);
01000   else
01001     gnome_canvas_item_hide(alert_submarine);
01002 
01003   /* if the submarine dives, stop charging air tanks and batteries */
01004   if ( depth >= SURFACE_DEPTH+10.0 ) {
01005     if (air_charging) {
01006       air_charging = FALSE;
01007       gc_item_rotate_with_center(air_compressor_item, 0 , TRIGGER_CENTER_X, TRIGGER_CENTER_Y );
01008     }
01009     if (battery_charging) {
01010       battery_charging = FALSE;
01011       gc_item_rotate_with_center(battery_charger_item, 0 , TRIGGER_CENTER_X, TRIGGER_CENTER_Y );
01012     }
01013   }
01014 
01015   /* if the submarine is too close from right, put it at left */
01016   if ( submarine_x > WRAP_X )
01017     submarine_x = SUBMARINE_WIDTH/2.0;
01018 
01019   { /* displayes the submarine */
01020     double r[6],t1[6], t2[6];
01021     double y = depth + SUBMARINE_HEIGHT/2 + SURFACE_IN_BACKGROUND - SUBMARINE_WIDTH/2.0*sin(DEG_TO_RAD(assiette));
01022     art_affine_translate( t1 , (double)-SUBMARINE_WIDTH/2.0, (double)-SUBMARINE_HEIGHT );
01023     art_affine_rotate( r, -assiette );
01024     art_affine_multiply( r, t1, r);
01025     art_affine_translate( t2 , submarine_x, y );
01026     art_affine_multiply( r, r, t2);
01027     gnome_canvas_item_affine_absolute( submarine_item, r );
01028   }
01029 
01030   /* the frigate */
01031   {
01032     double x1, x2, y1, y2, x;
01033     x = - FRIGATE_SPEED * UPDATE_DELAY_SLOW/1000.0;
01034     gnome_canvas_item_get_bounds(frigate_item, &x1, &y1, &x2, &y2);
01035     gnome_canvas_item_move(frigate_item, - FRIGATE_SPEED * UPDATE_DELAY_SLOW/1000.0, 0.0);
01036     /* detects a collision between the frigate and the submarine */
01037     if (depth <= 30.0 && !submarine_destroyed)
01038       if ( (submarine_x - SUBMARINE_WIDTH <= x1 && submarine_x >= x2) ||
01039           (submarine_x - SUBMARINE_WIDTH >= x1 && submarine_x - SUBMARINE_WIDTH <= x2) ||
01040           (submarine_x >= x1 && submarine_x <= x2) ) {
01041         submarine_explosion();
01042       }
01043     /* wraps the destroyer if it reached the left side (and disappeared for a long time)*/
01044     if (x2 < -300.0)
01045       gc_item_absolute_move( frigate_item, gcomprisBoard->width, y1 );
01046   }
01047 
01048   /* whale detection */
01049   {
01050     double dist1, dist2, dist3;
01051     dist1 = hypot( submarine_x -SUBMARINE_WIDTH/2 -whale_x, depth+SURFACE_IN_BACKGROUND-whale_y);
01052     dist2 = hypot(submarine_x - SUBMARINE_WIDTH - whale_x, depth+SURFACE_IN_BACKGROUND-whale_y);
01053     dist3 = hypot(submarine_x - whale_x, depth+SURFACE_IN_BACKGROUND-whale_y);
01054     /* magnetic detection (dist1) or collision with the whale (dist2 & dist3) */
01055     if ( (dist1 < WHALE_DETECTION_RADIUS || dist2 < WHALE_DETECTION_RADIUS ||dist3 < WHALE_DETECTION_RADIUS)
01056         && !submarine_destroyed ) {
01057       gc_sound_play_ogg("sounds/crash.ogg", NULL);
01058       gnome_canvas_item_hide(whale);
01059       //gc_item_absolute_move(big_explosion, whale_x, whale_y);
01060       gnome_canvas_item_show(big_explosion);
01061       submarine_explosion();
01062     }
01063   }
01064 
01065   return TRUE;
01066 }
01067 /* =====================================================================
01068  * Periodically recalculate some submarine parameters, with a slow delay
01069  * =====================================================================*/
01070 static gboolean update_timeout_very_slow() {
01071   /* charging */
01072 
01073   if(board_paused)
01074     return FALSE;
01075 
01076   if (air_charging && depth < SURFACE_DEPTH+5.0) {
01077     air += 100.0*UPDATE_DELAY_VERY_SLOW/1000.0;
01078     setAir(air);
01079   }
01080 
01081   if (battery_charging && depth < SURFACE_DEPTH+5.0) {
01082     if (battery < 0.3*battery)
01083       battery += 300.0*UPDATE_DELAY_VERY_SLOW/1000.0;
01084     else
01085       if (battery < 0.6*battery)
01086        battery += 100.0*UPDATE_DELAY_VERY_SLOW/1000.0;
01087       else
01088        if (battery < 0.8*battery)
01089          battery += 50.0*UPDATE_DELAY_VERY_SLOW/1000.0;
01090        else
01091          battery += 20.0*UPDATE_DELAY_VERY_SLOW/1000.0;
01092   }
01093 
01094   /* battery */
01095   battery -= submarine_horizontal_speed*submarine_horizontal_speed/3.0*UPDATE_DELAY_VERY_SLOW/1000.0;
01096   if (battery < 0.0) {
01097     battery = 0.0;
01098     speed_ordered = 0;
01099     setSpeed(speed_ordered);
01100   }
01101 
01102   setBattery( battery );
01103 
01104   /* bubbling */
01105   if ( (ballast_av_purge_open && ballast_av_air > 0.0) ||
01106        ( ballast_av_chasse_open && ballast_av_air == MAX_BALLAST ) ) {
01107     gc_item_absolute_move( bubbling[0], submarine_x-30.0, depth-50.0);
01108     gnome_canvas_item_show( bubbling[0] );
01109   } else
01110     gnome_canvas_item_hide( bubbling[0] );
01111 
01112   if ( (ballast_ar_purge_open && ballast_ar_air > 0.0) ||
01113        ( ballast_ar_chasse_open && ballast_ar_air == MAX_BALLAST ) ) {
01114     gc_item_absolute_move( bubbling[2], submarine_x - SUBMARINE_WIDTH , depth-30.0);
01115     gnome_canvas_item_show( bubbling[2] );
01116   } else
01117     gnome_canvas_item_hide( bubbling[2] );
01118 
01119   if (regleur_purge_open && regleur < MAX_REGLEUR) {
01120     gc_item_absolute_move( bubbling[1], submarine_x - SUBMARINE_WIDTH/2 -30.0, depth-30.0);
01121     gnome_canvas_item_show( bubbling[1] );
01122   } else
01123     gnome_canvas_item_hide( bubbling[1] );
01124 
01125   return TRUE;
01126 }
01127 /* =====================================================================
01128  *
01129  * =====================================================================*/
01130 static void game_won() {
01131   gcomprisBoard->sublevel++;
01132   if(gcomprisBoard->sublevel > gcomprisBoard->number_of_sublevel) {
01133     /* Try the next level */
01134     gcomprisBoard->sublevel=1;
01135     gcomprisBoard->level++;
01136     if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
01137       gc_bonus_end_display(BOARD_FINISHED_TUXLOCO);
01138       return;
01139     }
01140   }
01141   submarine_next_level();
01142 }
01143 
01144 /* =====================================================================
01145  *
01146  * =====================================================================*/
01147 static gboolean quit_after_delay() {
01148   gc_board_stop();
01149   return FALSE;
01150 }
01151 static gboolean ok_timeout() {
01152   gc_bonus_display(gamewon, BONUS_SMILEY);
01153   g_timeout_add(TIME_CLICK_TO_BONUS*5, quit_after_delay, NULL);
01154   return FALSE;
01155 }
01156 
01157 static void ok() {
01158   // leave time to display the right answer
01159   g_timeout_add(TIME_CLICK_TO_BONUS, ok_timeout, NULL);
01160 }
01161 
01162 /* =====================================================================
01163  *            ballast_av_purge_event
01164  * =====================================================================*/
01165 static gint ballast_av_purge_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
01166   if(board_paused)
01167     return FALSE;
01168 
01169   switch (event->type)
01170     {
01171     case GDK_BUTTON_PRESS:
01172       ballast_av_purge_open = !ballast_av_purge_open;
01173       if (ballast_av_purge_open)
01174        gc_item_rotate(item, 90.0);
01175       else
01176        gc_item_rotate(item, 0.0);
01177       break;
01178 
01179     default:
01180       break;
01181     }
01182   return FALSE;
01183 }
01184 
01185 /* =====================================================================
01186  *            ballast_ar_purge_event
01187  * =====================================================================*/
01188 static gint ballast_ar_purge_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
01189   if(board_paused)
01190     return FALSE;
01191 
01192   switch (event->type)
01193     {
01194     case GDK_BUTTON_PRESS:
01195       ballast_ar_purge_open = !ballast_ar_purge_open;
01196       if (ballast_ar_purge_open)
01197        gc_item_rotate(item, 90.0);
01198       else
01199        gc_item_rotate(item, 0.0);
01200       break;
01201 
01202     default:
01203       break;
01204     }
01205   return FALSE;
01206 }
01207 /* =====================================================================
01208  *            regleur_purge_event
01209  * =====================================================================*/
01210 static gint regleur_purge_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
01211   if(board_paused)
01212     return FALSE;
01213 
01214   switch (event->type)
01215     {
01216     case GDK_BUTTON_PRESS:
01217       regleur_purge_open = !regleur_purge_open;
01218       if (regleur_purge_open)
01219        gc_item_rotate(item, 90.0);
01220       else
01221        gc_item_rotate(item, 0.0);
01222       break;
01223 
01224     default:
01225       break;
01226     }
01227   return FALSE;
01228 }
01229 /* =====================================================================
01230  *            ballast_ar_chasse_event
01231  * =====================================================================*/
01232 static gint ballast_ar_chasse_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
01233   if(board_paused)
01234     return FALSE;
01235 
01236   switch (event->type)
01237     {
01238     case GDK_BUTTON_PRESS:
01239       ballast_ar_chasse_open = !ballast_ar_chasse_open;
01240       if (ballast_ar_chasse_open)
01241        gc_item_rotate(item, 90.0);
01242       else
01243        gc_item_rotate(item, 0.0);
01244       break;
01245 
01246     default:
01247       break;
01248     }
01249   return FALSE;
01250 }
01251 /* =====================================================================
01252  *            ballast_av_chasse_event
01253  * =====================================================================*/
01254 static gint ballast_av_chasse_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
01255   if(board_paused)
01256     return FALSE;
01257 
01258   switch (event->type)
01259     {
01260     case GDK_BUTTON_PRESS:
01261       ballast_av_chasse_open = !ballast_av_chasse_open;
01262       if (ballast_av_chasse_open)
01263        gc_item_rotate(item, 90.0);
01264       else
01265        gc_item_rotate(item, 0.0);
01266       break;
01267 
01268     default:
01269       break;
01270     }
01271   return FALSE;
01272 }
01273 /* =====================================================================
01274  *
01275  * =====================================================================*/
01276 static gint regleur_chasse_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
01277   if(board_paused)
01278     return FALSE;
01279 
01280   switch (event->type)
01281     {
01282     case GDK_BUTTON_PRESS:
01283       regleur_chasse_open = !regleur_chasse_open;
01284       if (regleur_chasse_open)
01285        gc_item_rotate(item, 90.0);
01286       else
01287        gc_item_rotate(item, 0.0);
01288       break;
01289 
01290     default:
01291       break;
01292     }
01293   return FALSE;
01294 }
01295 
01296 /* =====================================================================
01297  *            barre_av_event
01298  * =====================================================================*/
01299 static gint barre_av_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
01300   int d = GPOINTER_TO_INT(data);
01301   if(board_paused)
01302     return FALSE;
01303 
01304   switch (event->type)
01305     {
01306     case GDK_BUTTON_PRESS:
01307       if (d == UP && barre_av_angle < RUDDER_MAX) {
01308         barre_av_angle += RUDDER_STEP;
01309         gc_item_rotate_with_center( barre_av_item, barre_av_angle,RUDDER_CENTER_X,RUDDER_CENTER_Y);
01310       }
01311       if (d == DOWN && barre_av_angle > -RUDDER_MAX) {
01312         barre_av_angle -= RUDDER_STEP;
01313         gc_item_rotate_with_center( barre_av_item, barre_av_angle,RUDDER_CENTER_X,RUDDER_CENTER_Y);
01314       }
01315       break;
01316 
01317     default:
01318       break;
01319     }
01320   return FALSE;
01321 }
01322 /* =====================================================================
01323  *            barre_ar_event
01324  * =====================================================================*/
01325 static gint barre_ar_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
01326   int d = GPOINTER_TO_INT(data);
01327 
01328   if(board_paused)
01329     return FALSE;
01330 
01331   switch (event->type)
01332     {
01333     case GDK_BUTTON_PRESS:
01334       if (d == UP && barre_ar_angle < RUDDER_MAX) {
01335         barre_ar_angle += RUDDER_STEP;
01336         gc_item_rotate_with_center( barre_ar_item, barre_ar_angle,RUDDER_CENTER_X,RUDDER_CENTER_Y);
01337       }
01338       if (d == DOWN && barre_ar_angle > -RUDDER_MAX) {
01339         barre_ar_angle -= RUDDER_STEP;
01340         gc_item_rotate_with_center( barre_ar_item, barre_ar_angle,RUDDER_CENTER_X,RUDDER_CENTER_Y);
01341       }
01342       break;
01343 
01344     default:
01345       break;
01346     }
01347   return FALSE;
01348 }
01349 /* =====================================================================
01350  *            engine_event
01351  * =====================================================================*/
01352 static gint engine_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
01353   int d = GPOINTER_TO_INT(data);
01354 
01355   if(board_paused)
01356     return FALSE;
01357 
01358   switch (event->type)
01359     {
01360     case GDK_BUTTON_PRESS:
01361       if (d == UP) {
01362         speed_ordered += SPEED_STEP;
01363       }
01364       if (d == DOWN) {
01365         speed_ordered -= SPEED_STEP;
01366       }
01367       if (speed_ordered > SPEED_MAX)
01368        speed_ordered = SPEED_MAX;
01369       if (speed_ordered < 0)
01370        speed_ordered = 0;
01371       setSpeed(speed_ordered);
01372       break;
01373 
01374     default:
01375       break;
01376     }
01377   return FALSE;
01378 }
01379 /* =====================================================================
01380  *            air_compressor_event
01381  * =====================================================================*/
01382 static gint air_compressor_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
01383   if(board_paused)
01384     return FALSE;
01385   switch (event->type)
01386     {
01387     case GDK_BUTTON_PRESS:
01388       if (air_charging)
01389        air_charging = FALSE;
01390       else
01391        air_charging = TRUE;
01392       gc_item_rotate_with_center(item, air_charging ? 180 : 0 , TRIGGER_CENTER_X, TRIGGER_CENTER_Y );
01393       break;
01394 
01395     default:
01396       break;
01397     }
01398   return FALSE;
01399 }
01400 /* =====================================================================
01401  *            battery_charger_event
01402  * =====================================================================*/
01403 static gint battery_charger_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
01404   if(board_paused)
01405     return FALSE;
01406   switch (event->type)
01407     {
01408     case GDK_BUTTON_PRESS:
01409       if (battery_charging)
01410        battery_charging = FALSE;
01411       else
01412        battery_charging = TRUE;
01413       gc_item_rotate_with_center(item, battery_charging ? 180 : 0 , TRIGGER_CENTER_X, TRIGGER_CENTER_Y );
01414       break;
01415 
01416     default:
01417       break;
01418     }
01419   return FALSE;
01420 }
01421 /* =====================================================================
01422  * Helper functions to update the graphical display
01423  * =====================================================================*/
01424 static void setSpeed(double value) {
01425   char s12[12];
01426   sprintf(s12,"%d",(int)value);
01427   gnome_canvas_item_set(speed_item_back, "text", s12, NULL);
01428   gnome_canvas_item_set(speed_item_front, "text", s12, NULL);
01429 }
01430 static void setBattery(double value) {
01431   char s12[12];
01432   sprintf(s12,"%d",(int)value);
01433   gnome_canvas_item_set(battery_item_back, "text", s12, NULL);
01434   gnome_canvas_item_set(battery_item_front, "text", s12, NULL);
01435 }
01436 static void setAir(double value) {
01437   char s12[12];
01438   sprintf(s12,"%d",(int)value);
01439   gnome_canvas_item_set(air_item_back, "text", s12, NULL);
01440   gnome_canvas_item_set(air_item_front, "text", s12, NULL);
01441 }
01442 static void setRegleur(double value) {
01443   char s12[12];
01444   sprintf(s12,"%d",(int)value);
01445   gnome_canvas_item_set(regleur_item_back, "text", s12, NULL);
01446   gnome_canvas_item_set(regleur_item_front, "text", s12, NULL);
01447   gnome_canvas_item_set(regleur_item_rect,
01448                      "y1", (double) schema_y + REGLEUR_Y2 +
01449                      ( value * (REGLEUR_Y1 - REGLEUR_Y2)) / MAX_REGLEUR,
01450                      NULL);
01451 }
01452 static void setBallastAV(double value) {
01453   char s12[12];
01454   sprintf(s12,"%d", MAX_BALLAST - (int)value);
01455   gnome_canvas_item_set(ballast_av_air_item_back, "text", s12, NULL);
01456   gnome_canvas_item_set(ballast_av_air_item_front, "text", s12, NULL);
01457   gnome_canvas_item_set(ballast_av_air_item_rect,
01458                      "y1", (double) schema_y + BALLAST_AV_AIR_Y2 +
01459                      ( (MAX_BALLAST - value) * (BALLAST_AV_AIR_Y1 - BALLAST_AV_AIR_Y2)) / MAX_BALLAST,
01460                      NULL);
01461 }
01462 static void setBallastAR(double value) {
01463   char s12[12];
01464   sprintf(s12,"%d", MAX_BALLAST - (int)value);
01465   gnome_canvas_item_set(ballast_ar_air_item_back, "text", s12, NULL);
01466   gnome_canvas_item_set(ballast_ar_air_item_front, "text", s12, NULL);
01467   gnome_canvas_item_set(ballast_ar_air_item_rect,
01468                      "y1", (double) schema_y + BALLAST_AR_AIR_Y2 +
01469                      ( (MAX_BALLAST - value) * (BALLAST_AR_AIR_Y1 - BALLAST_AR_AIR_Y2)) / MAX_BALLAST,
01470                      NULL);
01471 
01472 
01473 }
01474 /* =====================================================================
01475  *     Submarine explosion
01476  * =====================================================================*/
01477 static void submarine_explosion() {
01478   GdkPixbuf *pixmap = NULL;
01479   char *str = NULL;
01480 
01481   submarine_destroyed = TRUE;
01482   gamewon = FALSE;
01483   gc_sound_play_ogg("sounds/crash.ogg", NULL);
01484   /* make the submarine die */
01485   setSpeed(speed_ordered = submarine_horizontal_speed = 0.0);
01486   setBattery(battery = 0.0);
01487   setAir(air = 0.0);
01488   regleur = MAX_REGLEUR;
01489   weight = 2000.0;
01490 
01491   /* display the boken submarine */
01492   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "submarine-broken.png");
01493   pixmap = gc_pixmap_load(str);
01494   gnome_canvas_item_set(submarine_item,
01495                      "pixbuf", pixmap,
01496                      NULL);
01497   g_free(str);
01498   gdk_pixbuf_unref(pixmap);
01499 
01500   ok();
01501 }