/* gcompris - submarine.c
*
* Copyright (C) 2003 Pascal Georges
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
#include "gcompris/gcompris.h"
#define DEG_TO_RAD(x) M_PI*(x)/180.0
#define SOUNDLISTFILE PACKAGE
static GcomprisBoard *gcomprisBoard = NULL;
static gboolean board_paused = TRUE;
static void start_board (GcomprisBoard *agcomprisBoard);
static void pause_board (gboolean pause);
static void end_board (void);
static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
static void set_level (guint level);
static int gamewon;
static void ok(void);
static void game_won();
#define PURGE_AR 225
#define PURGE_AV 438
#define REGLEUR 330
#define CHASSE_BALLAST_AR_X 227
#define CHASSE_BALLAST_AR_Y 97
#define CHASSE_BALLAST_AV_X 440
#define CHASSE_BALLAST_AV_Y 98
#define CHASSE_REGLEUR_X 331
#define CHASSE_REGLEUR_Y 72
#define BARRE_AR_X 100
#define BARRE_AR_Y 50
#define BARRE_AV_X 530
#define BARRE_AV_Y 100
#define BALLAST_AV_AIR_TEXT_X 440
#define BALLAST_AV_AIR_TEXT_Y 50
#define BALLAST_AV_AIR_X1 393
#define BALLAST_AV_AIR_Y1 20
#define BALLAST_AV_AIR_X2 483
#define BALLAST_AV_AIR_Y2 80
#define BALLAST_AR_AIR_TEXT_X 220
#define BALLAST_AR_AIR_TEXT_Y 50
#define BALLAST_AR_AIR_X1 180
#define BALLAST_AR_AIR_Y1 20
#define BALLAST_AR_AIR_X2 270
#define BALLAST_AR_AIR_Y2 80
#define SURFACE_IN_BACKGROUND 40
#define SURFACE_DEPTH 20.0
#define IP_DEPTH 13.0
#define SECURITY_DEPTH 55.0
#define MAX_DEPTH 250.0
#define SPEED_MAX 10
#define SPEED_STEP 1
#define AIR_INITIAL 30000
#define BATTERY_INITIAL 3000
#define MAX_BALLAST 10000
#define MAX_REGLEUR 800
#define REGLEUR_INITIAL 500.0
#define WEIGHT_INITIAL -300.0
#define SUBMARINE_INITIAL_X 150
#define WRAP_X BOARDWIDTH
#define SUBMARINE_INITIAL_DEPTH SURFACE_DEPTH
#define RUDDER_STEP 5
#define RUDDER_MAX 15
#define RUDDER_CENTER_X 72
#define RUDDER_CENTER_Y 7
#define ENGINE_DOWN_X 42
#define ENGINE_DOWN_Y 104
#define ENGINE_UP_X 124
#define ENGINE_UP_Y 104
#define AIR_X 328
#define AIR_Y 109
#define BATTERY_X 285
#define BATTERY_Y 156
#define REGLEUR_TEXT_X 330
#define REGLEUR_TEXT_Y 37
#define REGLEUR_X1 325
#define REGLEUR_Y1 18
#define REGLEUR_X2 337
#define REGLEUR_Y2 56
#define AIR_TRIGGER_X 154
#define AIR_TRIGGER_Y 108
#define BATTERY_TRIGGER_X 184
#define BATTERY_TRIGGER_Y 108
#define TRIGGER_CENTER_X 7
#define TRIGGER_CENTER_Y 23
#define ALERT_SUBMARINE_X 719
#define ALERT_SUBMARINE_Y 368
#define UP 1
#define DOWN 0
#define FRIGATE_SPEED 5.0
#define WHALE_DETECTION_RADIUS 30.0
#define TREASURE_DETECTION_RADIUS 30.0
#define UPDATE_DELAY 200
#define UPDATE_DELAY_SLOW 300
#define UPDATE_DELAY_VERY_SLOW 1500
#define TEXT_COLOR_FRONT "red"
#define TEXT_COLOR_BACK "orange"
/* ================================================================ */
static GnomeCanvasGroup *boardRootItem = NULL;
static GnomeCanvasItem *sub_schema_image_item, *submarine_item,
*ballast_av_purge_item, *ballast_ar_purge_item, *regleur_purge_item;
static GnomeCanvasItem *ballast_av_chasse_item, *ballast_ar_chasse_item, *regleur_chasse_item;
gboolean ballast_av_purge_open, ballast_ar_purge_open, regleur_purge_open;
gboolean ballast_av_chasse_open, ballast_ar_chasse_open, regleur_chasse_open;
gboolean air_charging, battery_charging;
gboolean submarine_destroyed;
gboolean treasure_captured;
static GnomeCanvasItem *barre_av_item, *barre_ar_item,
*barre_av_up_item, *barre_av_down_item, *barre_ar_up_item, *barre_ar_down_item,
*engine_up_item, *engine_down_item,
*speed_item_back, *speed_item_front,
*air_item_back, *air_item_front,
*regleur_item_back, *regleur_item_front,
*regleur_item_rect,
*battery_item_back, *battery_item_front,
*ballast_av_air_item_back, *ballast_av_air_item_front,
*ballast_ar_air_item_back, *ballast_ar_air_item_front,
*ballast_av_air_item_rect, *ballast_ar_air_item_rect,
*air_compressor_item, *battery_charger_item, *alert_submarine,
*bubbling[3], *frigate_item, *big_explosion, *whale, *treasure, *top_gate_item;
/* submarine parameters */
static double barre_av_angle, barre_ar_angle, depth, weight, resulting_weight, submarine_x, air, battery, regleur;
static double submarine_horizontal_speed, submarine_vertical_speed, speed_ordered, assiette;
static double ballast_av_air, ballast_ar_air;
static double whale_x, whale_y;
static double treasure_x, treasure_y;
static guint schema_x, schema_y;
/* Defines the right gate */
static guint gate_top_y, gate_bottom_y, gate_top_current_y;
/* updated from submarine.png */
static guint submarine_width;
static guint submarine_height;
static GnomeCanvasItem *submarine_create_item(GnomeCanvasGroup *parent);
static void submarine_destroy_all_items(void);
static void submarine_next_level(void);
static gint ballast_av_purge_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static gint ballast_ar_purge_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static gint regleur_purge_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static gint ballast_ar_chasse_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static gint ballast_av_chasse_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static gint regleur_chasse_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static gint barre_av_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static gint barre_ar_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static gint engine_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static gint air_compressor_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static gint battery_charger_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static void setSpeed(double value);
static void setBattery(double value);
static void setAir(double value);
static void setRegleur(double value);
static void setBallastAV(double value);
static void setBallastAR(double value);
static void submarine_explosion();
static void open_door();
static gboolean update_timeout();
static gboolean update_timeout_slow();
static gboolean update_timeout_very_slow();
static guint timer_id, timer_slow_id, timer_very_slow_id;
/* Description of this plugin */
static BoardPlugin menu_bp =
{
NULL,
NULL,
"Submarine",
"Control the depth of a submarine",
"Pascal Georges pascal.georges1@free.fr>",
NULL,
NULL,
NULL,
NULL,
start_board,
pause_board,
end_board,
is_our_board,
NULL,
NULL,
set_level,
NULL,
NULL,
NULL,
NULL
};
/* =====================================================================
*
* =====================================================================*/
GET_BPLUGIN_INFO(submarine)
/* =====================================================================
* in : boolean TRUE = PAUSE : FALSE = CONTINUE
* =====================================================================*/
static void pause_board (gboolean pause)
{
if(gcomprisBoard==NULL)
return;
if(gamewon == TRUE && pause == FALSE) /* the game is won */
game_won();
board_paused = pause;
}
/* =====================================================================
*
* =====================================================================*/
static void start_board (GcomprisBoard *agcomprisBoard) {
if(agcomprisBoard!=NULL) {
gcomprisBoard=agcomprisBoard;
gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), "submarine/sub_bg.jpg");
gcomprisBoard->level=1;
gcomprisBoard->maxlevel=3;
gcomprisBoard->sublevel=1;
gc_bar_set(GC_BAR_LEVEL);
submarine_next_level();
gamewon = FALSE;
pause_board(FALSE);
}
}
/* =====================================================================
*
* =====================================================================*/
static void end_board () {
if(gcomprisBoard!=NULL){
pause_board(TRUE);
submarine_destroy_all_items();
}
gcomprisBoard = NULL;
}
/* =====================================================================
*
* =====================================================================*/
static void set_level (guint level) {
if(gcomprisBoard!=NULL)
{
gcomprisBoard->level=level;
gcomprisBoard->sublevel=1;
submarine_next_level();
}
}
/* =====================================================================
*
* =====================================================================*/
static gboolean is_our_board (GcomprisBoard *gcomprisBoard) {
if (gcomprisBoard) {
if(g_strcasecmp(gcomprisBoard->type, "submarine")==0) {
/* Set the plugin entry */
gcomprisBoard->plugin=&menu_bp;
return TRUE;
}
}
return FALSE;
}
/* =====================================================================
* set initial values for the next level
* =====================================================================*/
static void submarine_next_level()
{
gc_bar_set_level(gcomprisBoard);
ballast_av_purge_open = ballast_ar_purge_open = regleur_purge_open = FALSE;
ballast_av_chasse_open = ballast_ar_chasse_open = regleur_chasse_open = FALSE;
air_charging = battery_charging = FALSE;
barre_av_angle = barre_ar_angle = 0.0;
depth = SUBMARINE_INITIAL_DEPTH;
submarine_horizontal_speed = speed_ordered = 0.0;
submarine_x = SUBMARINE_INITIAL_X;
weight = WEIGHT_INITIAL;
regleur = REGLEUR_INITIAL;
air = AIR_INITIAL;
battery = BATTERY_INITIAL;
ballast_av_air = ballast_ar_air = MAX_BALLAST/10.0;
assiette = 0.0;
submarine_destroyed = FALSE;
treasure_captured = FALSE;
submarine_destroy_all_items();
gamewon = FALSE;
/* Try the next level */
submarine_create_item(gnome_canvas_root(gcomprisBoard->canvas));
}
/* =====================================================================
* Destroy all the items
* =====================================================================*/
static void submarine_destroy_all_items() {
/* kill pending timers */
if(timer_id)
g_source_remove(timer_id);
timer_id = 0;
if(timer_slow_id)
g_source_remove(timer_slow_id);
timer_slow_id = 0;
if(timer_very_slow_id)
g_source_remove(timer_very_slow_id);
timer_very_slow_id = 0;
if(boardRootItem!=NULL)
gtk_object_destroy (GTK_OBJECT(boardRootItem));
boardRootItem = NULL;
}
/* =====================================================================
*
* =====================================================================*/
static GnomeCanvasItem *submarine_create_item(GnomeCanvasGroup *parent) {
GdkPixbuf *pixmap = NULL;
char s12[12];
int i, w, h;
boardRootItem = GNOME_CANVAS_GROUP(
gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
gnome_canvas_group_get_type (),
"x", (double) 0,
"y", (double) 0,
NULL));
pixmap = gc_pixmap_load("submarine/submarine.png");
submarine_width = gdk_pixbuf_get_width(pixmap);
submarine_height = gdk_pixbuf_get_height(pixmap);
submarine_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) 0.0,//SUBMARINE_INITIAL_X,
"y", (double) 0.0,//SUBMARINE_INITIAL_DEPTH + SURFACE_IN_BACKGROUND - submarine_height,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gdk_pixbuf_unref(pixmap);
pixmap = gc_pixmap_load("submarine/sub_schema.png");
w = gdk_pixbuf_get_width(pixmap);
h = gdk_pixbuf_get_height(pixmap);
schema_x = (gcomprisBoard->width - w)/2 ;
schema_y = gcomprisBoard->height - h;
sub_schema_image_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + w/2.0,
"y", (double) schema_y + h/2.0,
"width", (double) w,
"height", (double) h,
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gdk_pixbuf_unref(pixmap);
pixmap = gc_pixmap_load("submarine/vanne.png");
w = gdk_pixbuf_get_width(pixmap);
h = gdk_pixbuf_get_height(pixmap);
ballast_ar_purge_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) PURGE_AR + schema_x,
"y", (double) schema_y + h/2.0 -1.0,
"width", (double) w,
"height", (double) h,
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gtk_signal_connect(GTK_OBJECT(ballast_ar_purge_item), "event", (GtkSignalFunc) ballast_ar_purge_event, NULL);
ballast_av_purge_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) PURGE_AV + schema_x,
"y", (double) schema_y + h/2.0 -1.0,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gtk_signal_connect(GTK_OBJECT(ballast_av_purge_item), "event", (GtkSignalFunc) ballast_av_purge_event, NULL);
regleur_purge_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) REGLEUR + schema_x,
"y", (double) schema_y + h/2.0 -2.0,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gtk_signal_connect(GTK_OBJECT(regleur_purge_item), "event", (GtkSignalFunc) regleur_purge_event, NULL);
ballast_av_chasse_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + CHASSE_BALLAST_AV_X,
"y", (double) schema_y + CHASSE_BALLAST_AV_Y,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gtk_signal_connect(GTK_OBJECT(ballast_av_chasse_item), "event", (GtkSignalFunc) ballast_av_chasse_event, NULL);
ballast_ar_chasse_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + CHASSE_BALLAST_AR_X,
"y", (double) schema_y + CHASSE_BALLAST_AR_Y,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gtk_signal_connect(GTK_OBJECT(ballast_ar_chasse_item), "event", (GtkSignalFunc) ballast_ar_chasse_event, NULL);
regleur_chasse_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + CHASSE_REGLEUR_X,
"y", (double) schema_y + CHASSE_REGLEUR_Y,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gtk_signal_connect(GTK_OBJECT(regleur_chasse_item), "event", (GtkSignalFunc) regleur_chasse_event, NULL);
gdk_pixbuf_unref(pixmap);
// DEPTH RUDDERS
pixmap = gc_pixmap_load("submarine/rudder.png");
barre_av_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + BARRE_AV_X,
"y", (double) schema_y + BARRE_AV_Y,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
barre_ar_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + BARRE_AR_X,
"y", (double) schema_y + BARRE_AR_Y,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gdk_pixbuf_unref(pixmap);
#define COMMAND_OFFSET 20.0
pixmap = gc_pixmap_load("submarine/up.png");
barre_av_up_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + BARRE_AV_X + COMMAND_OFFSET,
"y", (double) schema_y + BARRE_AV_Y - COMMAND_OFFSET,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
barre_ar_up_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + BARRE_AR_X + COMMAND_OFFSET,
"y", (double) schema_y + BARRE_AR_Y - COMMAND_OFFSET,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
engine_up_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + ENGINE_UP_X,
"y", (double) schema_y + ENGINE_UP_Y,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gdk_pixbuf_unref(pixmap);
pixmap = gc_pixmap_load("submarine/down.png");
barre_av_down_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + BARRE_AV_X + COMMAND_OFFSET,
"y", (double) schema_y + BARRE_AV_Y + COMMAND_OFFSET,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
barre_ar_down_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + BARRE_AR_X + COMMAND_OFFSET,
"y", (double) schema_y + BARRE_AR_Y + COMMAND_OFFSET,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
engine_down_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + ENGINE_DOWN_X,
"y", (double) schema_y + ENGINE_DOWN_Y,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gdk_pixbuf_unref(pixmap);
gtk_signal_connect(GTK_OBJECT(barre_av_up_item), "event",
(GtkSignalFunc) barre_av_event, GINT_TO_POINTER(UP));
gtk_signal_connect(GTK_OBJECT(barre_ar_up_item), "event",
(GtkSignalFunc) barre_ar_event, GINT_TO_POINTER(UP));
gtk_signal_connect(GTK_OBJECT(barre_av_down_item), "event",
(GtkSignalFunc) barre_av_event, GINT_TO_POINTER(DOWN));
gtk_signal_connect(GTK_OBJECT(barre_ar_down_item), "event",
(GtkSignalFunc) barre_ar_event, GINT_TO_POINTER(DOWN));
gtk_signal_connect(GTK_OBJECT(engine_up_item), "event",
(GtkSignalFunc) engine_event, GINT_TO_POINTER(UP));
gtk_signal_connect(GTK_OBJECT(engine_down_item), "event",
(GtkSignalFunc) engine_event, GINT_TO_POINTER(DOWN));
// displays the speed on the engine
sprintf(s12,"%d",(int)submarine_horizontal_speed);
speed_item_back = gnome_canvas_item_new (boardRootItem,
gnome_canvas_text_get_type (),
"text", s12,
"font", gc_skin_font_board_title_bold,
"x", (double) schema_x + (ENGINE_UP_X + ENGINE_DOWN_X)/2 +1,
"y", (double) schema_y + ENGINE_UP_Y + 1,
"anchor", GTK_ANCHOR_CENTER,
"fill_color", TEXT_COLOR_BACK,
NULL);
speed_item_front = gnome_canvas_item_new (boardRootItem,
gnome_canvas_text_get_type (),
"text", s12,
"font", gc_skin_font_board_title_bold,
"x", (double) schema_x + (ENGINE_UP_X + ENGINE_DOWN_X)/2,
"y", (double) schema_y + ENGINE_UP_Y,
"anchor", GTK_ANCHOR_CENTER,
"fill_color", TEXT_COLOR_FRONT,
NULL);
// displays the ballast_av_air value
ballast_av_air_item_rect = gnome_canvas_item_new (boardRootItem,
gnome_canvas_rect_get_type (),
"x1", (double) schema_x + BALLAST_AV_AIR_X1,
"y1", (double) schema_y + BALLAST_AV_AIR_Y2,
"x2", (double) schema_x + BALLAST_AV_AIR_X2,
"y2", (double) schema_y + BALLAST_AV_AIR_Y2,
"fill_color", "blue",
"width_pixels", 0,
NULL);
sprintf(s12,"%d",(int)ballast_av_air);
ballast_av_air_item_back = gnome_canvas_item_new (boardRootItem,
gnome_canvas_text_get_type (),
"text", s12,
"font", gc_skin_font_board_title_bold,
"x", (double) schema_x + BALLAST_AV_AIR_TEXT_X + 1,
"y", (double) schema_y + BALLAST_AV_AIR_TEXT_Y + 1,
"anchor", GTK_ANCHOR_CENTER,
"fill_color", TEXT_COLOR_BACK,
NULL);
ballast_av_air_item_front = gnome_canvas_item_new (boardRootItem,
gnome_canvas_text_get_type (),
"text", s12,
"font", gc_skin_font_board_title_bold,
"x", (double) schema_x + BALLAST_AV_AIR_TEXT_X,
"y", (double) schema_y + BALLAST_AV_AIR_TEXT_Y,
"anchor", GTK_ANCHOR_CENTER,
"fill_color", TEXT_COLOR_FRONT,
NULL);
setBallastAV(ballast_av_air);
// displays the ballast_ar_air value
ballast_ar_air_item_rect = gnome_canvas_item_new (boardRootItem,
gnome_canvas_rect_get_type (),
"x1", (double) schema_x + BALLAST_AR_AIR_X1,
"y1", (double) schema_y + BALLAST_AR_AIR_Y2,
"x2", (double) schema_x + BALLAST_AR_AIR_X2,
"y2", (double) schema_y + BALLAST_AR_AIR_Y2,
"fill_color", "blue",
"width_pixels", 0,
NULL);
sprintf(s12,"%d",(int)ballast_ar_air);
ballast_ar_air_item_back = gnome_canvas_item_new (boardRootItem,
gnome_canvas_text_get_type (),
"text", s12,
"font", gc_skin_font_board_title_bold,
"x", (double) schema_x + BALLAST_AR_AIR_TEXT_X + 1,
"y", (double) schema_y + BALLAST_AR_AIR_TEXT_Y + 1,
"anchor", GTK_ANCHOR_CENTER,
"fill_color", TEXT_COLOR_BACK,
NULL);
ballast_ar_air_item_front = gnome_canvas_item_new (boardRootItem,
gnome_canvas_text_get_type (),
"text", s12,
"font", gc_skin_font_board_title_bold,
"x", (double) schema_x + BALLAST_AR_AIR_TEXT_X,
"y", (double) schema_y + BALLAST_AR_AIR_TEXT_Y,
"anchor", GTK_ANCHOR_CENTER,
"fill_color", TEXT_COLOR_FRONT,
NULL);
setBallastAR(ballast_ar_air);
// displays the remaining air value
sprintf(s12,"%d", (int)air);
air_item_back = gnome_canvas_item_new (boardRootItem,
gnome_canvas_text_get_type (),
"text", s12,
"font", gc_skin_font_board_title_bold,
"x", (double) schema_x + AIR_X +1,
"y", (double) schema_y + AIR_Y + 1,
"anchor", GTK_ANCHOR_CENTER,
"fill_color", TEXT_COLOR_BACK,
NULL);
air_item_front = gnome_canvas_item_new (boardRootItem,
gnome_canvas_text_get_type (),
"text", s12,
"font", gc_skin_font_board_title_bold,
"x", (double) schema_x + AIR_X,
"y", (double) schema_y + AIR_Y,
"anchor", GTK_ANCHOR_CENTER,
"fill_color", TEXT_COLOR_FRONT,
NULL);
// displays the remaining battery value
sprintf(s12,"%d", (int)battery);
battery_item_back = gnome_canvas_item_new (boardRootItem,
gnome_canvas_text_get_type (),
"text", s12,
"font", gc_skin_font_board_title_bold,
"x", (double) schema_x + BATTERY_X +1,
"y", (double) schema_y + BATTERY_Y + 1,
"anchor", GTK_ANCHOR_CENTER,
"fill_color", TEXT_COLOR_BACK,
NULL);
battery_item_front = gnome_canvas_item_new (boardRootItem,
gnome_canvas_text_get_type (),
"text", s12,
"font", gc_skin_font_board_title_bold,
"x", (double) schema_x + BATTERY_X,
"y", (double) schema_y + BATTERY_Y,
"anchor", GTK_ANCHOR_CENTER,
"fill_color", TEXT_COLOR_FRONT,
NULL);
// displays the remaining regleur value
regleur_item_rect = gnome_canvas_item_new (boardRootItem,
gnome_canvas_rect_get_type (),
"x1", (double) schema_x + REGLEUR_X1,
"y1", (double) schema_y + REGLEUR_Y2,
"x2", (double) schema_x + REGLEUR_X2,
"y2", (double) schema_y + REGLEUR_Y2,
"fill_color", "blue",
"width_pixels", 0,
NULL);
sprintf(s12,"%d", (int)regleur);
regleur_item_back = gnome_canvas_item_new (boardRootItem,
gnome_canvas_text_get_type (),
"text", s12,
"font", gc_skin_font_board_title_bold,
"x", (double) schema_x + REGLEUR_TEXT_X +1,
"y", (double) schema_y + REGLEUR_TEXT_Y + 1,
"anchor", GTK_ANCHOR_CENTER,
"fill_color", TEXT_COLOR_BACK,
NULL);
regleur_item_front = gnome_canvas_item_new (boardRootItem,
gnome_canvas_text_get_type (),
"text", s12,
"font", gc_skin_font_board_title_bold,
"x", (double) schema_x + REGLEUR_TEXT_X,
"y", (double) schema_y + REGLEUR_TEXT_Y,
"anchor", GTK_ANCHOR_CENTER,
"fill_color", TEXT_COLOR_FRONT,
NULL);
setRegleur(regleur);
// displays an alert when some parameters are bad
pixmap = gc_pixmap_load("submarine/alert_submarine.png");
alert_submarine = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) ALERT_SUBMARINE_X,
"y", (double) ALERT_SUBMARINE_Y,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gdk_pixbuf_unref(pixmap);
gnome_canvas_item_hide(alert_submarine);
// when the submarine makes some bubbles ...
pixmap = gc_pixmap_load("submarine/bubbling.png");
for (i=0; i<3; i++) {
bubbling[i] = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) 0.0,
"y", (double) 0.0,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gnome_canvas_item_hide(bubbling[i]);
}
gdk_pixbuf_unref(pixmap);
// whale item
pixmap = gc_pixmap_load("submarine/whale.png");
whale_x = g_random_int_range((int)(gcomprisBoard->width/4),
(int)(gcomprisBoard->width/2));
whale_y = g_random_int_range((int)(SURFACE_IN_BACKGROUND + gdk_pixbuf_get_height(pixmap)*2),
(int)MAX_DEPTH);
whale = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) whale_x,
"y", (double) whale_y,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gdk_pixbuf_unref(pixmap);
// big explosion item (only for the whale)
pixmap = gc_pixmap_load("submarine/whale_hit.png");
big_explosion = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) whale_x,
"y", (double) whale_y,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gnome_canvas_item_hide(big_explosion);
gdk_pixbuf_unref(pixmap);
// treasure item
pixmap = gc_pixmap_load("gcompris/misc/crown.png");
treasure_x = (gcomprisBoard->width*3)/4;
treasure_y = MAX_DEPTH;
treasure = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) treasure_x,
"y", (double) treasure_y,
"width", (double) gdk_pixbuf_get_width(pixmap)/2,
"height", (double) gdk_pixbuf_get_height(pixmap)/2,
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gdk_pixbuf_unref(pixmap);
// the triggers for air compressor and battery charger
pixmap = gc_pixmap_load("submarine/manette.png");
air_compressor_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + AIR_TRIGGER_X,
"y", (double) schema_y + AIR_TRIGGER_Y,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
battery_charger_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) schema_x + BATTERY_TRIGGER_X,
"y", (double) schema_y + BATTERY_TRIGGER_Y,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_CENTER,
NULL);
gdk_pixbuf_unref(pixmap);
// the antisubmarine warfare frigate
pixmap = gc_pixmap_load("submarine/asw_frigate.png");
frigate_item = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type (),
"pixbuf", pixmap,
"x", (double) 700.0,
"y", (double) 2.0,
"width", (double) gdk_pixbuf_get_width(pixmap),
"height", (double) gdk_pixbuf_get_height(pixmap),
"width_set", TRUE,
"height_set", TRUE,
//"anchor", GTK_ANCHOR_CENTER,
NULL);
gdk_pixbuf_unref(pixmap);
gtk_signal_connect(GTK_OBJECT(air_compressor_item), "event", (GtkSignalFunc) air_compressor_event, NULL);
gtk_signal_connect(GTK_OBJECT(battery_charger_item), "event", (GtkSignalFunc) battery_charger_event, NULL);
/*
* Set the right wall
* ------------------
*/
switch(gcomprisBoard->level)
{
case 1:
gate_top_y = 80;
gate_bottom_y = schema_y - 100;
break;
case 2:
gate_top_y = 100;
gate_bottom_y = schema_y - 120;
break;
default:
gate_top_y = 120;
gate_bottom_y = schema_y - 120;
break;
}
/* At startup, the gate is closed */
gate_top_current_y = gate_bottom_y;
top_gate_item = gnome_canvas_item_new \
(boardRootItem,
gnome_canvas_rect_get_type (),
"x1", (double) BOARDWIDTH - 25,
"y1", (double) 40,
"x2", (double) BOARDWIDTH + 2,
"y2", (double) gate_top_current_y,
"fill_color_rgba", 0x989677FF,
"outline_color", "black",
"width_pixels", 2,
NULL);
gnome_canvas_item_new (boardRootItem,
gnome_canvas_rect_get_type (),
"x1", (double) BOARDWIDTH - 25,
"y1", (double) gate_bottom_y,
"x2", (double) BOARDWIDTH + 2,
"y2", (double) schema_y,
"fill_color_rgba", 0x989677FF,
"outline_color", "black",
"width_pixels", 2,
NULL);
timer_id = g_timeout_add(UPDATE_DELAY, update_timeout, NULL);
timer_slow_id = g_timeout_add(UPDATE_DELAY_SLOW, update_timeout_slow, NULL);
timer_very_slow_id = g_timeout_add(UPDATE_DELAY_VERY_SLOW, update_timeout_very_slow, NULL);
return NULL;
}
/* =====================================================================
* Periodically recalculate the submarine parameters
* =====================================================================*/
static gboolean update_timeout() {
double delta_air;
gboolean regleur_dirty = FALSE;
gboolean air_dirty = FALSE;
if(!boardRootItem)
return FALSE;
if(board_paused)
return TRUE;
/* air in ballasts */
if (ballast_av_purge_open) {
ballast_av_air -= UPDATE_DELAY/1000.0 *500.0; // 500 liters go out per second
if (ballast_av_air < 0.0)
ballast_av_air = 0.0;
setBallastAV(ballast_av_air);
}
if (ballast_ar_purge_open) {
ballast_ar_air -= UPDATE_DELAY/1000.0 *500.0;
if (ballast_ar_air < 0.0)
ballast_ar_air = 0.0;
setBallastAR(ballast_ar_air);
}
if (ballast_av_chasse_open && air>0.0) {
delta_air = UPDATE_DELAY/1000.0 *500.0; // 200 liters are injected each second
ballast_av_air += delta_air;
air -= delta_air;
if (air<0.0)
air = 0.0;
if (ballast_av_air > MAX_BALLAST)
ballast_av_air = MAX_BALLAST;
air_dirty = TRUE;
setBallastAV(ballast_av_air);
}
if (ballast_ar_chasse_open && air>0.0) {
delta_air = UPDATE_DELAY/1000.0 *500.0;
ballast_ar_air += delta_air;
air -= delta_air;
if (air<0.0)
air = 0.0;
if (ballast_ar_air > MAX_BALLAST)
ballast_ar_air = MAX_BALLAST;
air_dirty = TRUE;
setBallastAR(ballast_ar_air);
}
if (air_dirty)
setAir(air);
/* air in "regleur" (small ballast to finely balance the submarine) */
if (regleur_purge_open) {
regleur += UPDATE_DELAY/1000.0 *50.0; // 100 liters enter per second
if (regleur > MAX_REGLEUR)
regleur = MAX_REGLEUR;
regleur_dirty = TRUE;
}
if (regleur_chasse_open && air>0.0 && regleur > 0.0) {
delta_air = UPDATE_DELAY/1000.0 *50.0; // 50 liters are injected each second
regleur -= delta_air;
air -= delta_air;
if (air<0.0)
air = 0.0;
if (regleur < 0.0)
regleur = 0.0;
regleur_dirty = TRUE;
setAir(air);
}
if (regleur_dirty)
setRegleur(regleur);
return TRUE;
}
/* =====================================================================
* Periodically recalculate some submarine parameters, with a larger delay
* =====================================================================*/
static gboolean update_timeout_slow() {
double delta_assiette;
if(!boardRootItem)
return FALSE;
if(board_paused)
return TRUE;
/* speed : don't reach instantly the ordered speed */
if (speed_ordered != submarine_horizontal_speed) {
submarine_horizontal_speed += (speed_ordered-submarine_horizontal_speed)/10.0;
if (fabs(speed_ordered - submarine_horizontal_speed) < 0.1)
submarine_horizontal_speed = speed_ordered;
}
/* assiette */
delta_assiette = (ballast_ar_air - ballast_av_air)/200.0 +
(barre_av_angle - barre_ar_angle)/5.0*submarine_horizontal_speed;
assiette -= delta_assiette*UPDATE_DELAY/10000.0;
if (assiette < -30.0)
assiette = -30.0;
if (assiette > 30.0)
assiette = 30.0;
/* If surfacing, diminish the 'assiette' */
if ( depth <= 5.0 + SURFACE_DEPTH) {
assiette *= depth/(depth+1.0);
}
/* update some dynamic parameters */
/* resulting_weight > 0 ==> the sub goes deeper
regleur : this is the qty of water */
resulting_weight = weight - ballast_av_air - ballast_ar_air + regleur;
submarine_vertical_speed = resulting_weight/300.0 + submarine_horizontal_speed*sin(DEG_TO_RAD(-assiette));
/* if depth rudders are in the same direction */
if (barre_ar_angle != 0.0 && barre_av_angle != 0.0) {
if (fabs(barre_ar_angle)/barre_ar_angle == fabs(barre_av_angle)/barre_av_angle) {
double a = (fabs(barre_ar_angle) > fabs(barre_av_angle)) ? barre_av_angle : barre_ar_angle;
submarine_vertical_speed += a * submarine_horizontal_speed/30.0;
}
}
/* position & depth */
submarine_x += submarine_horizontal_speed * cos(DEG_TO_RAD(assiette)) * UPDATE_DELAY_SLOW/1000.0;
depth += submarine_vertical_speed * UPDATE_DELAY_SLOW/1000.0;
if (depth < SURFACE_DEPTH)
depth = SURFACE_DEPTH;
if (depth > MAX_DEPTH)
depth = MAX_DEPTH;
// show an alert if some parameters reach the limit
if (depth >= MAX_DEPTH-20.0 || assiette == -30.0 || assiette == 30.0 || air == 0.0 || battery == 0.0)
gnome_canvas_item_show(alert_submarine);
else
gnome_canvas_item_hide(alert_submarine);
/* if the submarine dives, stop charging air tanks and batteries */
if ( depth >= SURFACE_DEPTH+10.0 ) {
if (air_charging) {
air_charging = FALSE;
gc_item_rotate_with_center(air_compressor_item, 0 , TRIGGER_CENTER_X, TRIGGER_CENTER_Y );
}
if (battery_charging) {
battery_charging = FALSE;
gc_item_rotate_with_center(battery_charger_item, 0 , TRIGGER_CENTER_X, TRIGGER_CENTER_Y );
}
}
/* if the submarine is too close from right, put it on the left */
if ( submarine_x > WRAP_X )
{
/* Check its within the gate range */
double x1,x2,y1,y2;
gnome_canvas_item_get_bounds (submarine_item, &x1, &y1, &x2, &y2);
if(y1gate_bottom_y)
{
/* It's a crash */
submarine_explosion();
}
else
{
gamewon = TRUE;
/* Let the user play indefinitly at level 3 */
if(gcomprisBoard->level<3)
gc_bonus_display(gamewon, GC_BONUS_SMILEY);
else
submarine_x = submarine_width/2.0;
}
}
/* Open the door */
if(treasure_captured && gate_top_current_y > gate_top_y)
open_door();
{ /* display the submarine */
double r[6],t1[6], t2[6];
double y = depth + submarine_height/2 + SURFACE_IN_BACKGROUND - submarine_width/2.0*sin(DEG_TO_RAD(assiette));
art_affine_translate( t1 , (double)(submarine_width/2.0)*-1, (double)(submarine_height)*-1);
art_affine_rotate( r, -assiette );
art_affine_multiply( r, t1, r);
art_affine_translate( t2 , submarine_x, y );
art_affine_multiply( r, r, t2);
gnome_canvas_item_affine_absolute( submarine_item, r );
}
/* the frigate */
{
double x1, x2, y1, y2, x;
x = - FRIGATE_SPEED * UPDATE_DELAY_SLOW/1000.0;
gnome_canvas_item_get_bounds(frigate_item, &x1, &y1, &x2, &y2);
gnome_canvas_item_move(frigate_item, - FRIGATE_SPEED * UPDATE_DELAY_SLOW/1000.0, 0.0);
/* detects a collision between the frigate and the submarine */
if (depth <= 30.0 && !submarine_destroyed)
if ( (submarine_x - submarine_width <= x1 && submarine_x >= x2) ||
(submarine_x - submarine_width >= x1 && submarine_x - submarine_width <= x2) ||
(submarine_x >= x1 && submarine_x <= x2) ) {
submarine_explosion();
}
/* wraps the destroyer if it reached the left side (and disappeared for a long time)*/
if (x2 < -300.0)
gc_item_absolute_move( frigate_item, gcomprisBoard->width, y1 );
}
/* whale detection */
{
double dist1, dist2, dist3;
dist1 = hypot( submarine_x -submarine_width/2 -whale_x, depth+SURFACE_IN_BACKGROUND-whale_y);
dist2 = hypot(submarine_x - submarine_width - whale_x, depth+SURFACE_IN_BACKGROUND-whale_y);
dist3 = hypot(submarine_x - whale_x, depth+SURFACE_IN_BACKGROUND-whale_y);
/* magnetic detection (dist1) or collision with the whale (dist2 & dist3) */
if ( (dist1 < WHALE_DETECTION_RADIUS || dist2 < WHALE_DETECTION_RADIUS ||dist3 < WHALE_DETECTION_RADIUS)
&& !submarine_destroyed ) {
gnome_canvas_item_hide(whale);
gnome_canvas_item_show(big_explosion);
submarine_explosion();
}
}
/* treasure detection */
{
double dist1, dist2, dist3;
dist1 = hypot( submarine_x -submarine_width/2 -treasure_x, depth+SURFACE_IN_BACKGROUND-treasure_y);
dist2 = hypot(submarine_x - submarine_width - treasure_x, depth+SURFACE_IN_BACKGROUND-treasure_y);
dist3 = hypot(submarine_x - treasure_x, depth+SURFACE_IN_BACKGROUND-treasure_y);
/* magnetic detection (dist1) or collision with the treasure (dist2 & dist3) */
if ( (dist1 < TREASURE_DETECTION_RADIUS
|| dist2 < TREASURE_DETECTION_RADIUS
|| dist3 < TREASURE_DETECTION_RADIUS)
&& !treasure_captured ) {
gc_sound_play_ogg("sounds/tuxok.wav", NULL);
gnome_canvas_item_hide(treasure);
treasure_captured = TRUE;
open_door();
}
}
return TRUE;
}
/* =====================================================================
* Periodically recalculate some submarine parameters, with a slow delay
* =====================================================================*/
static gboolean update_timeout_very_slow() {
/* charging */
if(!boardRootItem)
return FALSE;
if(board_paused)
return TRUE;
if (air_charging && depth < SURFACE_DEPTH+5.0) {
air += 100.0*UPDATE_DELAY_VERY_SLOW/1000.0;
setAir(air);
}
if (battery_charging && depth < SURFACE_DEPTH+5.0) {
if (battery < 0.3*battery)
battery += 500.0*UPDATE_DELAY_VERY_SLOW/1000.0;
else
if (battery < 0.6*battery)
battery += 200.0*UPDATE_DELAY_VERY_SLOW/1000.0;
else
if (battery < 0.8*battery)
battery += 100.0*UPDATE_DELAY_VERY_SLOW/1000.0;
else
battery += 50.0*UPDATE_DELAY_VERY_SLOW/1000.0;
}
/* battery */
battery -= submarine_horizontal_speed*submarine_horizontal_speed/3.0*UPDATE_DELAY_VERY_SLOW/1000.0;
if (battery < 0.0) {
battery = 0.0;
speed_ordered = 0;
setSpeed(speed_ordered);
}
setBattery( battery );
/* bubbling */
if ( (ballast_av_purge_open && ballast_av_air > 0.0) ||
( ballast_av_chasse_open && ballast_av_air == MAX_BALLAST ) ) {
gc_item_absolute_move( bubbling[0], submarine_x-30.0, depth-50.0);
gnome_canvas_item_show( bubbling[0] );
gc_sound_play_ogg ("sounds/bubble.wav", NULL);
} else
gnome_canvas_item_hide( bubbling[0] );
if ( (ballast_ar_purge_open && ballast_ar_air > 0.0) ||
( ballast_ar_chasse_open && ballast_ar_air == MAX_BALLAST ) ) {
gc_item_absolute_move( bubbling[2], submarine_x - submarine_width , depth-30.0);
gc_sound_play_ogg ("sounds/bubble.wav", NULL);
gnome_canvas_item_show( bubbling[2] );
} else
gnome_canvas_item_hide( bubbling[2] );
if (regleur_purge_open && regleur < MAX_REGLEUR) {
gc_item_absolute_move( bubbling[1], submarine_x - submarine_width/2 -30.0, depth-30.0);
gc_sound_play_ogg ("sounds/bubble.wav", NULL);
gnome_canvas_item_show( bubbling[1] );
} else
gnome_canvas_item_hide( bubbling[1] );
return TRUE;
}
/* =====================================================================
*
* =====================================================================*/
static void game_won() {
gcomprisBoard->sublevel++;
if(gcomprisBoard->sublevel > gcomprisBoard->number_of_sublevel) {
/* Try the next level */
gcomprisBoard->sublevel=1;
gcomprisBoard->level++;
if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
gc_bonus_end_display(GC_BOARD_FINISHED_RANDOM);
return;
}
}
submarine_next_level();
}
/* =====================================================================
*
* =====================================================================*/
static gboolean quit_after_delay() {
if(!boardRootItem)
return FALSE;
if(board_paused)
return TRUE;
submarine_next_level();
gc_bar_hide(FALSE);
return FALSE;
}
static gboolean ok_timeout() {
gc_bonus_display(gamewon, GC_BONUS_SMILEY);
g_timeout_add(TIME_CLICK_TO_BONUS*5, quit_after_delay, NULL);
return FALSE;
}
static void ok() {
gc_bar_hide(TRUE);
// leave time to display the right answer
g_timeout_add(TIME_CLICK_TO_BONUS, ok_timeout, NULL);
}
/* =====================================================================
* ballast_av_purge_event
* =====================================================================*/
static gint ballast_av_purge_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
if(board_paused || !boardRootItem)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
ballast_av_purge_open = !ballast_av_purge_open;
if (ballast_av_purge_open)
gc_item_rotate(item, 90.0);
else
gc_item_rotate(item, 0.0);
break;
default:
break;
}
return FALSE;
}
/* =====================================================================
* ballast_ar_purge_event
* =====================================================================*/
static gint ballast_ar_purge_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
if(board_paused || !boardRootItem)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
ballast_ar_purge_open = !ballast_ar_purge_open;
if (ballast_ar_purge_open)
gc_item_rotate(item, 90.0);
else
gc_item_rotate(item, 0.0);
break;
default:
break;
}
return FALSE;
}
/* =====================================================================
* regleur_purge_event
* =====================================================================*/
static gint regleur_purge_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
if(board_paused || !boardRootItem)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
regleur_purge_open = !regleur_purge_open;
if (regleur_purge_open)
gc_item_rotate(item, 90.0);
else
gc_item_rotate(item, 0.0);
break;
default:
break;
}
return FALSE;
}
/* =====================================================================
* ballast_ar_chasse_event
* =====================================================================*/
static gint ballast_ar_chasse_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
if(board_paused || !boardRootItem)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
ballast_ar_chasse_open = !ballast_ar_chasse_open;
if (ballast_ar_chasse_open)
gc_item_rotate(item, 90.0);
else
gc_item_rotate(item, 0.0);
break;
default:
break;
}
return FALSE;
}
/* =====================================================================
* ballast_av_chasse_event
* =====================================================================*/
static gint ballast_av_chasse_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
if(board_paused || !boardRootItem)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
ballast_av_chasse_open = !ballast_av_chasse_open;
if (ballast_av_chasse_open)
gc_item_rotate(item, 90.0);
else
gc_item_rotate(item, 0.0);
break;
default:
break;
}
return FALSE;
}
/* =====================================================================
*
* =====================================================================*/
static gint regleur_chasse_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
if(board_paused || !boardRootItem)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
regleur_chasse_open = !regleur_chasse_open;
if (regleur_chasse_open)
gc_item_rotate(item, 90.0);
else
gc_item_rotate(item, 0.0);
break;
default:
break;
}
return FALSE;
}
/* =====================================================================
* barre_av_event
* =====================================================================*/
static gint barre_av_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
int d = GPOINTER_TO_INT(data);
if(board_paused || !boardRootItem)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
if (d == UP && barre_av_angle < RUDDER_MAX) {
barre_av_angle += RUDDER_STEP;
gc_item_rotate_with_center( barre_av_item, barre_av_angle,RUDDER_CENTER_X,RUDDER_CENTER_Y);
}
if (d == DOWN && barre_av_angle > -RUDDER_MAX) {
barre_av_angle -= RUDDER_STEP;
gc_item_rotate_with_center( barre_av_item, barre_av_angle,RUDDER_CENTER_X,RUDDER_CENTER_Y);
}
break;
default:
break;
}
return FALSE;
}
/* =====================================================================
* barre_ar_event
* =====================================================================*/
static gint barre_ar_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
int d = GPOINTER_TO_INT(data);
if(board_paused || !boardRootItem)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
if (d == UP && barre_ar_angle < RUDDER_MAX) {
barre_ar_angle += RUDDER_STEP;
gc_item_rotate_with_center( barre_ar_item, barre_ar_angle,RUDDER_CENTER_X,RUDDER_CENTER_Y);
}
if (d == DOWN && barre_ar_angle > -RUDDER_MAX) {
barre_ar_angle -= RUDDER_STEP;
gc_item_rotate_with_center( barre_ar_item, barre_ar_angle,RUDDER_CENTER_X,RUDDER_CENTER_Y);
}
break;
default:
break;
}
return FALSE;
}
/* =====================================================================
* engine_event
* =====================================================================*/
static gint engine_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
int d = GPOINTER_TO_INT(data);
if(board_paused || !boardRootItem)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
if (d == UP) {
speed_ordered += SPEED_STEP;
}
if (d == DOWN) {
speed_ordered -= SPEED_STEP;
}
if (speed_ordered > SPEED_MAX)
speed_ordered = SPEED_MAX;
if (speed_ordered < 0)
speed_ordered = 0;
setSpeed(speed_ordered);
break;
default:
break;
}
return FALSE;
}
/* =====================================================================
* air_compressor_event
* =====================================================================*/
static gint air_compressor_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
if(board_paused || !boardRootItem)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
if (air_charging)
air_charging = FALSE;
else
air_charging = TRUE;
gc_item_rotate_with_center(item, air_charging ? 180 : 0 , TRIGGER_CENTER_X, TRIGGER_CENTER_Y );
break;
default:
break;
}
return FALSE;
}
/* =====================================================================
* battery_charger_event
* =====================================================================*/
static gint battery_charger_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
if(board_paused || !boardRootItem)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
if (battery_charging)
battery_charging = FALSE;
else
battery_charging = TRUE;
gc_item_rotate_with_center(item, battery_charging ? 180 : 0 , TRIGGER_CENTER_X, TRIGGER_CENTER_Y );
break;
default:
break;
}
return FALSE;
}
/* =====================================================================
* Helper functions to update the graphical display
* =====================================================================*/
static void setSpeed(double value) {
char s12[12];
sprintf(s12,"%d",(int)value);
gnome_canvas_item_set(speed_item_back, "text", s12, NULL);
gnome_canvas_item_set(speed_item_front, "text", s12, NULL);
}
static void setBattery(double value) {
char s12[12];
sprintf(s12,"%d",(int)value);
gnome_canvas_item_set(battery_item_back, "text", s12, NULL);
gnome_canvas_item_set(battery_item_front, "text", s12, NULL);
}
static void setAir(double value) {
char s12[12];
sprintf(s12,"%d",(int)value);
gnome_canvas_item_set(air_item_back, "text", s12, NULL);
gnome_canvas_item_set(air_item_front, "text", s12, NULL);
}
static void setRegleur(double value) {
char s12[12];
sprintf(s12,"%d",(int)value);
gnome_canvas_item_set(regleur_item_back, "text", s12, NULL);
gnome_canvas_item_set(regleur_item_front, "text", s12, NULL);
gnome_canvas_item_set(regleur_item_rect,
"y1", (double) schema_y + REGLEUR_Y2 +
( value * (REGLEUR_Y1 - REGLEUR_Y2)) / MAX_REGLEUR,
NULL);
}
static void setBallastAV(double value) {
char s12[12];
sprintf(s12,"%d", MAX_BALLAST - (int)value);
gnome_canvas_item_set(ballast_av_air_item_back, "text", s12, NULL);
gnome_canvas_item_set(ballast_av_air_item_front, "text", s12, NULL);
gnome_canvas_item_set(ballast_av_air_item_rect,
"y1", (double) schema_y + BALLAST_AV_AIR_Y2 +
( (MAX_BALLAST - value) * (BALLAST_AV_AIR_Y1 - BALLAST_AV_AIR_Y2)) / MAX_BALLAST,
NULL);
}
static void setBallastAR(double value) {
char s12[12];
sprintf(s12,"%d", MAX_BALLAST - (int)value);
gnome_canvas_item_set(ballast_ar_air_item_back, "text", s12, NULL);
gnome_canvas_item_set(ballast_ar_air_item_front, "text", s12, NULL);
gnome_canvas_item_set(ballast_ar_air_item_rect,
"y1", (double) schema_y + BALLAST_AR_AIR_Y2 +
( (MAX_BALLAST - value) * (BALLAST_AR_AIR_Y1 - BALLAST_AR_AIR_Y2)) / MAX_BALLAST,
NULL);
}
/* =====================================================================
* Submarine explosion
* =====================================================================*/
static void open_door()
{
gnome_canvas_item_set(top_gate_item,
"y2", (double)gate_top_current_y--,
NULL);
}
/* =====================================================================
* Submarine explosion
* =====================================================================*/
static void submarine_explosion() {
GdkPixbuf *pixmap = NULL;
if (submarine_destroyed)
return;
submarine_destroyed = TRUE;
gamewon = FALSE;
gc_sound_play_ogg("sounds/crash.wav", NULL);
/* make the submarine die */
setSpeed(speed_ordered = submarine_horizontal_speed = 0.0);
setBattery(battery = 0.0);
setAir(air = 0.0);
regleur = MAX_REGLEUR;
weight = 2000.0;
/* display the boken submarine */
pixmap = gc_pixmap_load("submarine/submarine-broken.png");
gnome_canvas_item_set(submarine_item,
"pixbuf", pixmap,
NULL);
gdk_pixbuf_unref(pixmap);
ok();
}