Back to index

gcompris  8.2.2
smallnumbers.c
Go to the documentation of this file.
00001 /* gcompris - smallnumbers.c
00002  *
00003  * Time-stamp: <2006/08/21 23:36:29 bruno>
00004  *
00005  * Copyright (C) 2000 Bruno Coudoin
00006  * 
00007  *   This program is free software; you can redistribute it and/or modify
00008  *   it under the terms of the GNU General Public License as published by
00009  *   the Free Software Foundation; either version 2 of the License, or
00010  *   (at your option) any later version.
00011  *
00012  *   This program is distributed in the hope that it will be useful,
00013  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *   GNU General Public License for more details.
00016  *
00017  *   You should have received a copy of the GNU General Public License
00018  *   along with this program; if not, write to the Free Software
00019  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020  */
00021 #include <string.h>
00022 
00023 #include "gcompris/gcompris.h"
00024 
00025 #define SOUNDLISTFILE PACKAGE
00026 
00027 static GcomprisBoard *gcomprisBoard = NULL;
00028 
00029 static gint dummy_id = 0;
00030 static gint drop_items_id = 0;
00031 
00032 static char *numbers = "123456";
00033 static  int  gamewon;
00034 static guint number_of_dices=1;
00035 
00036 static GnomeCanvasGroup *boardRootItem = NULL;
00037 
00038 static void start_board (GcomprisBoard *agcomprisBoard);
00039 static void pause_board (gboolean pause);
00040 static void end_board (void);
00041 static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
00042 static void set_level (guint level);
00043 static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str);
00044 
00045 static void smallnumbers_create_item(GnomeCanvasGroup *parent);
00046 static gint smallnumbers_drop_items (GtkWidget *widget, gpointer data);
00047 static gint smallnumbers_move_items (GtkWidget *widget, gpointer data);
00048 static void smallnumbers_destroy_all_items(void);
00049 static void smallnumbers_next_level(void);
00050 static void smallnumbers_gotkey_item(GnomeCanvasItem *item, guint key);
00051 
00052 static void           smallnumber_config_start(GcomprisBoard *agcomprisBoard,
00053                                         GcomprisProfile *aProfile);
00054 static void           smallnumber_config_stop(void);
00055 
00056 static void player_win(GnomeCanvasItem *item);
00057 static void player_loose(void);
00058 
00059 static  guint32              fallSpeed = 0;
00060 static  double               speed = 0.0;
00061 static  double               imageZoom = 0.0;
00062 
00063 /* if board has alternate locale */
00064 static gchar *locale_sound = NULL;
00065 static gboolean with_sound = FALSE;
00066 
00067 /* Description of this plugin */
00068 static BoardPlugin menu_bp =
00069 {
00070    NULL,
00071    NULL,
00072    "Numbers With Dice",
00073    "Type the keyboard number 1 to 9 before the dice reaches the ground",
00074    "Bruno Coudoin <bruno.coudoin@free.fr>",
00075    NULL,
00076    NULL,
00077    NULL,
00078    NULL,
00079    start_board,
00080    pause_board,
00081    end_board,
00082    is_our_board,
00083    key_press,
00084    NULL,
00085    set_level,
00086    NULL,
00087    NULL,
00088    smallnumber_config_start,
00089    smallnumber_config_stop
00090 };
00091 
00092 /*
00093  * Main entry point mandatory for each Gcompris's game
00094  * ---------------------------------------------------
00095  *
00096  */
00097 
00098 GET_BPLUGIN_INFO(smallnumbers)
00099 
00100 /*
00101  * in : boolean TRUE = PAUSE : FALSE = UNPAUSE
00102  *
00103  */
00104 static void pause_board (gboolean pause)
00105 {
00106 
00107   if(gcomprisBoard==NULL)
00108     return;
00109 
00110   if(pause)
00111     {
00112       if (dummy_id) {
00113        gtk_timeout_remove (dummy_id);
00114        dummy_id = 0;
00115       }
00116       if (drop_items_id) {
00117        gtk_timeout_remove (drop_items_id);
00118        drop_items_id = 0;
00119       }
00120     }
00121   else
00122     {
00123       if(gamewon == TRUE) /* the game is won */
00124        {
00125          smallnumbers_next_level();
00126        }
00127 
00128       if(!drop_items_id) {
00129        drop_items_id = gtk_timeout_add (1000,
00130                                     (GtkFunction) smallnumbers_drop_items, NULL);
00131       }
00132       if(!dummy_id) {
00133        dummy_id = gtk_timeout_add (1000, (GtkFunction) smallnumbers_move_items, NULL);
00134       }
00135     }
00136 }
00137 
00138 /*
00139  */
00140 static void start_board (GcomprisBoard *agcomprisBoard)
00141 {
00142   GHashTable *config = gc_db_get_board_conf();
00143 
00144   locale_sound = g_strdup(g_hash_table_lookup( config, "locale_sound"));
00145 
00146   gchar *control_sound = g_hash_table_lookup( config, "with_sound");
00147 
00148   if (control_sound && strcmp(g_hash_table_lookup( config, "with_sound"),"True")==0)
00149     with_sound = TRUE;
00150   else
00151     with_sound = FALSE;
00152 
00153   g_hash_table_destroy(config);
00154 
00155   if(agcomprisBoard!=NULL)
00156     {
00157       gcomprisBoard=agcomprisBoard;
00158 
00159       /* disable im_context */
00160       gcomprisBoard->disable_im_context = TRUE;
00161 
00162       gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), "images/scenery7_background.png");
00163 
00164       gcomprisBoard->level = 1;
00165       gcomprisBoard->maxlevel = 9;
00166       gcomprisBoard->number_of_sublevel=10;
00167       gc_score_start(SCORESTYLE_NOTE, 
00168                         gcomprisBoard->width - 220, 
00169                         gcomprisBoard->height - 50, 
00170                         gcomprisBoard->number_of_sublevel);
00171       gc_bar_set(GC_BAR_CONFIG|GC_BAR_LEVEL);
00172 
00173 
00174       number_of_dices=1;
00175       if(!gcomprisBoard->mode)
00176        number_of_dices=1;
00177       else if(g_strncasecmp(gcomprisBoard->mode, "2_DICES", 7)==0) {
00178        /* 2 Dices mode */
00179        number_of_dices=2;
00180       }
00181 
00182       smallnumbers_next_level();
00183 
00184       gamewon = FALSE;
00185       pause_board(FALSE);
00186     }
00187 }
00188 
00189 static void
00190 end_board ()
00191 {
00192   if(gcomprisBoard!=NULL)
00193     {
00194       pause_board(TRUE);
00195       gc_score_end();
00196       smallnumbers_destroy_all_items();
00197     }
00198   gcomprisBoard = NULL;
00199 }
00200 
00201 static void
00202 set_level (guint level)
00203 {
00204 
00205   if(gcomprisBoard!=NULL)
00206     {
00207       gcomprisBoard->level=level;
00208       smallnumbers_next_level();
00209     }
00210 }
00211 
00212 static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str)
00213 {
00214   char str[2];
00215 
00216   if(!gcomprisBoard || !boardRootItem)
00217     return FALSE;
00218 
00219   /* Add some filter for control and shift key */
00220   switch (keyval)
00221     {
00222     case GDK_Shift_L:
00223     case GDK_Shift_R:
00224     case GDK_Control_L:
00225     case GDK_Control_R:
00226     case GDK_Caps_Lock:
00227     case GDK_Shift_Lock:
00228     case GDK_Meta_L:
00229     case GDK_Meta_R:
00230     case GDK_Alt_L:
00231     case GDK_Alt_R:
00232     case GDK_Super_L:
00233     case GDK_Super_R:
00234     case GDK_Hyper_L:
00235     case GDK_Hyper_R:
00236     case GDK_Mode_switch:
00237     case GDK_dead_circumflex:
00238     case GDK_Num_Lock:
00239       return FALSE; 
00240     }
00241 
00242   sprintf(str, "%c", keyval);
00243 
00244   keyval = atoi(str);
00245 
00246   g_list_foreach(GNOME_CANVAS_GROUP(boardRootItem)->item_list, 
00247                (GFunc) smallnumbers_gotkey_item,
00248                GINT_TO_POINTER(keyval));
00249 
00250   return TRUE;
00251 }
00252 
00253 gboolean
00254 is_our_board (GcomprisBoard *gcomprisBoard)
00255 {
00256   if (gcomprisBoard)
00257     {
00258       if(g_strcasecmp(gcomprisBoard->type, "smallnumbers")==0)
00259        {
00260          /* Set the plugin entry */
00261          gcomprisBoard->plugin=&menu_bp;
00262 
00263          return TRUE;
00264        }
00265     }
00266   return FALSE;
00267 }
00268 
00269 
00270 /*-------------------------------------------------------------------------------*/
00271 /*-------------------------------------------------------------------------------*/
00272 /*-------------------------------------------------------------------------------*/
00273 /*-------------------------------------------------------------------------------*/
00274 
00275 /* set initial values for the next level */
00276 static void smallnumbers_next_level() 
00277 {
00278 
00279   gamewon = FALSE;
00280   gc_bar_set_level(gcomprisBoard);
00281 
00282   smallnumbers_destroy_all_items();
00283 
00284   boardRootItem = GNOME_CANVAS_GROUP(
00285                                  gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
00286                                                      gnome_canvas_group_get_type (),
00287                                                      "x", (double) 0,
00288                                                      "y", (double) 0,
00289                                                      NULL));
00290 
00291   /* Try the next level */
00292   speed=100+(40/gcomprisBoard->level);
00293   fallSpeed=5000-gcomprisBoard->level*200;
00294   imageZoom=0.9+(0.5/gcomprisBoard->level);
00295   gcomprisBoard->sublevel=1;
00296   gc_score_set(gcomprisBoard->sublevel);
00297 }
00298 
00299 
00300 /* Destroy all the items */
00301 static void smallnumbers_destroy_all_items()
00302 {
00303 
00304   if(boardRootItem!=NULL)
00305     gtk_object_destroy (GTK_OBJECT(boardRootItem));
00306 
00307   boardRootItem = NULL;
00308 
00309 }
00310 static void smallnumbers_gotkey_item(GnomeCanvasItem *item, guint key)
00311 {
00312   guint number;
00313   
00314   if(G_OBJECT (item)) {
00315     number = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "dice_number"));
00316 
00317     if(number==key) {
00318       player_win(item);
00319     }
00320   }
00321 }
00322 
00323 static void smallnumbers_move_item(GnomeCanvasItem *item)
00324 {
00325   double x1, y1, x2, y2;
00326   gnome_canvas_item_move(item, 0, 2.0);
00327 
00328   gnome_canvas_item_get_bounds (item,
00329                             &x1,
00330                             &y1,
00331                             &x2,
00332                             &y2);
00333   
00334   if(y1>gcomprisBoard->height) {
00335     player_loose();
00336     gtk_object_destroy (GTK_OBJECT(item));
00337   }
00338 }
00339 
00340 /*
00341  * This does the moves of the game items on the play canvas
00342  *
00343  */
00344 static gint smallnumbers_move_items (GtkWidget *widget, gpointer data)
00345 {
00346 
00347   /* For each item we need to move */
00348   g_list_foreach(GNOME_CANVAS_GROUP(boardRootItem)->item_list, (GFunc) smallnumbers_move_item, NULL);
00349 
00350   dummy_id = gtk_timeout_add (speed, 
00351                            (GtkFunction) smallnumbers_move_items, NULL);
00352 
00353   return(FALSE);
00354 }
00355 
00356 static void smallnumbers_create_item(GnomeCanvasGroup *parent)
00357 {
00358   GdkPixbuf *smallnumbers_pixmap = NULL;
00359   GnomeCanvasItem *item;
00360   GnomeCanvasGroup *group_item;
00361   guint i;
00362   guint total_number = 0;
00363   double x = 0.0;
00364   guint number_of_dice = number_of_dices;
00365 
00366   group_item = GNOME_CANVAS_GROUP(
00367                               gnome_canvas_item_new (parent,
00368                                                   gnome_canvas_group_get_type (),
00369                                                   "x", (double) 0,
00370                                                   "y", (double) 40,
00371                                                   NULL));
00372 
00373   while(number_of_dice-- > 0) {
00374     gchar *str1 = NULL;
00375     gchar *str2 = NULL;
00376 
00377     /* Take care not to go above 9 anyway */
00378     if(total_number==0) {
00379       i=rand()%6;
00380     } else {
00381       int rando = rand()%(9-total_number);
00382       i=MIN(rando, 5);
00383     }
00384 
00385     total_number += i + 1;
00386 
00387     /*
00388      * Play the sound
00389      */
00390 
00391     if (with_sound)
00392       {
00393        gunichar *unichar_letterItem;
00394        char *lettersItem;
00395        gchar *letter;
00396 
00397        lettersItem = g_malloc (2);
00398 
00399        sprintf(lettersItem, "%c", numbers[i]);
00400        lettersItem[1] = '\0';
00401 
00402        unichar_letterItem = g_new(gunichar,1);
00403 
00404        *unichar_letterItem = g_utf8_get_char (lettersItem);
00405 
00406        letter = g_new0(gchar, 6);
00407 
00408        g_unichar_to_utf8(*unichar_letterItem, letter);
00409 
00410        str1 = gc_sound_alphabet(letter);
00411 
00412        g_free(letter);
00413        g_free(lettersItem);
00414        g_free(unichar_letterItem);
00415 
00416        str2 = g_strdup_printf("sounds/$LOCALE/alphabet/%s", str1);
00417 
00418        gc_sound_play_ogg(str2, NULL);
00419 
00420        g_free(str1);
00421        g_free(str2);
00422       }
00423 
00424     /*
00425      * Now the images
00426      */
00427     str1 = g_strdup_printf("level%c.png", numbers[i]);
00428     str2 = gc_skin_image_get(str1);
00429 
00430     smallnumbers_pixmap = gc_pixmap_load(str2);
00431 
00432     g_free(str1);
00433     g_free(str2);
00434 
00435     if(x==0.0)
00436       {
00437        x = (double)(rand()%(gcomprisBoard->width-
00438                           (guint)(gdk_pixbuf_get_width(smallnumbers_pixmap)* imageZoom)*2));
00439       }
00440     else
00441       {
00442        x += ((gdk_pixbuf_get_width(smallnumbers_pixmap)-10)*imageZoom);
00443       }
00444 
00445     item = gnome_canvas_item_new (group_item,
00446                               gnome_canvas_pixbuf_get_type (),
00447                               "pixbuf", smallnumbers_pixmap, 
00448                               "x", x,
00449                               "y", (double) -gdk_pixbuf_get_height(smallnumbers_pixmap)*imageZoom,
00450                               "width", (double) gdk_pixbuf_get_width(smallnumbers_pixmap)*imageZoom,
00451                               "height", (double) gdk_pixbuf_get_height(smallnumbers_pixmap)*imageZoom,
00452                               "width_set", TRUE, 
00453                               "height_set", TRUE,
00454                               NULL);
00455     gdk_pixbuf_unref(smallnumbers_pixmap);
00456   }
00457   g_object_set_data (G_OBJECT (group_item), "dice_number", GINT_TO_POINTER (total_number));
00458 
00459 }
00460 
00461 /*
00462  * This is called on a low frequency and is used to drop new items
00463  *
00464  */
00465 static gint smallnumbers_drop_items (GtkWidget *widget, gpointer data)
00466 {
00467   smallnumbers_create_item(boardRootItem);
00468 
00469   drop_items_id = gtk_timeout_add (fallSpeed,
00470                                (GtkFunction) smallnumbers_drop_items, NULL);
00471   return (FALSE);
00472 }
00473 
00474 static void player_win(GnomeCanvasItem *item)
00475 {
00476   gtk_object_destroy (GTK_OBJECT(item));
00477   gc_sound_play_ogg ("sounds/gobble.ogg", NULL);
00478 
00479   gcomprisBoard->sublevel++;
00480   gc_score_set(gcomprisBoard->sublevel);
00481 
00482   if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel)
00483     {
00484       /* Try the next level */
00485       gcomprisBoard->level++;
00486       if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
00487        gc_score_end();
00488        gc_bonus_end_display(BOARD_FINISHED_RANDOM);
00489        return;
00490       }
00491       gamewon = TRUE;
00492       smallnumbers_destroy_all_items();
00493       gc_bonus_display(gamewon, BONUS_SMILEY);
00494     }
00495   else
00496     {
00497       gc_score_set(gcomprisBoard->sublevel);
00498     }
00499 }
00500 
00501 static void player_loose()
00502 {
00503   gc_sound_play_ogg ("crash", NULL);
00504 }
00505 
00506 
00507 /* ======================= */
00508 /* = config_start        = */
00509 /* ======================= */
00510 
00511 static GcomprisProfile *profile_conf;
00512 static GcomprisBoard   *board_conf;
00513 
00514 static GHFunc save_table (gpointer key,
00515                   gpointer value,
00516                   gpointer user_data)
00517 {
00518   gc_db_set_board_conf ( profile_conf,
00519                          board_conf,
00520                          (gchar *) key, 
00521                          (gchar *) value);
00522 
00523   return NULL;
00524 }
00525 
00526 static void conf_ok(GHashTable *table)
00527 {
00528   if (!table){
00529     if (gcomprisBoard)
00530       pause_board(FALSE);
00531     return;
00532   }
00533 
00534   g_hash_table_foreach(table, (GHFunc) save_table, NULL);
00535 
00536   if (gcomprisBoard){
00537     GHashTable *config;
00538 
00539     if (profile_conf)
00540       config = gc_db_get_board_conf();
00541     else
00542       config = table;
00543     
00544     if (locale_sound)
00545       g_free(locale_sound);
00546 
00547     locale_sound = g_strdup(g_hash_table_lookup( config, "locale_sound"));
00548     
00549     gchar *control_sound = g_hash_table_lookup( config, "with_sound");
00550     
00551     if (control_sound && strcmp(g_hash_table_lookup( config, "with_sound"),"True")==0)
00552       with_sound = TRUE;
00553     else
00554       with_sound = FALSE;
00555     
00556     if (profile_conf)
00557       g_hash_table_destroy(config);
00558 
00559     smallnumbers_next_level();
00560 
00561     gamewon = FALSE;
00562 
00563     pause_board(FALSE);
00564   }
00565 
00566   board_conf = NULL;
00567   profile_conf = NULL;
00568 }
00569 
00570 static void sound_control_box_toggled(GtkToggleButton *togglebutton,
00571                                   gpointer combo)
00572 {
00573   gtk_widget_set_sensitive(GTK_WIDGET(combo), gtk_toggle_button_get_active (togglebutton));
00574 }
00575 
00576 
00577 static void
00578 smallnumber_config_start(GcomprisBoard *agcomprisBoard,
00579                   GcomprisProfile *aProfile)
00580 {
00581   board_conf = agcomprisBoard;
00582   profile_conf = aProfile;
00583 
00584   if (gcomprisBoard)
00585     pause_board(TRUE);
00586 
00587   gchar *label;
00588   
00589   label = g_strdup_printf("<b>%s</b> configuration\n for profile <b>%s</b>",
00590                        agcomprisBoard->name, aProfile ? aProfile->name : "");
00591 
00592   gc_board_config_window_display(label, (GcomprisConfCallback )conf_ok);
00593 
00594   g_free(label);
00595 
00596   /* init the combo to previously saved value */
00597   GHashTable *config = gc_db_get_conf( profile_conf, board_conf);
00598 
00599   gchar *saved_locale_sound = g_hash_table_lookup( config, "locale_sound");
00600 
00601   gchar *control_sound = g_hash_table_lookup( config, "with_sound");
00602   if (control_sound && strcmp(g_hash_table_lookup( config, "with_sound"),"True")==0)
00603     with_sound = TRUE;
00604   else
00605     with_sound = FALSE;
00606 
00607   GtkCheckButton  *sound_control = gc_board_config_boolean_box("Enable sounds", "with_sound", with_sound);
00608   
00609   GtkComboBox *sound_box = gc_board_config_combo_locales_asset( "Select sound locale",
00610                                                   saved_locale_sound,
00611                                                   "sounds/$LOCALE/colors/purple.ogg");
00612 
00613   gtk_widget_set_sensitive(GTK_WIDGET(sound_box), with_sound);
00614 
00615   g_signal_connect(G_OBJECT(sound_control), "toggled", 
00616                  G_CALLBACK(sound_control_box_toggled),
00617                  sound_box);
00618 
00619   g_hash_table_destroy(config);
00620 
00621 }  
00622 /* ======================= */
00623 /* = config_stop        = */
00624 /* ======================= */
00625 static void 
00626 smallnumber_config_stop()
00627 {
00628 }