Back to index

gcompris  8.2.2
advanced_colors.c
Go to the documentation of this file.
00001 /* gcompris - advanced_colors.c
00002  *
00003  * Copyright (C) 2002 Pascal Georges
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU General Public License as published by
00007  *   the Free Software Foundation; either version 2 of the License, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details.
00014  *
00015  *   You should have received a copy of the GNU General Public License
00016  *   along with this program; if not, write to the Free Software
00017  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #include <string.h>
00021 
00022 /* libxml includes */
00023 #include <libxml/tree.h>
00024 #include <libxml/parser.h>
00025 
00026 #include "gcompris/gcompris.h"
00027 
00028 #define SOUNDLISTFILE PACKAGE
00029 
00030 static GcomprisBoard *gcomprisBoard = NULL;
00031 static gboolean board_paused = TRUE;
00032 
00033 static void           start_board (GcomprisBoard *agcomprisBoard);
00034 static void           pause_board (gboolean pause);
00035 static void           end_board (void);
00036 static gboolean              is_our_board (GcomprisBoard *gcomprisBoard);
00037 static int gamewon, errors;
00038 
00039 static void           ok(void);
00040 static void           highlight_selected(int);
00041 static void           game_won(void);
00042 static void           init_xml(void);
00043 static gboolean              read_xml_file(char *fname);
00044 
00045 /* ================================================================ */
00046 static GnomeCanvasGroup *boardRootItem = NULL;
00047 static GnomeCanvasItem *highlight_image_item = NULL;
00048 static GnomeCanvasItem *clock_image_item = NULL;
00049 static GdkPixbuf *clock_pixmap = NULL;
00050 static GnomeCanvasItem *color_item = NULL;
00051 
00052 static GnomeCanvasItem *colors_create_item(GnomeCanvasGroup *parent);
00053 static void colors_destroy_all_items(void);
00054 static void colors_next_level(void);
00055 static void set_level (guint);
00056 static void update_clock();
00057 static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
00058 static int highlight_width, highlight_height;
00059 static GList * listColors = NULL;
00060 
00061 #define LAST_COLOR 8
00062 #define LAST_BOARD 9
00063 #define MAX_ERRORS 10
00064 #define CLOCK_X 40
00065 #define CLOCK_Y 420
00066 
00067 
00068 static char* colors[LAST_COLOR];
00069 static char *backgroundFile = NULL;
00070 
00071 static int X[] = {57,229,236,389,413,567,573,744,
00072                 7,207,212,388,415,589,594,794};
00073 static int Y[] = {158,255,268,380};
00074 
00075 /* (x1,y1) and (x2, y2) are the coordinates of the rectangle where to
00076    draw the color's name */
00077 static int color_x1 = 199, color_x2 = 582;
00078 static int color_y1 = 47, color_y2 = 133;
00079 
00080 /* Description of this plugin */
00081 static BoardPlugin menu_bp =
00082   {
00083     NULL,
00084     NULL,
00085     "Advanced colors",
00086     "Click on the right color",
00087     "Pascal Georges pascal.georges1@free.fr>",
00088     NULL,
00089     NULL,
00090     NULL,
00091     NULL,
00092     start_board,
00093     pause_board,
00094     end_board,
00095     is_our_board,
00096     NULL,
00097     NULL,
00098     set_level,
00099     NULL,
00100     NULL,
00101     NULL,
00102     NULL
00103   };
00104 
00105 /* =====================================================================
00106  *
00107  * =====================================================================*/
00108 GET_BPLUGIN_INFO(advanced_colors)
00109 
00110 /* =====================================================================
00111  * in : boolean TRUE = PAUSE : FALSE = CONTINUE
00112  * =====================================================================*/
00113 static void pause_board (gboolean pause)
00114 {
00115   if(gcomprisBoard==NULL)
00116     return;
00117 
00118   gc_bar_hide(FALSE);
00119   if(gamewon == TRUE && pause == FALSE) /* the game is won */
00120     game_won();
00121 
00122   board_paused = pause;
00123 }
00124 
00125 /* =====================================================================
00126  *
00127  * =====================================================================*/
00128 static void start_board (GcomprisBoard *agcomprisBoard) {
00129   if(agcomprisBoard!=NULL) {
00130     gcomprisBoard=agcomprisBoard;
00131     gcomprisBoard->level=1;
00132     gcomprisBoard->maxlevel=LAST_BOARD;
00133     gcomprisBoard->sublevel = 1;
00134     gcomprisBoard->number_of_sublevel = 8;
00135 
00136     gc_bar_set(GC_BAR_LEVEL);
00137     gc_score_start(SCORESTYLE_NOTE,
00138                       gcomprisBoard->width - 220,
00139                       gcomprisBoard->height - 50,
00140                       gcomprisBoard->number_of_sublevel);
00141 
00142     gamewon = FALSE;
00143     errors = MAX_ERRORS;
00144     init_xml();
00145 
00146     gtk_signal_connect(GTK_OBJECT(gcomprisBoard->canvas), "event",  (GtkSignalFunc) item_event, NULL);
00147 
00148     colors_next_level();
00149     pause_board(FALSE);
00150   }
00151 }
00152 
00153 /* =====================================================================
00154  *
00155  * =====================================================================*/
00156 static void end_board () {
00157 
00158   if(gcomprisBoard!=NULL){
00159     pause_board(TRUE);
00160     gc_score_end();
00161     colors_destroy_all_items();
00162     // free list
00163     while (g_list_length(listColors) > 0)
00164       listColors = g_list_remove(listColors, g_list_nth_data(listColors,0));
00165   }
00166   gcomprisBoard = NULL;
00167 }
00168 
00169 /* =====================================================================
00170  *
00171  * =====================================================================*/
00172 static void set_level (guint level) {
00173   if(gcomprisBoard!=NULL) {
00174     gcomprisBoard->level=level;
00175     gcomprisBoard->sublevel=1;
00176     init_xml();
00177     colors_next_level();
00178   }
00179 }
00180 
00181 /* =====================================================================
00182  *
00183  * =====================================================================*/
00184 static gboolean is_our_board (GcomprisBoard *gcomprisBoard) {
00185   if (gcomprisBoard) {
00186     if(g_strcasecmp(gcomprisBoard->type, "advanced_colors")==0) {
00187       /* Set the plugin entry */
00188       gcomprisBoard->plugin=&menu_bp;
00189       return TRUE;
00190     }
00191   }
00192   return FALSE;
00193 }
00194 /* =====================================================================
00195  * set initial values for the next level
00196  * =====================================================================*/
00197 static void colors_next_level() {
00198   gchar *str = NULL;
00199   int i;
00200   GList * list = NULL;
00201   int * item;
00202 
00203   colors_destroy_all_items();
00204   gamewon = FALSE;
00205 
00206   gc_score_set(gcomprisBoard->sublevel);
00207   gc_bar_set_level(gcomprisBoard);
00208 
00209   /* initialize board only once*/
00210   if (gcomprisBoard->sublevel == 1) {
00211     // we generate a list of color indexes in a random order
00212     while (g_list_length(listColors) > 0)
00213       listColors = g_list_remove(listColors, g_list_nth_data(listColors,0));
00214 
00215     for (i=0; i<LAST_COLOR; i++)
00216       list = g_list_append(list, GINT_TO_POINTER(i));
00217 
00218     while ((g_list_length(list) > 0)) {
00219       i = RAND(0,g_list_length(list)-1);
00220       item = g_list_nth_data(list, i);
00221       listColors = g_list_append(listColors, item);
00222       list = g_list_remove(list, item);
00223     }
00224 
00225     /* set background */
00226     str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, backgroundFile);
00227     g_warning("background = %s\n", str);
00228     gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), str);
00229     g_free(str);
00230   }
00231 
00232   colors_create_item(gnome_canvas_root(gcomprisBoard->canvas));
00233 
00234   /* show text of color to find */
00235   color_item = gnome_canvas_item_new (boardRootItem,
00236                                   gnome_canvas_text_get_type (),
00237                                   "text", colors[GPOINTER_TO_INT(g_list_nth_data(listColors,0))],
00238                                   "font", gc_skin_font_board_title_bold,
00239                                   "x", (double) (color_x1+color_x2)/2,
00240                                   "y", (double) (color_y1+color_y2)/2,
00241                                   "anchor", GTK_ANCHOR_CENTER,
00242                                   "fill_color", "darkblue",
00243                                   NULL);
00244 
00245 }
00246 /* =====================================================================
00247  * Destroy all the items
00248  * =====================================================================*/
00249 static void colors_destroy_all_items() {
00250   if(boardRootItem!=NULL)
00251     gtk_object_destroy (GTK_OBJECT(boardRootItem));
00252 
00253   boardRootItem = NULL;
00254 }
00255 
00256 /* =====================================================================
00257  *
00258  * =====================================================================*/
00259 static GnomeCanvasItem *colors_create_item(GnomeCanvasGroup *parent) {
00260   GdkPixbuf *highlight_pixmap = NULL;
00261 
00262   char *str = NULL;
00263   int i;
00264 
00265   boardRootItem = GNOME_CANVAS_GROUP(
00266                                  gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
00267                                                      gnome_canvas_group_get_type (),
00268                                                      "x", (double) 0,
00269                                                      "y", (double) 0,
00270                                                      NULL));
00271 
00272   str = g_strdup_printf("%s/%s", gcomprisBoard->boarddir, "advanced_colors_highlight.png");
00273   highlight_pixmap = gc_pixmap_load(str);
00274 
00275   highlight_image_item = gnome_canvas_item_new (boardRootItem,
00276                                           gnome_canvas_pixbuf_get_type (),
00277                                           "pixbuf", highlight_pixmap,
00278                                           "x", (double) 0,
00279                                           "y", (double) 0,
00280                                           "width", (double) gdk_pixbuf_get_width(highlight_pixmap),
00281                                           "height", (double) gdk_pixbuf_get_height(highlight_pixmap),
00282                                           "width_set", TRUE,
00283                                           "height_set", TRUE,
00284                                           NULL);
00285 
00286   highlight_width = gdk_pixbuf_get_width(highlight_pixmap);
00287   highlight_height = gdk_pixbuf_get_height(highlight_pixmap);
00288 
00289   g_free(str);
00290   gnome_canvas_item_hide(highlight_image_item);
00291   i = RAND(0,LAST_COLOR);
00292 
00293   gdk_pixbuf_unref(highlight_pixmap);
00294 
00295   /* setup the clock */
00296   str = g_strdup_printf("%s%d.png", "gcompris/timers/clock",errors);
00297   clock_pixmap = gc_pixmap_load(str);
00298 
00299   clock_image_item = gnome_canvas_item_new (boardRootItem,
00300                                        gnome_canvas_pixbuf_get_type (),
00301                                        "pixbuf", clock_pixmap,
00302                                        "x", (double) CLOCK_X,
00303                                        "y", (double) CLOCK_Y,
00304                                        "width", (double) gdk_pixbuf_get_width(clock_pixmap),
00305                                        "height", (double) gdk_pixbuf_get_height(clock_pixmap),
00306                                        "width_set", TRUE,
00307                                        "height_set", TRUE,
00308                                        NULL);
00309 
00310   g_free(str);
00311 
00312   return NULL;
00313 }
00314 /* =====================================================================
00315  *
00316  * =====================================================================*/
00317 static void game_won() {
00318 
00319   listColors = g_list_remove(listColors, g_list_nth_data(listColors,0));
00320 
00321   if( g_list_length(listColors) <= 0 ) { // the current board is finished
00322     gcomprisBoard->level++;
00323     gcomprisBoard->sublevel = 1;
00324     if (gcomprisBoard->level > gcomprisBoard->maxlevel) {
00325       gc_bonus_end_display(BOARD_FINISHED_TUXLOCO);
00326       return;
00327     }
00328 
00329     init_xml();
00330   } else { // the current board is not finished
00331     gcomprisBoard->sublevel++;
00332   }
00333 
00334   colors_next_level();
00335 }
00336 /* =====================================================================
00337  *
00338  * =====================================================================*/
00339 static gboolean ok_timeout() {
00340   g_warning("+++ ok_timeout errors = %d\n", errors);
00341   gc_bonus_display(gamewon, BONUS_SMILEY);
00342   if (!gamewon)
00343     errors--;
00344   if (errors <1)
00345     errors = 1;
00346   update_clock();
00347 
00348   if (errors <= 1) {
00349     gc_bonus_end_display(BOARD_FINISHED_TOOMANYERRORS);
00350   }
00351 
00352   return FALSE;
00353 }
00354 
00355 static void ok() {
00356   gc_bar_hide(TRUE);
00357   // leave time to display the right answer
00358   g_timeout_add(TIME_CLICK_TO_BONUS, ok_timeout, NULL);
00359 }
00360 
00361 /* =====================================================================
00362  *
00363  * =====================================================================*/
00364 static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
00365   double x, y;
00366   int i, j, clicked;
00367 
00368   x = event->button.x;
00369   y = event->button.y;
00370 
00371   if (!gcomprisBoard || board_paused)
00372     return FALSE;
00373 
00374   switch (event->type)
00375     {
00376     case GDK_BUTTON_PRESS:
00377       gnome_canvas_c2w (gcomprisBoard->canvas, x, y, &x, &y);
00378       clicked = -1;
00379       for (i=0; i<4; i++) {
00380        for (j=0; j<2; j++) {
00381          if (x>X[i*2] && x<X[i*2+1] && y>Y[j*2] && y<Y[j*2+1]) {
00382            clicked = j*4 + i;
00383          }
00384        }
00385       }
00386       if (clicked >= 0) {
00387        board_paused = TRUE;
00388        highlight_selected(clicked);
00389        gamewon = (clicked == GPOINTER_TO_INT(g_list_nth_data(listColors,0)));
00390        ok();
00391       }
00392       break;
00393 
00394     default:
00395       break;
00396     }
00397   return FALSE;
00398 }
00399 
00400 /* =====================================================================
00401  *
00402  * =====================================================================*/
00403 static void update_clock() {
00404   char *str = g_strdup_printf("%s%d.png", "gcompris/timers/clock",errors);
00405 
00406   gtk_object_destroy (GTK_OBJECT(clock_image_item));
00407 
00408   clock_pixmap = gc_pixmap_load(str);
00409 
00410   clock_image_item = gnome_canvas_item_new (boardRootItem,
00411                                        gnome_canvas_pixbuf_get_type (),
00412                                        "pixbuf", clock_pixmap,
00413                                        "x", (double) CLOCK_X,
00414                                        "y", (double) CLOCK_Y,
00415                                        "width", (double) gdk_pixbuf_get_width(clock_pixmap),
00416                                        "height", (double) gdk_pixbuf_get_height(clock_pixmap),
00417                                        "width_set", TRUE,
00418                                        "height_set", TRUE,
00419                                        NULL);
00420 
00421   gdk_pixbuf_unref(clock_pixmap);
00422   g_free(str);
00423 }
00424 /* =====================================================================
00425  *
00426  * =====================================================================*/
00427 static void highlight_selected(int c) {
00428   int x, y;
00429 
00430   g_assert(c>=0 && c<8);
00431 
00432   x = (X[c*2] + X[c*2+1]) /2;
00433   y = (Y[(int)(c/4)*2] + Y[(int)(c/4)*2+1]) /2;
00434 
00435   x -= highlight_width/2;
00436   y -= highlight_height;
00437   gnome_canvas_item_show(highlight_image_item);
00438   gc_item_absolute_move(highlight_image_item, x, y);
00439 }
00440 
00441 /* ===================================
00442  *                XML stuff
00443  * ==================================== */
00444 static void init_xml()
00445 {
00446   char *filename;
00447 
00448   filename = gc_file_find_absolute("%s/board%d.xml",
00449                           gcomprisBoard->boarddir,
00450                           gcomprisBoard->level);
00451 
00452   g_assert(read_xml_file(filename)== TRUE);
00453 
00454   g_free(filename);
00455 }
00456 
00457 /* ==================================== */
00458 static void add_xml_data(xmlDocPtr doc, xmlNodePtr xmlnode, GNode * child)
00459 {
00460   char *text = NULL;
00461   char *sColor = NULL;
00462   int i;
00463 
00464   xmlnode = xmlnode->xmlChildrenNode;
00465 
00466   xmlnode = xmlnode->next;
00467 
00468   while (xmlnode != NULL)
00469     {
00470       if (!strcmp((char *)xmlnode->name, "pixmapfile"))
00471        backgroundFile = (char *)xmlNodeListGetString(doc, xmlnode->xmlChildrenNode, 1);
00472 
00473       // try to match color[i]
00474       for (i=0; i<8; i++)
00475        {
00476          sColor = g_strdup_printf("color%d", i+1);
00477          if (!strcmp((char *)xmlnode->name, sColor))
00478            {
00479              colors[i] = gettext((char *)xmlNodeListGetString(doc, xmlnode->xmlChildrenNode, 1));
00480              g_free(sColor);
00481              break;
00482            }
00483          g_free(sColor);
00484        } // end for
00485       xmlnode = xmlnode->next;
00486     }
00487 
00488   // I really don't know why this test, but otherwise, the list is doubled
00489   // with 1 line on 2 filled with NULL elements
00490   if ( backgroundFile == NULL || text == NULL)
00491     return;
00492 
00493 }
00494 
00495 /* ==================================== */
00496 static void parse_doc(xmlDocPtr doc)
00497 {
00498   xmlNodePtr node;
00499 
00500   for(node = doc->children->children; node != NULL; node = node->next) {
00501     if ( g_strcasecmp((char *)node->name, "Board") == 0 )
00502       add_xml_data(doc, node, NULL);
00503   }
00504 
00505 }
00506 /* ==================================== */
00507 /* read an xml file into our memory structures and update our view,
00508    dump any old data we have in memory if we can load a new set */
00509 static gboolean read_xml_file(char *fname)
00510 {
00511   /* pointer to the new doc */
00512   xmlDocPtr doc;
00513 
00514   g_return_val_if_fail(fname!=NULL,FALSE);
00515 
00516   /* parse the new file and put the result into newdoc */
00517   doc = gc_net_load_xml(fname);
00518 
00519   /* in case something went wrong */
00520   if(!doc)
00521     return FALSE;
00522 
00523   if(/* if there is no root element */
00524      !doc->children ||
00525      /* if it doesn't have a name */
00526      !doc->children->name ||
00527      /* if it isn't a ImageId node */
00528      g_strcasecmp((char *)doc->children->name,"AdvancedColors")!=0) {
00529     xmlFreeDoc(doc);
00530     return FALSE;
00531   }
00532 
00533   parse_doc(doc);
00534   xmlFreeDoc(doc);
00535   return TRUE;
00536 }
00537