/* gcompris - smallnumbers.c
*
* Copyright (C) 2000 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 gboolean board_paused = TRUE;
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 GnomeCanvasGroup *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(GnomeCanvasGroup *parent);
static gint smallnumbers_drop_items (GtkWidget *widget, gpointer data);
static gint smallnumbers_move_items (GtkWidget *widget, gpointer data);
static void smallnumbers_destroy_all_items(void);
static void smallnumbers_next_level(void);
static void smallnumbers_gotkey_item(GnomeCanvasItem *item, guint key);
static void smallnumber_config_start(GcomprisBoard *agcomprisBoard,
GcomprisProfile *aProfile);
static void smallnumber_config_stop(void);
static void player_win(GnomeCanvasItem *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) {
gtk_timeout_remove (dummy_id);
dummy_id = 0;
}
if (drop_items_id) {
gtk_timeout_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 = gtk_timeout_add (1000,
(GtkFunction) smallnumbers_drop_items, NULL);
}
if(!dummy_id) {
dummy_id = gtk_timeout_add (1000, (GtkFunction) smallnumbers_move_items, NULL);
}
}
board_paused = pause;
}
/*
*/
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(gnome_canvas_root(gcomprisBoard->canvas), "opt/scenery7_background.png");
gcomprisBoard->level = 1;
gcomprisBoard->maxlevel = 9;
gcomprisBoard->number_of_sublevel=10;
gc_score_start(SCORESTYLE_NOTE,
gcomprisBoard->width - 220,
gcomprisBoard->height - 50,
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_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];
if(board_paused || !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);
g_list_foreach(GNOME_CANVAS_GROUP(boardRootItem)->item_list,
(GFunc) smallnumbers_gotkey_item,
GINT_TO_POINTER(keyval));
if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel)
{
/* Try the next level */
gcomprisBoard->level++;
if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
gc_score_end();
gc_bonus_end_display(GC_BOARD_FINISHED_RANDOM);
return TRUE;
}
gamewon = TRUE;
smallnumbers_destroy_all_items();
gc_bonus_display(gamewon, GC_BONUS_SMILEY);
}
else
{
gc_score_set(gcomprisBoard->sublevel);
}
return TRUE;
}
gboolean
is_our_board (GcomprisBoard *gcomprisBoard)
{
if (gcomprisBoard)
{
if(g_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 = GNOME_CANVAS_GROUP(
gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
gnome_canvas_group_get_type (),
"x", (double) 0,
"y", (double) 0,
NULL));
/* Try the next level */
speed=100+(40/gcomprisBoard->level);
fallSpeed=5000-gcomprisBoard->level*200;
imageZoom=0.9+(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)
gtk_object_destroy (GTK_OBJECT(boardRootItem));
boardRootItem = NULL;
}
static void smallnumbers_gotkey_item(GnomeCanvasItem *item, guint key)
{
guint number;
if(G_OBJECT (item)) {
number = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item), "dice_number"));
if(number==key) {
player_win(item);
}
}
}
static void smallnumbers_move_item(GnomeCanvasItem *item)
{
double x1, y1, x2, y2;
gnome_canvas_item_move(item, 0, 2.0);
gnome_canvas_item_get_bounds (item,
&x1,
&y1,
&x2,
&y2);
if(y1>gcomprisBoard->height) {
player_loose();
gtk_object_destroy (GTK_OBJECT(item));
}
}
/*
* This does the moves of the game items on the play canvas
*
*/
static gint smallnumbers_move_items (GtkWidget *widget, gpointer data)
{
/* For each item we need to move */
g_list_foreach(GNOME_CANVAS_GROUP(boardRootItem)->item_list, (GFunc) smallnumbers_move_item, NULL);
dummy_id = gtk_timeout_add (speed,
(GtkFunction) smallnumbers_move_items, NULL);
return(FALSE);
}
static void smallnumbers_create_item(GnomeCanvasGroup *parent)
{
GdkPixbuf *smallnumbers_pixmap = NULL;
GnomeCanvasItem *item;
GnomeCanvasGroup *group_item;
guint i;
guint total_number = 0;
double x = 0.0;
guint number_of_dice = number_of_dices;
group_item = GNOME_CANVAS_GROUP(
gnome_canvas_item_new (parent,
gnome_canvas_group_get_type (),
"x", (double) 0,
"y", (double) 40,
NULL));
while(number_of_dice-- > 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
*/
str1 = g_strdup_printf("level%c.png", numbers[i]);
str2 = gc_skin_image_get(str1);
smallnumbers_pixmap = gc_pixmap_load(str2);
g_free(str1);
g_free(str2);
if(x==0.0)
{
x = (double)(g_random_int()%(gcomprisBoard->width-
(guint)(gdk_pixbuf_get_width(smallnumbers_pixmap)* imageZoom)*2));
}
else
{
x += ((gdk_pixbuf_get_width(smallnumbers_pixmap)-10)*imageZoom);
}
item = gnome_canvas_item_new (group_item,
gnome_canvas_pixbuf_get_type (),
"pixbuf", smallnumbers_pixmap,
"x", x,
"y", (double) -gdk_pixbuf_get_height(smallnumbers_pixmap)*imageZoom,
"width", (double) gdk_pixbuf_get_width(smallnumbers_pixmap)*imageZoom,
"height", (double) gdk_pixbuf_get_height(smallnumbers_pixmap)*imageZoom,
"width_set", TRUE,
"height_set", TRUE,
NULL);
gdk_pixbuf_unref(smallnumbers_pixmap);
}
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 gint smallnumbers_drop_items (GtkWidget *widget, gpointer data)
{
gc_sound_play_ogg ("sounds/level.wav", NULL);
smallnumbers_create_item(boardRootItem);
drop_items_id = gtk_timeout_add (fallSpeed,
(GtkFunction) smallnumbers_drop_items, NULL);
return (FALSE);
}
static void player_win(GnomeCanvasItem *item)
{
gtk_object_destroy (GTK_OBJECT(item));
gc_sound_play_ogg ("sounds/flip.wav", NULL);
gcomprisBoard->sublevel++;
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 void conf_ok(GHashTable *table)
{
if (!table){
if (gcomprisBoard)
pause_board(FALSE);
return;
}
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;
}
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, (GcomprisConfCallback )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");
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()
{
}