/* gcompris - smallnumbers.c * * Copyright (C) 2000, 2008 Bruno Coudoin * * 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 #include "gcompris/gcompris.h" #define SOUNDLISTFILE PACKAGE static GcomprisBoard *gcomprisBoard = NULL; static gint dummy_id = 0; static gint drop_items_id = 0; static char *numbers = "123456"; static int gamewon; static guint number_of_dices=1; static GooCanvasItem *boardRootItem = NULL; 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 gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str); static void smallnumbers_create_item(GooCanvasItem *parent); static gboolean smallnumbers_drop_items (gpointer data); static gboolean smallnumbers_move_items (gpointer data); static void smallnumbers_destroy_all_items(void); static void smallnumbers_next_level(void); static gboolean smallnumbers_gotkey_item(GooCanvasItem *item, guint key); static void smallnumber_config_start(GcomprisBoard *agcomprisBoard, GcomprisProfile *aProfile); static void smallnumber_config_stop(void); static void player_win(GooCanvasItem *item); static void player_loose(void); static guint32 fallSpeed = 0; static double speed = 0.0; static double imageZoom = 0.0; /* if board has alternate locale */ static gchar *locale_sound = NULL; static gboolean with_sound = FALSE; /* Description of this plugin */ static BoardPlugin menu_bp = { NULL, NULL, "Numbers With Dice", "Type the keyboard number 1 to 9 before the dice reaches the ground", "Bruno Coudoin ", NULL, NULL, NULL, NULL, start_board, pause_board, end_board, is_our_board, key_press, NULL, set_level, NULL, NULL, smallnumber_config_start, smallnumber_config_stop }; /* * Main entry point mandatory for each Gcompris's game * --------------------------------------------------- * */ GET_BPLUGIN_INFO(smallnumbers) /* * in : boolean TRUE = PAUSE : FALSE = UNPAUSE * */ static void pause_board (gboolean pause) { if(gcomprisBoard==NULL) return; if(pause) { if (dummy_id) { g_source_remove (dummy_id); dummy_id = 0; } if (drop_items_id) { g_source_remove (drop_items_id); drop_items_id = 0; } } else { if(gamewon == TRUE) /* the game is won */ { smallnumbers_next_level(); } if(!drop_items_id) { drop_items_id = g_timeout_add (1000, smallnumbers_drop_items, NULL); } if(!dummy_id) { dummy_id = g_timeout_add (1000, smallnumbers_move_items, NULL); } } } /* */ static void start_board (GcomprisBoard *agcomprisBoard) { GHashTable *config = gc_db_get_board_conf(); locale_sound = g_strdup(g_hash_table_lookup( config, "locale_sound")); gchar *control_sound = g_hash_table_lookup( config, "with_sound"); if (control_sound && strcmp(g_hash_table_lookup( config, "with_sound"),"True")==0) with_sound = TRUE; else with_sound = FALSE; g_hash_table_destroy(config); if(agcomprisBoard!=NULL) { gcomprisBoard=agcomprisBoard; /* disable im_context */ gcomprisBoard->disable_im_context = TRUE; gc_set_background(goo_canvas_get_root_item(gcomprisBoard->canvas), "smallnumbers/scenery7_background.png"); gcomprisBoard->level = 1; gcomprisBoard->maxlevel = 9; gcomprisBoard->number_of_sublevel=10; gc_score_start(SCORESTYLE_NOTE, BOARDWIDTH - 195, BOARDHEIGHT - 30, gcomprisBoard->number_of_sublevel); gc_bar_set(GC_BAR_CONFIG|GC_BAR_LEVEL); number_of_dices=1; if(!gcomprisBoard->mode) number_of_dices=1; else if(g_ascii_strncasecmp(gcomprisBoard->mode, "2_DICES", 7)==0) { /* 2 Dices mode */ number_of_dices=2; } smallnumbers_next_level(); gamewon = FALSE; pause_board(FALSE); } } static void end_board () { if(gcomprisBoard!=NULL) { pause_board(TRUE); gc_score_end(); smallnumbers_destroy_all_items(); } gcomprisBoard = NULL; } static void set_level (guint level) { if(gcomprisBoard!=NULL) { gcomprisBoard->level=level; smallnumbers_next_level(); } } static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str) { char str[2]; int i; if(!gcomprisBoard || !boardRootItem) return FALSE; /* Add some filter for control and shift key */ switch (keyval) { case GDK_Shift_L: case GDK_Shift_R: case GDK_Control_L: case GDK_Control_R: case GDK_Caps_Lock: case GDK_Shift_Lock: case GDK_Meta_L: case GDK_Meta_R: case GDK_Alt_L: case GDK_Alt_R: case GDK_Super_L: case GDK_Super_R: case GDK_Hyper_L: case GDK_Hyper_R: case GDK_Mode_switch: case GDK_dead_circumflex: case GDK_Num_Lock: return FALSE; } sprintf(str, "%c", keyval); keyval = atoi(str); /* Warning, deleting items in a loop is not safe */ int gotit = FALSE; int nb_item = goo_canvas_item_get_n_children(boardRootItem); for(i=0; (!gotit && i< nb_item); i++) gotit = smallnumbers_gotkey_item( goo_canvas_item_get_child(boardRootItem, i), keyval ); return TRUE; } gboolean is_our_board (GcomprisBoard *gcomprisBoard) { if (gcomprisBoard) { if(g_ascii_strcasecmp(gcomprisBoard->type, "smallnumbers")==0) { /* Set the plugin entry */ gcomprisBoard->plugin=&menu_bp; return TRUE; } } return FALSE; } /*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------------*/ /* set initial values for the next level */ static void smallnumbers_next_level() { gamewon = FALSE; gc_bar_set_level(gcomprisBoard); smallnumbers_destroy_all_items(); boardRootItem = goo_canvas_group_new (goo_canvas_get_root_item(gcomprisBoard->canvas), NULL); /* Try the next level */ speed=100+(40/gcomprisBoard->level); fallSpeed=5000-gcomprisBoard->level*200; imageZoom=0.4+(0.5/gcomprisBoard->level); gcomprisBoard->sublevel=1; gc_score_set(gcomprisBoard->sublevel); } /* Destroy all the items */ static void smallnumbers_destroy_all_items() { if(boardRootItem!=NULL) goo_canvas_item_remove(boardRootItem); boardRootItem = NULL; } static gboolean smallnumbers_gotkey_item(GooCanvasItem *item, guint key) { guint number; gboolean gotit = FALSE; if(G_OBJECT (item)) { number = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "dice_number")); if(number == key) { gotit = TRUE; player_win(item); } } return(gotit); } static void smallnumbers_move_item(GooCanvasItem *item) { if (item == NULL ) return; goo_canvas_item_translate(item, 0, 2.0); GooCanvasBounds bounds; goo_canvas_item_get_bounds (item, &bounds); if(bounds.y1>BOARDHEIGHT) { player_loose(); goo_canvas_item_remove(item); } } /* * This does the moves of the game items on the play canvas * */ static gboolean smallnumbers_move_items (gpointer data) { int i; int count = goo_canvas_item_get_n_children(boardRootItem); /* For each item we need to move */ for(i=0; i 0) { gchar *str1 = NULL; gchar *str2 = NULL; /* Take care not to go above 9 anyway */ if(total_number==0) { i=g_random_int()%6; } else { int rando = g_random_int()%(9-total_number); i=MIN(rando, 5); } total_number += i + 1; /* * Play the sound */ if (with_sound) { gunichar *unichar_letterItem; char *lettersItem; gchar *letter; lettersItem = g_malloc (2); sprintf(lettersItem, "%c", numbers[i]); lettersItem[1] = '\0'; unichar_letterItem = g_new(gunichar,1); *unichar_letterItem = g_utf8_get_char (lettersItem); letter = g_new0(gchar, 6); g_unichar_to_utf8(*unichar_letterItem, letter); str1 = gc_sound_alphabet(letter); g_free(letter); g_free(lettersItem); g_free(unichar_letterItem); str2 = g_strdup_printf("voices/$LOCALE/alphabet/%s", str1); gc_sound_play_ogg(str2, NULL); g_free(str1); g_free(str2); } /* * Now the images */ RsvgHandle *svg_handle; RsvgDimensionData rsvg_dimension; str1 = g_strdup_printf("smallnumbers/dice%c.svgz", numbers[i]); svg_handle = gc_rsvg_load(str1); rsvg_handle_get_dimensions (svg_handle, &rsvg_dimension); g_free(str1); gdouble item_w = rsvg_dimension.width * imageZoom; if (x == 0) { if ( x_previous < BOARDWIDTH / 2 ) x = x_previous + item_w + (gdouble)(g_random_int() % (guint)(BOARDWIDTH - x_previous - item_w * 3)); else x = (double)(g_random_int() % (guint)(x_previous - item_w)); x_previous = x; } else { x += item_w; } item = goo_canvas_svg_new (group_item, svg_handle, NULL); goo_canvas_item_translate(item, x, - (rsvg_dimension.height * imageZoom )); goo_canvas_item_scale(item, imageZoom, imageZoom); g_object_unref(svg_handle); } g_object_set_data (G_OBJECT (group_item), "dice_number", GINT_TO_POINTER (total_number)); } /* * This is called on a low frequency and is used to drop new items * */ static gboolean smallnumbers_drop_items (gpointer data) { gc_sound_play_ogg ("sounds/level.wav", NULL); smallnumbers_create_item(boardRootItem); drop_items_id = g_timeout_add (fallSpeed, smallnumbers_drop_items, NULL); return (FALSE); } static void player_win(GooCanvasItem *item) { goo_canvas_item_remove(item); gc_sound_play_ogg ("sounds/flip.wav", NULL); gcomprisBoard->sublevel++; if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) { /* Try the next level */ gcomprisBoard->level++; if(gcomprisBoard->level>gcomprisBoard->maxlevel) gcomprisBoard->level = gcomprisBoard->maxlevel; gamewon = TRUE; smallnumbers_destroy_all_items(); gc_bonus_display(gamewon, GC_BONUS_SMILEY); } else { gc_score_set(gcomprisBoard->sublevel); } } static void player_loose() { gc_sound_play_ogg ("crash", NULL); } /* ======================= */ /* = config_start = */ /* ======================= */ static GcomprisProfile *profile_conf; static GcomprisBoard *board_conf; static GHFunc save_table (gpointer key, gpointer value, gpointer user_data) { gc_db_set_board_conf ( profile_conf, board_conf, (gchar *) key, (gchar *) value); return NULL; } static gboolean conf_ok(GHashTable *table) { if (!table){ if (gcomprisBoard) pause_board(FALSE); return TRUE; } g_hash_table_foreach(table, (GHFunc) save_table, NULL); if (gcomprisBoard){ GHashTable *config; if (profile_conf) config = gc_db_get_board_conf(); else config = table; if (locale_sound) g_free(locale_sound); locale_sound = g_strdup(g_hash_table_lookup( config, "locale_sound")); gchar *control_sound = g_hash_table_lookup( config, "with_sound"); if (control_sound && strcmp(g_hash_table_lookup( config, "with_sound"),"True")==0) with_sound = TRUE; else with_sound = FALSE; if (profile_conf) g_hash_table_destroy(config); smallnumbers_next_level(); gamewon = FALSE; pause_board(FALSE); } board_conf = NULL; profile_conf = NULL; return TRUE; } static void sound_control_box_toggled(GtkToggleButton *togglebutton, gpointer combo) { gtk_widget_set_sensitive(GTK_WIDGET(combo), gtk_toggle_button_get_active (togglebutton)); } static void smallnumber_config_start(GcomprisBoard *agcomprisBoard, GcomprisProfile *aProfile) { board_conf = agcomprisBoard; profile_conf = aProfile; if (gcomprisBoard) pause_board(TRUE); gchar *label; label = g_strdup_printf(_("%s configuration\n for profile %s"), agcomprisBoard->name, aProfile ? aProfile->name : ""); GcomprisBoardConf *bconf; bconf = gc_board_config_window_display(label, conf_ok); g_free(label); /* init the combo to previously saved value */ GHashTable *config = gc_db_get_conf( profile_conf, board_conf); gchar *saved_locale_sound = g_hash_table_lookup( config, "locale_sound"); gchar *control_sound = g_hash_table_lookup( config, "with_sound"); if (control_sound && strcmp(g_hash_table_lookup( config, "with_sound"),"True")==0) with_sound = TRUE; else with_sound = FALSE; GtkCheckButton *sound_control = gc_board_config_boolean_box(bconf, _("Enable sounds"), "with_sound", with_sound); GtkComboBox *sound_box = gc_board_config_combo_locales_asset(bconf, _("Select sound locale"), saved_locale_sound, "voices/$LOCALE/colors/purple.ogg", NULL); gtk_widget_set_sensitive(GTK_WIDGET(sound_box), with_sound); g_signal_connect(G_OBJECT(sound_control), "toggled", G_CALLBACK(sound_control_box_toggled), sound_box); g_hash_table_destroy(config); } /* ======================= */ /* = config_stop = */ /* ======================= */ static void smallnumber_config_stop() { }