/* gcompris - advanced_colors.c * * Copyright (C) 2002 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 /* libxml includes */ #include #include #include "gcompris/gcompris.h" #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 int gamewon, errors; static void ok(void); static void highlight_selected(int); static void game_won(void); static void init_xml(void); static gboolean read_xml_file(char *fname); /* ================================================================ */ static GnomeCanvasGroup *boardRootItem = NULL; static GnomeCanvasItem *highlight_image_item = NULL; static GnomeCanvasItem *clock_image_item = NULL; static GdkPixbuf *clock_pixmap = NULL; static GnomeCanvasItem *color_item = NULL; static GnomeCanvasItem *colors_create_item(GnomeCanvasGroup *parent); static void colors_destroy_all_items(void); static void colors_next_level(void); static void set_level (guint); static void update_clock(); static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data); static int highlight_width, highlight_height; static GList * listColors = NULL; #define LAST_COLOR 8 #define LAST_BOARD 9 #define MAX_ERRORS 10 #define CLOCK_X 40 #define CLOCK_Y 420 static char* colors[LAST_COLOR]; static char *backgroundFile = NULL; static int X[] = {57,229,236,389,413,567,573,744, 7,207,212,388,415,589,594,794}; static int Y[] = {158,255,268,380}; /* (x1,y1) and (x2, y2) are the coordinates of the rectangle where to draw the color's name */ static int color_x1 = 199, color_x2 = 582; static int color_y1 = 47, color_y2 = 133; /* Description of this plugin */ static BoardPlugin menu_bp = { NULL, NULL, "Advanced colors", "Click on the right color", "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(advanced_colors) /* ===================================================================== * in : boolean TRUE = PAUSE : FALSE = CONTINUE * =====================================================================*/ static void pause_board (gboolean pause) { if(gcomprisBoard==NULL) return; gc_bar_hide(FALSE); 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; gcomprisBoard->level=1; gcomprisBoard->maxlevel=LAST_BOARD; gcomprisBoard->sublevel = 1; gcomprisBoard->number_of_sublevel = 8; gc_bar_set(GC_BAR_LEVEL); gc_score_start(SCORESTYLE_NOTE, gcomprisBoard->width - 220, gcomprisBoard->height - 50, gcomprisBoard->number_of_sublevel); gamewon = FALSE; errors = MAX_ERRORS; init_xml(); gtk_signal_connect(GTK_OBJECT(gcomprisBoard->canvas), "event", (GtkSignalFunc) item_event, NULL); colors_next_level(); pause_board(FALSE); } } /* ===================================================================== * * =====================================================================*/ static void end_board () { if(gcomprisBoard!=NULL){ pause_board(TRUE); gc_score_end(); colors_destroy_all_items(); // free list while (g_list_length(listColors) > 0) listColors = g_list_remove(listColors, g_list_nth_data(listColors,0)); } gcomprisBoard = NULL; } /* ===================================================================== * * =====================================================================*/ static void set_level (guint level) { if(gcomprisBoard!=NULL) { gcomprisBoard->level=level; gcomprisBoard->sublevel=1; init_xml(); colors_next_level(); } } /* ===================================================================== * * =====================================================================*/ static gboolean is_our_board (GcomprisBoard *gcomprisBoard) { if (gcomprisBoard) { if(g_strcasecmp(gcomprisBoard->type, "advanced_colors")==0) { /* Set the plugin entry */ gcomprisBoard->plugin=&menu_bp; return TRUE; } } return FALSE; } /* ===================================================================== * set initial values for the next level * =====================================================================*/ static void colors_next_level() { gchar *str = NULL; int i, list_length; GList * list = NULL; int * item; colors_destroy_all_items(); gamewon = FALSE; gc_score_set(gcomprisBoard->sublevel); gc_bar_set_level(gcomprisBoard); /* initialize board only once*/ if (gcomprisBoard->sublevel == 1) { // we generate a list of color indexes in a random order while (g_list_length(listColors) > 0) listColors = g_list_remove(listColors, g_list_nth_data(listColors,0)); for (i=0; iboarddir, backgroundFile); g_warning("background = %s\n", str); gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), str); g_free(str); } colors_create_item(gnome_canvas_root(gcomprisBoard->canvas)); /* show text of color to find */ color_item = gnome_canvas_item_new (boardRootItem, gnome_canvas_text_get_type (), "text", colors[GPOINTER_TO_INT(g_list_nth_data(listColors,0))], "font", gc_skin_font_board_title_bold, "x", (double) (color_x1+color_x2)/2, "y", (double) (color_y1+color_y2)/2, "anchor", GTK_ANCHOR_CENTER, "fill_color", "darkblue", NULL); } /* ===================================================================== * Destroy all the items * =====================================================================*/ static void colors_destroy_all_items() { if(boardRootItem!=NULL) gtk_object_destroy (GTK_OBJECT(boardRootItem)); boardRootItem = NULL; } /* ===================================================================== * * =====================================================================*/ static GnomeCanvasItem *colors_create_item(GnomeCanvasGroup *parent) { GdkPixbuf *highlight_pixmap = NULL; char *str = NULL; int i; 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)); str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "advanced_colors_highlight.png"); highlight_pixmap = gc_pixmap_load(str); highlight_image_item = gnome_canvas_item_new (boardRootItem, gnome_canvas_pixbuf_get_type (), "pixbuf", highlight_pixmap, "x", (double) 0, "y", (double) 0, "width", (double) gdk_pixbuf_get_width(highlight_pixmap), "height", (double) gdk_pixbuf_get_height(highlight_pixmap), "width_set", TRUE, "height_set", TRUE, NULL); highlight_width = gdk_pixbuf_get_width(highlight_pixmap); highlight_height = gdk_pixbuf_get_height(highlight_pixmap); g_free(str); gnome_canvas_item_hide(highlight_image_item); i = g_random_int_range(0,LAST_COLOR); gdk_pixbuf_unref(highlight_pixmap); /* setup the clock */ str = g_strdup_printf("%s%d.png", "gcompris/timers/clock",errors); clock_pixmap = gc_pixmap_load(str); clock_image_item = gnome_canvas_item_new (boardRootItem, gnome_canvas_pixbuf_get_type (), "pixbuf", clock_pixmap, "x", (double) CLOCK_X, "y", (double) CLOCK_Y, "width", (double) gdk_pixbuf_get_width(clock_pixmap), "height", (double) gdk_pixbuf_get_height(clock_pixmap), "width_set", TRUE, "height_set", TRUE, NULL); g_free(str); return NULL; } /* ===================================================================== * * =====================================================================*/ static void game_won() { listColors = g_list_remove(listColors, g_list_nth_data(listColors,0)); if( g_list_length(listColors) <= 0 ) { // the current board is finished gcomprisBoard->level++; gcomprisBoard->sublevel = 1; if (gcomprisBoard->level > gcomprisBoard->maxlevel) { gc_bonus_end_display(GC_BOARD_FINISHED_TUXLOCO); return; } init_xml(); } else { // the current board is not finished gcomprisBoard->sublevel++; } colors_next_level(); } /* ===================================================================== * * =====================================================================*/ static gboolean ok_timeout() { g_warning("+++ ok_timeout errors = %d\n", errors); gc_bonus_display(gamewon, GC_BONUS_SMILEY); if (!gamewon) errors--; if (errors <1) errors = 1; update_clock(); if (errors <= 1) { gc_bonus_end_display(GC_BOARD_FINISHED_TOOMANYERRORS); } 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); } /* ===================================================================== * * =====================================================================*/ static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) { double x, y; int i, j, clicked; x = event->button.x; y = event->button.y; if (!gcomprisBoard || board_paused) return FALSE; switch (event->type) { case GDK_BUTTON_PRESS: gnome_canvas_c2w (gcomprisBoard->canvas, x, y, &x, &y); clicked = -1; for (i=0; i<4; i++) { for (j=0; j<2; j++) { if (x>X[i*2] && xY[j*2] && y= 0) { gc_sound_play_ogg ("sounds/bleep.wav", NULL); board_paused = TRUE; highlight_selected(clicked); gamewon = (clicked == GPOINTER_TO_INT(g_list_nth_data(listColors,0))); ok(); } break; default: break; } return FALSE; } /* ===================================================================== * * =====================================================================*/ static void update_clock() { char *str = g_strdup_printf("%s%d.png", "gcompris/timers/clock",errors); gtk_object_destroy (GTK_OBJECT(clock_image_item)); clock_pixmap = gc_pixmap_load(str); clock_image_item = gnome_canvas_item_new (boardRootItem, gnome_canvas_pixbuf_get_type (), "pixbuf", clock_pixmap, "x", (double) CLOCK_X, "y", (double) CLOCK_Y, "width", (double) gdk_pixbuf_get_width(clock_pixmap), "height", (double) gdk_pixbuf_get_height(clock_pixmap), "width_set", TRUE, "height_set", TRUE, NULL); gdk_pixbuf_unref(clock_pixmap); g_free(str); } /* ===================================================================== * * =====================================================================*/ static void highlight_selected(int c) { int x, y; g_assert(c>=0 && c<8); x = (X[c*2] + X[c*2+1]) /2; y = (Y[(int)(c/4)*2] + Y[(int)(c/4)*2+1]) /2; x -= highlight_width/2; y -= highlight_height; gnome_canvas_item_show(highlight_image_item); gc_item_absolute_move(highlight_image_item, x, y); } /* =================================== * XML stuff * ==================================== */ static void init_xml() { char *filename; filename = gc_file_find_absolute("%s/board%d.xml", gcomprisBoard->boarddir, gcomprisBoard->level); g_assert(read_xml_file(filename)== TRUE); g_free(filename); } /* ==================================== */ static void add_xml_data(xmlDocPtr doc, xmlNodePtr xmlnode, GNode * child) { char *text = NULL; char *sColor = NULL; int i; xmlnode = xmlnode->xmlChildrenNode; xmlnode = xmlnode->next; while (xmlnode != NULL) { if (!strcmp((char *)xmlnode->name, "pixmapfile")) backgroundFile = (char *)xmlNodeListGetString(doc, xmlnode->xmlChildrenNode, 1); // try to match color[i] for (i=0; i<8; i++) { sColor = g_strdup_printf("color%d", i+1); if (!strcmp((char *)xmlnode->name, sColor)) { text = (char*)xmlNodeListGetString(doc, xmlnode->xmlChildrenNode, 1); if(text) { colors[i] = gettext((char *)text); // We got a translation, free the original value if ( text != colors[i] ) g_free(text); } text = NULL; g_free(sColor); break; } g_free(sColor); } // end for xmlnode = xmlnode->next; } // I really don't know why this test, but otherwise, the list is doubled // with 1 line on 2 filled with NULL elements if ( backgroundFile == NULL || text == NULL) return; } /* ==================================== */ static void parse_doc(xmlDocPtr doc) { xmlNodePtr node; for(node = doc->children->children; node != NULL; node = node->next) { if ( g_strcasecmp((char *)node->name, "Board") == 0 ) add_xml_data(doc, node, NULL); } } /* ==================================== */ /* read an xml file into our memory structures and update our view, dump any old data we have in memory if we can load a new set */ static gboolean read_xml_file(char *fname) { /* pointer to the new doc */ xmlDocPtr doc; g_return_val_if_fail(fname!=NULL,FALSE); /* parse the new file and put the result into newdoc */ doc = xmlParseFile(fname); /* in case something went wrong */ if(!doc) return FALSE; if(/* if there is no root element */ !doc->children || /* if it doesn't have a name */ !doc->children->name || /* if it isn't a ImageId node */ g_strcasecmp((char *)doc->children->name,"AdvancedColors")!=0) { xmlFreeDoc(doc); return FALSE; } parse_doc(doc); xmlFreeDoc(doc); return TRUE; }