Back to index

gcompris  8.2.2
memory.c
Go to the documentation of this file.
00001 /* gcompris - memory.c
00002  *
00003  * Time-stamp: <2006/08/21 23:33:28 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 
00022 // FIXME: Cleanup of MemoryItem created struct is not done
00023 
00024 #include <errno.h>
00025 #include <string.h>
00026 
00027 #include "gcompris/gcompris.h"
00028 
00029 
00030 #define SOUNDLISTFILE PACKAGE
00031 #define MAX_MEMORY_WIDTH  7
00032 #define MAX_MEMORY_HEIGHT 6
00033 
00034 //#define TEXT_FONT gc_skin_font_board_huge_bold
00035 #define TEXT_FONT "Serif bold 28"
00036 
00037 static gchar *op_fonts[10] =
00038   {
00039     "",
00040     "Serif bold 28",
00041     "Serif bold 24",
00042     "Serif bold 20",
00043     "Serif bold 20",
00044     "Serif bold 17",
00045     "Serif bold 13",
00046     "Serif bold 13",
00047     "Serif bold 13",
00048     "Serif bold 11",
00049   };
00050 
00051 static GcomprisBoard *gcomprisBoard = NULL;
00052 
00053 static GnomeCanvasGroup *boardRootItem = NULL;
00054 
00055 static gint win_id = 0;
00056 
00057 typedef enum
00058 {
00059   MODE_NORMAL        = 0,
00060   MODE_TUX              = 1,
00061 } Mode;
00062 static Mode currentMode = MODE_NORMAL;
00063 
00064 typedef enum
00065 {
00066   UIMODE_NORMAL             = 0,
00067   UIMODE_SOUND          = 1,
00068 } UiMode;
00069 static UiMode currentUiMode = UIMODE_NORMAL;
00070 
00071 typedef enum
00072 {
00073   BOARDMODE_NORMAL            = 0,
00074   BOARDMODE_SOUND                = 1,
00075   BOARDMODE_ADD                  = 2,
00076   BOARDMODE_MINUS                = 3,
00077   BOARDMODE_MULT                 = 4,
00078   BOARDMODE_DIV                  = 5,
00079   BOARDMODE_ADD_MINUS            = 6,
00080   BOARDMODE_MULT_DIV             = 7,
00081   BOARDMODE_ADD_MINUS_MULT_DIV   = 8,
00082 } BoardMode;
00083 static BoardMode currentBoardMode = BOARDMODE_NORMAL;
00084 
00085 typedef enum
00086 {
00087   ON_FRONT           = 0,
00088   ON_BACK            = 1,
00089   HIDDEN             = 2
00090 } CardStatus;
00091 
00092 static gchar *numbers;
00093 static gchar *alphabet_lowercase;
00094 static gchar *alphabet_uppercase;
00095 static gchar *operators;
00096 static gchar *op_add;
00097 static gchar *op_minus;
00098 static gchar *op_mult;
00099 static gchar *op_div;
00100 
00101 typedef struct {
00102   gchar *data;
00103   gint type;
00104   guint status;
00105   GnomeCanvasItem *rootItem;
00106   GnomeCanvasItem *backcardItem;
00107   GnomeCanvasItem *framecardItem;
00108   GnomeCanvasItem *frontcardItem;
00109   gboolean hidden;
00110   gchar *second_value;
00111 } MemoryItem;
00112 
00113 static MemoryItem *firstCard = NULL;
00114 static MemoryItem *secondCard = NULL;
00115 
00116 /* Define the page area where memory cards can be displayed for CARD MODE */
00117 #define BASE_CARD_X1 50
00118 #define BASE_CARD_Y1 50
00119 #define BASE_CARD_X2 790
00120 #define BASE_CARD_Y2 500
00121 #define BASE_CARD_X1_TUX 200
00122 
00123 /* Define the page area where memory cards can be displayed for SOUND MODE */
00124 #define BASE_SOUND_X1 250
00125 #define BASE_SOUND_Y1 30
00126 #define BASE_SOUND_X2 600
00127 #define BASE_SOUND_Y2 200
00128 #define BASE_SOUND_X1_TUX BASE_SOUND_X1
00129 
00130 /* The current page area where memory cards can be displayed */
00131 gint base_x1;
00132 gint base_y1;
00133 gint base_x2;
00134 gint base_y2;
00135 gint base_x1_tux;
00136 
00137 gint current_x;
00138 gint current_y;
00139 gint numberOfLine;
00140 gint numberOfColumn;
00141 gint remainingCards;
00142 
00143 static void start_board (GcomprisBoard *agcomprisBoard);
00144 static void pause_board (gboolean pause);
00145 static void end_board (void);
00146 static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
00147 static void set_level (guint level);
00148 
00149 static void create_item(GnomeCanvasGroup *parent);
00150 static void memory_destroy_all_items(void);
00151 static void memory_next_level(void);
00152 static gint item_event(GnomeCanvasItem *item, GdkEvent *event, MemoryItem *memoryItem);
00153 static gint compare_card (gconstpointer a, gconstpointer b);
00154 
00155 static void player_win();
00156 
00157 static void display_card(MemoryItem *memoryItem, CardStatus cardStatus);
00158 
00159 static void sound_callback(gchar *file);
00160 static void start_callback(gchar *file);
00161 static gboolean playing_sound = FALSE;
00162 
00163 // Number of images for x and y by level
00164 static guint levelDescription[] =
00165 {
00166   0,0,
00167   3,2,
00168   4,2,
00169   4,3,
00170   4,4,
00171   4,4,
00172   5,4,
00173   6,4,
00174   6,5,
00175   MAX_MEMORY_WIDTH,MAX_MEMORY_HEIGHT
00176 };
00177 
00178 static MemoryItem *memoryArray[MAX_MEMORY_WIDTH][MAX_MEMORY_HEIGHT];
00179 
00180 /* List of images to use in the memory */
00181 static gchar *imageList[] =
00182 {
00183   "gcompris/misc/apple.png",
00184   "gcompris/misc/bicycle.png",
00185   "gcompris/misc/bottle.png",
00186   "gcompris/misc/carot.png",
00187   "gcompris/misc/car.png",
00188   "gcompris/misc/castle.png",
00189   "gcompris/misc/cerise.png",
00190   "gcompris/misc/cocotier.png",
00191   "gcompris/misc/crown.png",
00192   "gcompris/misc/egg.png",
00193   "gcompris/misc/eggpot.png",
00194   "gcompris/misc/fishingboat.png",
00195   "gcompris/misc/flower.png",
00196   "gcompris/misc/flowerpot.png",
00197   "gcompris/misc/football.png",
00198   "gcompris/misc/fusee.png",
00199   "gcompris/misc/glass.png",
00200   "gcompris/misc/house.png",
00201   "gcompris/misc/lamp.png",
00202   "gcompris/misc/lighthouse.png",
00203   "gcompris/misc/light.png",
00204   "gcompris/misc/minivan.png",
00205   "gcompris/misc/peer.png",
00206   "gcompris/misc/pencil.png",
00207   "gcompris/misc/plane.png",
00208   "gcompris/misc/postcard.png",
00209   "gcompris/misc/postpoint.png",
00210   "gcompris/misc/rape.png",
00211   "gcompris/misc/raquette.png",
00212   "gcompris/misc/sailingboat.png",
00213   "gcompris/misc/sapin.png",
00214   "gcompris/misc/sofa.png",
00215   "gcompris/misc/star.png",
00216   "gcompris/misc/strawberry.png",
00217   "gcompris/misc/tree.png",
00218   "gcompris/misc/truck.png",
00219   "gcompris/misc/tuxplane.png",
00220   "gcompris/misc/tux.png",
00221   "gcompris/misc/windflag0.png",
00222   "gcompris/misc/windflag4.png",
00223   "gcompris/misc/windflag5.png",
00224 };
00225 #define NUMBER_OF_IMAGES G_N_ELEMENTS(imageList)
00226 
00227 /* List of images to use in the memory */
00228 static gchar *soundList[] =
00229 {
00230    "sounds/LuneRouge/animaux/LRRain_in_garden_01_by_Lionel_Allorge_cut.ogg",
00231    "sounds/LuneRouge/animaux/LRBark_1_by_Lionel_Allorge_cut.ogg",
00232    "sounds/LuneRouge/animaux/LRBark_3_by_Lionel_Allorge_cut.ogg",
00233    "sounds/LuneRouge/animaux/LRFrogsInPondDuringStormByLionelAllorgeCut.ogg",
00234    "sounds/LuneRouge/engins/LRObject_falling_02_by_Lionel_Allorge.ogg",
00235    "sounds/LuneRouge/engins/LRTrain_slowing_down_01_by_Lionel_Allorge_cut.ogg",
00236    "sounds/LuneRouge/engins/LRStartAndStopCarEngine1ByLionelAllorgeCut.ogg",
00237    "sounds/LuneRouge/engins/LRObject_falling_01_by_Lionel_Allorge.ogg",
00238    "sounds/LuneRouge/humain/LRApplauses_1_by_Lionel_Allorge_cut.ogg",
00239    "sounds/LuneRouge/humain/LRHeart_beat_01_by_Lionel_Allorge.ogg",
00240    "sounds/LuneRouge/maison/LRDoor_Open_2_by_Lionel_Allorge.ogg",
00241    "sounds/LuneRouge/maison/LRRing_01_by_Lionel_Allorge.ogg",
00242    "sounds/LuneRouge/musique/LRBuddhist_gong_05_by_Lionel_Allorge.ogg",
00243    "sounds/LuneRouge/sf/LRWeird_4_by_Lionel_Allorge.ogg",
00244    "sounds/LuneRouge/sf/LRWeird_1_by_Lionel_Allorge.ogg",
00245    "sounds/LuneRouge/sf/LRWeird_2_by_Lionel_Allorge.ogg",
00246    "sounds/LuneRouge/sf/LRWeird_3_by_Lionel_Allorge.ogg",
00247    "sounds/LuneRouge/sf/LRWeird_5_by_Lionel_Allorge.ogg",
00248    "sounds/LuneRouge/sf/LRWeird_6_by_Lionel_Allorge.ogg",
00249    "sounds/LuneRouge/sf/LRET_phone_home_01_by_Lionel_Allorge_cut.ogg",
00250    "sounds/LuneRouge/usine/LRFactory_noise_02_by_Lionel_Allorge.ogg",
00251    "sounds/LuneRouge/usine/LRFactory_noise_03_by_Lionel_Allorge.ogg",
00252    "sounds/LuneRouge/usine/LRFactory_noise_04_by_Lionel_Allorge.ogg",
00253    "sounds/LuneRouge/usine/LRFactory_noise_05_by_Lionel_Allorge.ogg",
00254    "sounds/LuneRouge/usine/LRFactory_noise_06_by_Lionel_Allorge.ogg",
00255    "sounds/LuneRouge/usine/LRHits_01_by_Lionel_Allorge.ogg",
00256    "sounds/LuneRouge/usine/LRFireballs_01_by_Lionel_Allorge.ogg",
00257    "sounds/LuneRouge/usine/LRFactory_noise_01_by_Lionel_Allorge.ogg",
00258    "sounds/LuneRouge/LRLaPause_short.ogg",
00259    "sounds/memory/plick.ogg",
00260    "sounds/memory/tick.ogg",
00261    "sounds/memory/tri.ogg",
00262    "sounds/chronos/space/1.ogg",
00263    "sounds/chronos/space/2.ogg",
00264    "sounds/chronos/space/2.ogg",
00265    "sounds/melody/guitar/melody.ogg",
00266    "sounds/melody/guitar/son1.ogg",
00267    "sounds/melody/guitar/son2.ogg",
00268    "sounds/melody/guitar/son3.ogg",
00269    "sounds/melody/guitar/son4.ogg",
00270    "sounds/melody/tachos/son1.ogg",
00271    "sounds/melody/tachos/son2.ogg",
00272    "sounds/melody/tachos/son3.ogg",
00273    "sounds/melody/tachos/son4.ogg",
00274    "sounds/melody/tachos/melody.ogg"
00275 };
00276 
00277 #define NUMBER_OF_SOUNDS G_N_ELEMENTS(soundList)
00278 
00279 static SoundPolicy sound_policy;
00280 
00281 /* Description of this plugin */
00282 static BoardPlugin menu_bp =
00283 {
00284    NULL,
00285    NULL,
00286    N_("Memory"),
00287    N_("Find the matching pair"),
00288    "Bruno Coudoin <bruno.coudoin@free.fr>",
00289    NULL,
00290    NULL,
00291    NULL,
00292    NULL,
00293    start_board,
00294    pause_board,
00295    end_board,
00296    is_our_board,
00297    NULL,
00298    NULL,
00299    set_level,
00300    NULL,
00301    NULL,
00302    NULL,
00303    NULL
00304 };
00305 
00306 
00307 /*
00308  * Against computer version
00309  * ------------------------
00310  *
00311  */
00312 
00313 static gboolean to_tux = FALSE;
00314 static GQueue *tux_memory;
00315 static gint tux_memory_size;
00316 static gint tux_memory_sizes[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
00317 static gint tux_pairs = 0;
00318 static gint player_pairs = 0;
00319 
00320 static void add_card_in_tux_memory(MemoryItem *card);
00321 static MemoryItem *find_card_in_tux_memory(MemoryItem *card);
00322 static void remove_card_from_tux_memory(MemoryItem *card);
00323 static gint tux_play();
00324 
00325 typedef struct {
00326   MemoryItem *first;
00327   MemoryItem *second;
00328 } WINNING;
00329 
00330 static GList *winning_pairs = NULL;
00331 
00332 static gint tux_id = 0;
00333 
00334 /*
00335  *
00336  * Operation versions
00337  *
00338  */
00339 
00340 
00341 /*  max number 1 / max number 2 */
00342 /*  to allow level with calculus like 7*12 */
00343 
00344 static guint add_levelDescription[10][2] =
00345 {
00346   {0,0},
00347   {5,5},
00348   {5,7},
00349   {7,7},
00350   {7,10},
00351   {10,10},
00352   {10,15},
00353   {15,15},
00354   {25,25},
00355   {50,50},
00356 };
00357 
00358 static guint minus_levelDescription[10][2] =
00359 {
00360   {0,0},
00361   {5,5},
00362   {5,7},
00363   {7,7},
00364   {7,10},
00365   {10,10},
00366   {10,15},
00367   {15,15},
00368   {25,25},
00369   {50,50},
00370 };
00371 
00372 
00373 static guint mult_levelDescription[10][2] =
00374 {
00375   {0,0},
00376   {5,5},
00377   {5,7},
00378   {7,7},
00379   {7,10},
00380   {10,10},
00381   {12,12},
00382   {15,15},
00383   {20,20},
00384   {25,25},
00385 };
00386 
00387 static guint div_levelDescription[10][2] =
00388 {
00389   {0,0},
00390   {5,5},
00391   {5,7},
00392   {7,7},
00393   {7,10},
00394   {10,10},
00395   {12,12},
00396   {15,15},
00397   {20,20},
00398   {25,25},
00399 };
00400 
00401 
00402 /*
00403  * random without repeted token
00404  * ------------------------
00405  *
00406  */
00407 
00408 #define TYPE_IMAGE     1
00409 #define TYPE_NUMBER    2
00410 #define TYPE_UPPERCASE 4
00411 #define TYPE_LOWERCASE 8
00412 #define TYPE_SOUND     16
00413 #define TYPE_ADD       32
00414 #define TYPE_MINUS     64
00415 #define TYPE_MULT      128
00416 #define TYPE_DIV       256
00417 
00418 static GList *passed_token = NULL;
00419 
00420 static GnomeCanvasItem *tux;
00421 static GnomeCanvasItem *tux_score;
00422 static GnomeCanvasItem *player_score;
00423 static GnomeCanvasItem *tux_score_s;
00424 static GnomeCanvasItem *player_score_s;
00425 
00426 /* set the type of the token returned in string in returned_type */
00427 void get_random_token(int token_type, gint *returned_type, gchar **string, gchar **second_value)
00428 {
00429   gchar *result = NULL;
00430   gchar *second = NULL;
00431   gboolean skip;
00432 
00433   gint max_token;
00434   gint j, i, k;
00435   gint type;
00436 
00437   typedef struct {
00438     gint bound;
00439     gint type;
00440   } DATUM ;
00441 
00442   GList *data= NULL;
00443   GList *list;
00444 
00445   max_token = 0;
00446 
00447   if (token_type & TYPE_IMAGE){
00448     max_token += NUMBER_OF_IMAGES;
00449 
00450     DATUM *dat = g_malloc0(sizeof(DATUM));
00451     dat->bound = max_token;
00452     dat->type =  TYPE_IMAGE;
00453     data = g_list_append(data, dat);
00454   }
00455 
00456   if (token_type & TYPE_NUMBER) {
00457     max_token += g_utf8_strlen (numbers, -1);
00458     DATUM *dat = g_malloc0(sizeof(DATUM));
00459     dat->bound = max_token;
00460     dat->type =  TYPE_NUMBER;
00461     data = g_list_append(data, dat);
00462   }
00463 
00464   if (token_type & TYPE_UPPERCASE){
00465     max_token += g_utf8_strlen (alphabet_uppercase, -1);
00466     DATUM *dat = g_malloc0(sizeof(DATUM));
00467     dat->bound = max_token;
00468     dat->type =   TYPE_UPPERCASE;
00469     data = g_list_append(data, dat);
00470   }
00471 
00472   if (token_type & TYPE_LOWERCASE){
00473     max_token += g_utf8_strlen (alphabet_lowercase, -1);;
00474     DATUM *dat = g_malloc0(sizeof(DATUM));
00475     dat->bound = max_token;
00476     dat->type =   TYPE_LOWERCASE;
00477     data = g_list_append(data, dat);
00478   }
00479 
00480 
00481   if (token_type & TYPE_SOUND){
00482     max_token += NUMBER_OF_SOUNDS;
00483     DATUM *dat = g_malloc0(sizeof(DATUM));
00484     dat->bound = max_token;
00485     dat->type =   TYPE_SOUND;
00486     data = g_list_append(data, dat);
00487   }
00488 
00489   if (token_type & TYPE_ADD){
00490     max_token += (add_levelDescription[gcomprisBoard->level][0]+1)*(add_levelDescription[gcomprisBoard->level][1]+1);
00491     DATUM *dat = g_malloc0(sizeof(DATUM));
00492     dat->bound = max_token;
00493     dat->type =   TYPE_ADD;
00494     data = g_list_append(data, dat);
00495   }
00496 
00497   if (token_type & TYPE_MINUS){
00498     max_token += (minus_levelDescription[gcomprisBoard->level][0]+1)*(minus_levelDescription[gcomprisBoard->level][1]+1);
00499     DATUM *dat = g_malloc0(sizeof(DATUM));
00500     dat->bound = max_token;
00501     dat->type =   TYPE_MINUS;
00502     data = g_list_append(data, dat);
00503   }
00504 
00505   if (token_type & TYPE_MULT){
00506    max_token += (mult_levelDescription[gcomprisBoard->level][0]+1)*(mult_levelDescription[gcomprisBoard->level][1]+1);
00507     DATUM *dat = g_malloc0(sizeof(DATUM));
00508     dat->bound = max_token;
00509     dat->type =   TYPE_MULT;
00510     data = g_list_append(data, dat);
00511   }
00512 
00513   if (token_type & TYPE_DIV){
00514     max_token += (div_levelDescription[gcomprisBoard->level][0]+1)*(div_levelDescription[gcomprisBoard->level][1]+1);
00515     DATUM *dat = g_malloc0(sizeof(DATUM));
00516     dat->bound = max_token;
00517     dat->type =   TYPE_DIV;
00518     data = g_list_append(data, dat);
00519   }
00520 
00521 
00522 
00523   g_assert(max_token >0);
00524 
00525   i = rand()%max_token;
00526 
00527   for (list = data; list != NULL; list = list->next)
00528     if ( i < ((DATUM *)list->data)->bound)
00529       break;
00530 
00531   j=-1;
00532 
00533   do {
00534     skip = FALSE;
00535     g_free(result);
00536     result = NULL;
00537     g_free(second);
00538     j++;
00539 
00540     if ((i+j) == max_token) {
00541       list = data;
00542     }
00543 
00544     if ((i+j)%max_token == ((DATUM *)list->data)->bound)
00545       list = list->next;
00546 
00547     /* calculate index in right table */
00548     k = (i+j)%max_token - (list->prev ? ((DATUM *)list->prev->data)->bound : 0);
00549 
00550 
00551     type = ((DATUM *)list->data)->type;
00552 
00553     switch (type) {
00554     case TYPE_IMAGE:
00555       result= g_strdup(imageList[k]);
00556       break;
00557     case TYPE_NUMBER:
00558       result = g_malloc0(2*sizeof(gunichar));
00559       g_utf8_strncpy(result, g_utf8_offset_to_pointer (numbers,k),1);
00560       break;
00561     case TYPE_UPPERCASE:
00562       result = g_malloc0(2*sizeof(gunichar));
00563       g_utf8_strncpy(result, g_utf8_offset_to_pointer (alphabet_uppercase,k),1);
00564       break;
00565     case TYPE_LOWERCASE:
00566       result = g_malloc0(2*sizeof(gunichar));
00567       g_utf8_strncpy(result, g_utf8_offset_to_pointer (alphabet_lowercase,k),1);
00568       break;
00569     case TYPE_SOUND:
00570       result = g_strdup(soundList[k]);
00571       break;
00572     case TYPE_ADD:
00573       {
00574        int i, j;
00575        i = k %  add_levelDescription[gcomprisBoard->level][0];
00576        j = k /  add_levelDescription[gcomprisBoard->level][0];
00577        result = g_strdup_printf("%d%s%d",i,op_add,j);
00578        second = g_strdup_printf("%d",i+j);;
00579        break;
00580       }
00581     case TYPE_MINUS:
00582       {
00583        int i, j;
00584        i = k %  minus_levelDescription[gcomprisBoard->level][0];
00585        j = k /  minus_levelDescription[gcomprisBoard->level][0];
00586        result = g_strdup_printf("%d%s%d",i+j,op_minus,i);
00587        second = g_strdup_printf("%d",j);;
00588        break;
00589       }
00590     case TYPE_MULT:
00591       {
00592        int i, j;
00593        i = k %  mult_levelDescription[gcomprisBoard->level][0];
00594        j = k /  mult_levelDescription[gcomprisBoard->level][0];
00595        result = g_strdup_printf("%d%s%d",i,op_mult,j);
00596        second = g_strdup_printf("%d",i*j);;
00597        break;
00598       }
00599     case TYPE_DIV:
00600       {
00601        int i1, i2;
00602        i1 = k %  div_levelDescription[gcomprisBoard->level][0];
00603        if (i1==0) skip=TRUE;
00604        i2 = k /  div_levelDescription[gcomprisBoard->level][0];
00605        result = g_strdup_printf("%d%s%d",i1*i2,op_div,i1);
00606        second = g_strdup_printf("%d",i2);
00607        break;
00608       }
00609     default:
00610       /* should never append */
00611       g_error("never !");
00612       break;
00613     }
00614 
00615   } while (skip || ((j < max_token )
00616           && (passed_token && result && g_list_find_custom(passed_token, result, (GCompareFunc)strcmp))));
00617 
00618   g_assert (j < max_token);
00619 
00620   passed_token = g_list_append( passed_token, result);
00621 
00622   *returned_type = type;
00623 
00624   *string = result;
00625 
00626   if (second_value)
00627     *second_value = second;
00628 
00629   for (list = data; list != NULL; list=list->next)
00630     g_free(list->data);
00631 
00632   g_list_free(data);
00633 
00634 }
00635 
00636 
00637 
00638 
00639 /*
00640  * Main entry point mandatory for each Gcompris's game
00641  * ---------------------------------------------------
00642  *
00643  */
00644 
00645 GET_BPLUGIN_INFO(memory)
00646 
00647 /*
00648  * in : boolean TRUE = PAUSE : FALSE = UNPAUSE
00649  *
00650  */
00651 
00652 static gboolean Paused = FALSE;
00653 
00654 static void pause_board (gboolean pause)
00655 {
00656 
00657   if(gcomprisBoard==NULL)
00658     return;
00659 
00660   Paused = pause;
00661 
00662   if(pause){
00663     if (currentMode == MODE_TUX){
00664       if (tux_id){
00665        g_source_remove(tux_id);
00666        tux_id = 0;
00667       }
00668     }
00669   }
00670   else {
00671     if (remainingCards<=0)
00672       memory_next_level();
00673     else {
00674       if (currentMode == MODE_TUX){
00675        if (to_tux){
00676          tux_id = g_timeout_add (2000,
00677                               (GSourceFunc) tux_play, NULL);
00678        }
00679       }
00680     }
00681 
00682   }
00683 }
00684 /*
00685  */
00686 static void start_board (GcomprisBoard *agcomprisBoard)
00687 {
00688 
00689   if(agcomprisBoard!=NULL)
00690     {
00691       gcomprisBoard=agcomprisBoard;
00692 
00693       gcomprisBoard->level = 1;
00694       gcomprisBoard->maxlevel = 9;
00695       gc_bar_set(GC_BAR_LEVEL);
00696 
00697       /* Default mode */
00698 
00699       if(!gcomprisBoard->mode){
00700        currentMode=MODE_NORMAL;
00701        currentUiMode=UIMODE_NORMAL;
00702        currentBoardMode=BOARDMODE_NORMAL;
00703       } else {
00704        if(g_strcasecmp(gcomprisBoard->mode, "tux")==0){
00705          currentMode=MODE_TUX;
00706          currentUiMode=UIMODE_NORMAL;
00707          currentBoardMode=BOARDMODE_NORMAL;
00708        } else {
00709          if(g_strcasecmp(gcomprisBoard->mode, "sound")==0){
00710            currentMode=MODE_NORMAL;
00711            currentUiMode=UIMODE_SOUND;
00712            currentBoardMode=BOARDMODE_SOUND;
00713          } else {
00714            if(g_strcasecmp(gcomprisBoard->mode, "sound_tux")==0){
00715              currentMode=MODE_TUX;
00716              currentUiMode=UIMODE_SOUND;
00717              currentBoardMode=BOARDMODE_SOUND;
00718            } else {
00719              if(g_strcasecmp(gcomprisBoard->mode, "add")==0){
00720               currentMode=MODE_NORMAL;
00721               currentUiMode=UIMODE_NORMAL;
00722               currentBoardMode=BOARDMODE_ADD;
00723              } else {
00724               if(g_strcasecmp(gcomprisBoard->mode, "add_tux")==0){
00725                 currentMode=MODE_TUX;
00726                 currentUiMode=UIMODE_NORMAL;
00727                 currentBoardMode=BOARDMODE_ADD;
00728               } else {
00729                 if(g_strcasecmp(gcomprisBoard->mode, "minus")==0){
00730                   currentMode=MODE_NORMAL;
00731                   currentUiMode=UIMODE_NORMAL;
00732                   currentBoardMode=BOARDMODE_MINUS;
00733                 } else {
00734                   if(g_strcasecmp(gcomprisBoard->mode, "minus_tux")==0){
00735                     currentMode=MODE_TUX;
00736                     currentUiMode=UIMODE_NORMAL;
00737                     currentBoardMode=BOARDMODE_MINUS;
00738                   } else {
00739                     if(g_strcasecmp(gcomprisBoard->mode, "mult")==0){
00740                      currentMode=MODE_NORMAL;
00741                      currentUiMode=UIMODE_NORMAL;
00742                      currentBoardMode=BOARDMODE_MULT;
00743                     } else {
00744                      if(g_strcasecmp(gcomprisBoard->mode, "mult_tux")==0){
00745                        currentMode=MODE_TUX;
00746                        currentUiMode=UIMODE_NORMAL;
00747                        currentBoardMode=BOARDMODE_MULT;
00748                      } else {
00749                        if(g_strcasecmp(gcomprisBoard->mode, "div")==0){
00750                          currentMode=MODE_NORMAL;
00751                          currentUiMode=UIMODE_NORMAL;
00752                          currentBoardMode=BOARDMODE_DIV;
00753                        } else {
00754                          if(g_strcasecmp(gcomprisBoard->mode, "div_tux")==0){
00755                            currentMode=MODE_TUX;
00756                            currentUiMode=UIMODE_NORMAL;
00757                            currentBoardMode=BOARDMODE_DIV;
00758                          } else {
00759                            if(g_strcasecmp(gcomprisBoard->mode, "add_minus")==0){
00760                             currentMode=MODE_NORMAL;
00761                             currentUiMode=UIMODE_NORMAL;
00762                             currentBoardMode=BOARDMODE_ADD_MINUS;
00763                            } else {
00764                             if(g_strcasecmp(gcomprisBoard->mode, "add_minus_tux")==0){
00765                               currentMode=MODE_TUX;
00766                               currentUiMode=UIMODE_NORMAL;
00767                               currentBoardMode=BOARDMODE_ADD_MINUS;
00768                             } else {
00769                               if(g_strcasecmp(gcomprisBoard->mode, "mult_div")==0){
00770                                 currentMode=MODE_NORMAL;
00771                                 currentUiMode=UIMODE_NORMAL;
00772                                 currentBoardMode=BOARDMODE_MULT_DIV;
00773                               } else {
00774                                 if(g_strcasecmp(gcomprisBoard->mode, "mult_div_tux")==0){
00775                                   currentMode=MODE_TUX;
00776                                   currentUiMode=UIMODE_NORMAL;
00777                                   currentBoardMode=BOARDMODE_MULT_DIV;
00778                                 } else {
00779                                   if(g_strcasecmp(gcomprisBoard->mode, "add_minus_mult_div")==0){
00780                                    currentMode=MODE_NORMAL;
00781                                    currentUiMode=UIMODE_NORMAL;
00782                                    currentBoardMode=BOARDMODE_ADD_MINUS_MULT_DIV;
00783                                   } else {
00784                                    if(g_strcasecmp(gcomprisBoard->mode, "add_minus_mult_div_tux")==0){
00785                                      currentMode=MODE_TUX;
00786                                      currentUiMode=UIMODE_NORMAL;
00787                                      currentBoardMode=BOARDMODE_ADD_MINUS_MULT_DIV;
00788                                    } else {
00789                                      currentMode=MODE_NORMAL;
00790                                      currentUiMode=UIMODE_NORMAL;
00791                                      currentBoardMode=BOARDMODE_NORMAL;
00792                                      g_warning("Fallback mode set to images");
00793                                    }
00794                                   }
00795                                 }
00796                               }
00797                             }
00798                            }
00799                          }
00800                        }
00801                      }
00802                     }
00803                   }
00804                 }
00805               }
00806              }
00807            }
00808          }
00809        }
00810       }
00811 
00812 
00813       if (currentUiMode == UIMODE_SOUND)
00814        {
00815          GcomprisProperties *properties = gc_prop_get();
00816 
00817          gc_sound_pause();
00818 
00819          /* initial state to restore */
00820          sound_policy = gc_sound_policy_get();
00821 
00822          gc_sound_policy_set(PLAY_AND_INTERRUPT);
00823 
00824          gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), "images/gcompris_band.png");
00825          base_x1 = BASE_SOUND_X1;
00826          base_y1 = BASE_SOUND_Y1;
00827          base_x2 = BASE_SOUND_X2;
00828          base_y2 = BASE_SOUND_Y2;
00829          base_x1_tux = BASE_SOUND_X1_TUX;
00830 
00831          if(!properties->fx) {
00832            gc_dialog(_("Error: this activity cannot be played with the\nsound effects disabled.\nGo to the configuration dialog to\nenable the sound"), gc_board_stop);
00833            return;
00834          }
00835 
00836        }
00837       else
00838        {
00839          gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), "images/scenery_background.png");
00840          base_x1 = BASE_CARD_X1;
00841          base_y1 = BASE_CARD_Y1;
00842          base_x2 = BASE_CARD_X2;
00843          base_y2 = BASE_CARD_Y2;
00844          base_x1_tux = BASE_CARD_X1_TUX;
00845        }
00846 
00847 
00848       /* TRANSLATORS: Put here the numbers in your language */
00849       numbers=_("0123456789");
00850       g_assert(g_utf8_validate(numbers,-1,NULL)); // require by all utf8-functions
00851 
00852       /* TRANSLATORS: Put here the alphabet lowercase in your language */
00853       alphabet_lowercase=_("abcdefghijklmnopqrstuvwxyz");
00854       g_assert(g_utf8_validate(alphabet_lowercase,-1,NULL)); // require by all utf8-functions
00855 
00856       g_warning("Using lowercase %s", alphabet_lowercase);
00857 
00858       /* TRANSLATORS: Put here the alphabet uppercase in your language */
00859       alphabet_uppercase=_("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
00860       g_assert(g_utf8_validate(alphabet_uppercase,-1,NULL)); // require by all utf8-functions
00861       g_warning("Using uppercase %s", alphabet_uppercase);
00862 
00863       /* TRANSLATORS: Put here the mathematical operators "+-" for  your language. */
00864       operators=_("+-×÷");
00865       g_assert(g_utf8_validate(operators,-1,NULL)); // require by all utf8-functions
00866       g_warning("Using operators %s", operators);
00867 
00868       op_add = g_malloc0(2*sizeof(gunichar));
00869       g_utf8_strncpy(op_add, g_utf8_offset_to_pointer (operators,0),1);
00870 
00871       op_minus = g_malloc0(2*sizeof(gunichar));
00872       g_utf8_strncpy(op_minus, g_utf8_offset_to_pointer (operators,1),1);
00873 
00874       op_mult = g_malloc0(2*sizeof(gunichar));
00875       g_utf8_strncpy(op_mult, g_utf8_offset_to_pointer (operators,2),1);
00876 
00877       op_div = g_malloc0(2*sizeof(gunichar));
00878       g_utf8_strncpy(op_div, g_utf8_offset_to_pointer (operators,3),1);
00879 
00880 
00881       g_warning("Using operators %s %s %s %s", op_add, op_minus,
00882                                              op_mult, op_div);
00883 
00884       if (currentMode == MODE_TUX){
00885        tux_memory_size = tux_memory_sizes[gcomprisBoard->level];
00886        tux_memory = g_queue_new ();
00887       }
00888 
00889       Paused = FALSE;
00890 
00891       to_tux = FALSE;
00892       if (currentUiMode == UIMODE_SOUND){
00893        playing_sound = TRUE;
00894        gc_sound_play_ogg_cb("sounds/LuneRouge/musique/LRBuddhist_gong_05_by_Lionel_Allorge.ogg",start_callback);
00895       } else
00896        playing_sound = FALSE;
00897 
00898       memory_next_level();
00899     }
00900 }
00901 
00902 static void
00903 end_board ()
00904 {
00905   if (currentUiMode == UIMODE_SOUND) {
00906     gc_sound_policy_set(sound_policy);
00907     gc_sound_resume();
00908   }
00909 
00910   if(gcomprisBoard!=NULL)
00911     {
00912       pause_board(TRUE);
00913 
00914       memory_destroy_all_items();
00915       if (currentMode == MODE_TUX){
00916        g_queue_free(tux_memory);
00917        tux_memory = NULL;
00918       }
00919     }
00920   g_free(op_add);
00921   g_free(op_minus);
00922   g_free(op_mult);
00923   g_free(op_div);
00924   
00925   gcomprisBoard = NULL;
00926 }
00927 
00928 static void
00929 set_level (guint level)
00930 {
00931 
00932   if(gcomprisBoard!=NULL)
00933     {
00934       gcomprisBoard->level=level;
00935       memory_next_level();
00936     }
00937 }
00938 
00939 static gboolean
00940 is_our_board (GcomprisBoard *gcomprisBoard)
00941 {
00942   if (gcomprisBoard)
00943     {
00944       if(g_strcasecmp(gcomprisBoard->type, "memory")==0)
00945        {
00946          /* Set the plugin entry */
00947          gcomprisBoard->plugin=&menu_bp;
00948 
00949          return TRUE;
00950        }
00951     }
00952   return FALSE;
00953 }
00954 
00955 
00956 /*-------------------------------------------------------------------------------*/
00957 /*-------------------------------------------------------------------------------*/
00958 /*-------------------------------------------------------------------------------*/
00959 /*-------------------------------------------------------------------------------*/
00960 
00961 static void update_scores()
00962 {
00963   gchar *tux_score_str;
00964   gchar *player_score_str;
00965 
00966   tux_score_str = g_strdup_printf("%d", tux_pairs);
00967   player_score_str = g_strdup_printf("%d", player_pairs);
00968 
00969   gnome_canvas_item_set(tux_score,      "text", tux_score_str, NULL);
00970   gnome_canvas_item_set(player_score,   "text", player_score_str, NULL);
00971   gnome_canvas_item_set(tux_score_s,    "text", tux_score_str, NULL);
00972   gnome_canvas_item_set(player_score_s, "text", player_score_str, NULL);
00973 
00974   g_free(tux_score_str);
00975   g_free(player_score_str);
00976 }
00977 
00978 /* set initial values for the next level */
00979 static void memory_next_level()
00980 {
00981   gc_bar_set_level(gcomprisBoard);
00982 
00983   memory_destroy_all_items();
00984 
00985   boardRootItem = GNOME_CANVAS_GROUP(
00986                                  gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
00987                                                      gnome_canvas_group_get_type (),
00988                                                      "x", (double) 0,
00989                                                      "y", (double) 0,
00990                                                      NULL));
00991 
00992   numberOfColumn = levelDescription[gcomprisBoard->level*2];
00993   numberOfLine   = levelDescription[gcomprisBoard->level*2+1];
00994   remainingCards = numberOfColumn * numberOfLine;
00995 
00996   gcomprisBoard->number_of_sublevel=1;
00997   gcomprisBoard->sublevel=0;
00998 
00999   create_item(boardRootItem);
01000 
01001   if (currentMode == MODE_TUX){
01002        tux_memory_size = tux_memory_sizes[gcomprisBoard->level];
01003        g_warning("tux_memory_size %d", tux_memory_size );
01004        tux_pairs = 0;
01005        player_pairs = 0;
01006        update_scores();
01007   }
01008 }
01009 
01010 
01011 /* Destroy all the items */
01012 static void memory_destroy_all_items()
01013 {
01014   gint x, y;
01015 
01016   firstCard = NULL;
01017   secondCard = NULL;
01018 
01019   /* Remove timers first */
01020   if (win_id) {
01021     g_source_remove (win_id);
01022   }
01023   win_id = 0;
01024 
01025   if (currentMode == MODE_TUX){
01026     if (tux_id) {
01027       g_source_remove (tux_id);
01028     }
01029     tux_id =0;
01030     to_tux = FALSE;
01031   }
01032 
01033   /* Now destroy all items */
01034   if(boardRootItem!=NULL)
01035       gtk_object_destroy (GTK_OBJECT(boardRootItem));
01036 
01037   boardRootItem=NULL;
01038 
01039   // Clear the memoryArray
01040   for(x=0; x<MAX_MEMORY_WIDTH; x++)
01041     for(y=0; y<MAX_MEMORY_HEIGHT; y++)
01042       {
01043        if (memoryArray[x][y])
01044          g_free(memoryArray[x][y]->second_value);
01045        g_free(memoryArray[x][y]);
01046        memoryArray[x][y] = NULL;
01047       }
01048 
01049   GList *list;
01050 
01051   for (list = passed_token; list != NULL; list=list->next)
01052     g_free(list->data);
01053 
01054   g_list_free(passed_token);
01055 
01056   passed_token = NULL;
01057 
01058   if (currentMode == MODE_TUX){
01059     for (list = winning_pairs; list != NULL; list=list->next)
01060       g_free(list->data);
01061 
01062     g_list_free(winning_pairs);
01063 
01064     winning_pairs = NULL;
01065     while (g_queue_pop_head (tux_memory));
01066     //tux_memory = NULL;
01067   }
01068 
01069 }
01070 
01071 /*
01072  * Takes care to return a random pair of images (one by one)
01073  * the image is loaded in memoryItem->image
01074  *
01075  */
01076 static void get_image(MemoryItem *memoryItem, guint x, guint y)
01077 {
01078   guint rx, ry;
01079 
01080   memoryItem->hidden = FALSE;
01081 
01082   if(memoryArray[x][y])
01083     {
01084       // Get the pair's image
01085       if (memoryArray[x][y]->type & (TYPE_ADD|TYPE_MINUS|TYPE_MULT|TYPE_DIV)){
01086        memoryItem->data = memoryArray[x][y]->second_value;
01087        memoryItem->type =  memoryArray[x][y]->type;
01088        memoryArray[x][y] = memoryItem;
01089        // if created by g_malloc0, this is not usefull;
01090        //memoryItem->second_value = NULL;
01091       }
01092       else {
01093        memoryItem->data = memoryArray[x][y]->data;
01094        memoryItem->type =  memoryArray[x][y]->type;
01095        memoryArray[x][y] = memoryItem;
01096       }
01097       return;
01098     }
01099 
01100 
01101   memoryArray[x][y] = memoryItem;
01102 
01103   switch (currentBoardMode) {
01104   case BOARDMODE_SOUND:
01105     get_random_token ( TYPE_SOUND, &memoryItem->type,  &memoryItem->data, NULL);
01106     g_assert (memoryItem->type ==  TYPE_SOUND);
01107     break;
01108   case BOARDMODE_NORMAL:
01109     switch(gcomprisBoard->level) {
01110 
01111     case 0:
01112     case 1:
01113     case 2:
01114     case 3:
01115     case 4:
01116       /* Image mode */
01117       get_random_token ( TYPE_IMAGE, &memoryItem->type,  &memoryItem->data, NULL);
01118       g_assert (memoryItem->type ==  TYPE_IMAGE);
01119       break;
01120 
01121     case 5:
01122       /* Limited Text mode Numbers only */
01123       get_random_token ( TYPE_NUMBER, &memoryItem->type,  &memoryItem->data, NULL);
01124       g_assert (memoryItem->type ==  TYPE_NUMBER);
01125       break;
01126 
01127     case 6:
01128       /* Limited Text mode Numbers + Capitals */
01129       get_random_token ( TYPE_NUMBER | TYPE_UPPERCASE, &memoryItem->type,  &memoryItem->data, NULL);
01130       g_assert((memoryItem->type == TYPE_NUMBER)||(memoryItem->type==TYPE_UPPERCASE));
01131       break;
01132 
01133     default:
01134       /* Text mode ALL */
01135       get_random_token ( TYPE_NUMBER | TYPE_UPPERCASE | TYPE_LOWERCASE, &memoryItem->type,  &memoryItem->data, NULL);
01136       g_assert (memoryItem->type & ( TYPE_NUMBER | TYPE_UPPERCASE | TYPE_LOWERCASE));
01137       break;
01138     }
01139     break;
01140   case BOARDMODE_ADD:
01141     get_random_token ( TYPE_ADD, &memoryItem->type,  &memoryItem->data, &memoryItem->second_value);
01142     g_assert (memoryItem->type == TYPE_ADD);
01143     break;
01144   case BOARDMODE_MINUS:
01145     get_random_token ( TYPE_MINUS, &memoryItem->type,  &memoryItem->data, &memoryItem->second_value);
01146     g_assert (memoryItem->type == TYPE_MINUS);
01147     break;
01148   case BOARDMODE_MULT:
01149     get_random_token ( TYPE_MULT, &memoryItem->type,  &memoryItem->data, &memoryItem->second_value);
01150     g_assert (memoryItem->type == TYPE_MULT);
01151     break;
01152   case BOARDMODE_DIV:
01153     get_random_token ( TYPE_DIV, &memoryItem->type,  &memoryItem->data, &memoryItem->second_value);
01154     g_assert (memoryItem->type == TYPE_DIV);
01155     break;
01156   case BOARDMODE_ADD_MINUS:
01157     get_random_token ( TYPE_ADD | TYPE_MINUS, &memoryItem->type,  &memoryItem->data, &memoryItem->second_value);
01158     g_assert (memoryItem->type & (TYPE_ADD | TYPE_MINUS));
01159     break;
01160   case BOARDMODE_MULT_DIV:
01161     get_random_token ( TYPE_MULT | TYPE_DIV, &memoryItem->type,  &memoryItem->data, &memoryItem->second_value);
01162     g_assert (memoryItem->type & (TYPE_MULT | TYPE_DIV));
01163     break;
01164   case BOARDMODE_ADD_MINUS_MULT_DIV:
01165     get_random_token ( TYPE_ADD | TYPE_MINUS |TYPE_MULT | TYPE_DIV , &memoryItem->type,  &memoryItem->data, &memoryItem->second_value);
01166     g_assert (memoryItem->type & (TYPE_ADD | TYPE_MINUS |TYPE_MULT | TYPE_DIV));
01167     break;
01168 
01169   default:
01170     g_error("Don't now in what mode run !");
01171     break;
01172   }
01173 
01174   g_warning("returned token %s for item x=%d y=%d", memoryItem->data, x, y);
01175 
01176 
01177   // Randomly set the pair
01178   rx = (int)(numberOfColumn*((double)rand()/RAND_MAX));
01179   ry = (int)(numberOfLine*((double)rand()/RAND_MAX));
01180 
01181   while(memoryArray[rx][ry])
01182     {
01183       rx++;
01184       // Wrap
01185       if(rx>=numberOfColumn)
01186        {
01187          rx=0;
01188          ry++;
01189          if(ry>=numberOfLine)
01190            ry=0;
01191        }
01192     }
01193   // Makes the pair point to this memoryItem for now
01194   memoryArray[rx][ry] = memoryItem;
01195 }
01196 
01197 static void create_item(GnomeCanvasGroup *parent)
01198 {
01199   MemoryItem *memoryItem;
01200   gint x, y;
01201   gint height, width;
01202   gint height2, width2;
01203   GdkPixbuf *pixmap = NULL;
01204   double xratio = 0;
01205   double yratio = 0;
01206   double card_shadow_w, card_shadow_h;
01207 
01208   // Calc width and height of one card
01209   width  = (base_x2-(currentMode == MODE_TUX ? base_x1_tux : base_x1))/numberOfColumn;
01210   height = (base_y2-base_y1)/numberOfLine;
01211 
01212   /* Remove a little bit of space for the card shadow */
01213   height2 = height * 0.95;
01214   width2  = width  * 0.95;
01215 
01216 
01217   if (currentUiMode == UIMODE_SOUND) {
01218     GdkPixbuf *pixmap =  gc_pixmap_load("images/transparent_square2.png");
01219     gnome_canvas_item_new (GNOME_CANVAS_GROUP(parent),
01220                         gnome_canvas_pixbuf_get_type (),
01221                         "pixbuf", pixmap,
01222                         "x", (double) (currentMode == MODE_TUX ? base_x1_tux : base_x1) - 20,
01223                         "y", (double) base_y1 - 15,
01224                         NULL);
01225     gdk_pixbuf_unref(pixmap);
01226   }
01227 
01228   if (currentMode == MODE_TUX){
01229     GdkPixbuf *pixmap_tux =  gc_pixmap_load("images/tux-teacher.png");
01230 
01231     tux = gnome_canvas_item_new (GNOME_CANVAS_GROUP(parent),
01232                              gnome_canvas_pixbuf_get_type (),
01233                              "pixbuf", pixmap_tux,
01234                              "x", (double) 50,
01235                              "y", (double) 20,
01236                              NULL);
01237     gdk_pixbuf_unref(pixmap_tux);
01238     
01239     tux_score_s = gnome_canvas_item_new (GNOME_CANVAS_GROUP(parent),
01240                                    gnome_canvas_text_get_type (),
01241                                    "font", gc_skin_font_board_huge_bold,
01242                                    "x", (double) 100+1.0,
01243                                    "y", (double) 200+1.0,
01244                                    "anchor", GTK_ANCHOR_CENTER,
01245                                    "fill_color_rgba", 0x101010FF,
01246                                    NULL);
01247 
01248     player_score_s = gnome_canvas_item_new (GNOME_CANVAS_GROUP(parent),
01249                                      gnome_canvas_text_get_type (),
01250                                      "font", gc_skin_font_board_huge_bold,
01251                                      "x", (double) 100+1.0,
01252                                      "y", (double) BASE_CARD_Y2 - 20+1.0,
01253                                      "anchor", GTK_ANCHOR_CENTER,
01254                                      "fill_color_rgba", 0x101010FF,
01255                                      NULL);
01256 
01257     tux_score = gnome_canvas_item_new (GNOME_CANVAS_GROUP(parent),
01258                                    gnome_canvas_text_get_type (),
01259                                    "font", gc_skin_font_board_huge_bold,
01260                                    "x", (double) 100,
01261                                    "y", (double) 200,
01262                                    "anchor", GTK_ANCHOR_CENTER,
01263                                    "fill_color_rgba", 0xFF0F0FFF,
01264                                    NULL);
01265 
01266     player_score = gnome_canvas_item_new (GNOME_CANVAS_GROUP(parent),
01267                                      gnome_canvas_text_get_type (),
01268                                      "font", gc_skin_font_board_huge_bold,
01269                                      "x", (double) 100,
01270                                      "y", (double) BASE_CARD_Y2 - 20,
01271                                      "anchor", GTK_ANCHOR_CENTER,
01272                                      "fill_color_rgba", 0xFF0F0FFF,
01273                                      NULL);
01274   }
01275 
01276   for(x=0; x<numberOfColumn; x++)
01277     {
01278       for(y=0; y<numberOfLine; y++)
01279        {
01280 
01281          memoryItem = g_malloc0(sizeof(MemoryItem));
01282 
01283          memoryItem->rootItem = \
01284            gnome_canvas_item_new (parent,
01285                                gnome_canvas_group_get_type (),
01286                                "x", (double) (currentMode == MODE_TUX ? base_x1_tux : base_x1) + x*width,
01287                                "y", (double) base_y1 + y*height,
01288                                NULL);
01289 
01290          if (currentUiMode == UIMODE_SOUND)
01291            pixmap = gc_pixmap_load("gcompris/misc/Tux_mute.png");
01292          else
01293            pixmap = gc_pixmap_load("gcompris/misc/backcard.png");
01294 
01295          memoryItem->backcardItem = \
01296            gnome_canvas_item_new (GNOME_CANVAS_GROUP(memoryItem->rootItem),
01297                                gnome_canvas_pixbuf_get_type (),
01298                                "pixbuf", pixmap,
01299                                "x", (double) 0,
01300                                "y", (double) 0,
01301                                "width", (double) width2,
01302                                "height", (double) height2,
01303                                "width_set", TRUE,
01304                                "height_set", TRUE,
01305                                NULL);
01306          gdk_pixbuf_unref(pixmap);
01307 
01308          if (currentUiMode != UIMODE_SOUND){
01309            pixmap = gc_pixmap_load("gcompris/misc/emptycard.png");
01310            memoryItem->framecardItem = \
01311              gnome_canvas_item_new (GNOME_CANVAS_GROUP(memoryItem->rootItem),
01312                                  gnome_canvas_pixbuf_get_type (),
01313                                  "pixbuf", pixmap,
01314                                  "x", (double) 0,
01315                                  "y", (double) 0,
01316                                  "width", (double) width2,
01317                                  "height", (double) height2,
01318                                  "width_set", TRUE,
01319                                  "height_set", TRUE,
01320                                  NULL);
01321            gnome_canvas_item_hide(memoryItem->framecardItem);
01322            gdk_pixbuf_unref(pixmap);
01323          }
01324 
01325 
01326          // Display the image itself while taking care of its size and maximize the ratio
01327          get_image(memoryItem, x, y);
01328 
01329          if (currentUiMode == UIMODE_SOUND){
01330            pixmap = gc_pixmap_load("gcompris/misc/Tux_play.png");
01331            memoryItem->frontcardItem =    \
01332              gnome_canvas_item_new (GNOME_CANVAS_GROUP(memoryItem->rootItem),
01333                                  gnome_canvas_pixbuf_get_type (),
01334                                  "pixbuf", pixmap,
01335                                  "x", (double) 0,
01336                                  "y", (double) 0,
01337                                  "width", (double) width2,
01338                                  "height", (double) height2,
01339                                  "width_set", TRUE,
01340                                  "height_set", TRUE,
01341                                  NULL);
01342            gdk_pixbuf_unref(pixmap);
01343          }
01344          else {
01345            if(memoryItem->type == TYPE_IMAGE) {
01346              pixmap = gc_pixmap_load(memoryItem->data);
01347 
01348              yratio=(height2*0.8)/(float)gdk_pixbuf_get_height(pixmap);
01349              xratio=(width2*0.8)/(float)gdk_pixbuf_get_width(pixmap);
01350              yratio=xratio=MIN(xratio, yratio);
01351              card_shadow_w = width*0.05;
01352              card_shadow_h = height*0.05;
01353 
01354              memoryItem->frontcardItem =  \
01355               gnome_canvas_item_new (GNOME_CANVAS_GROUP(memoryItem->rootItem),
01356                                    gnome_canvas_pixbuf_get_type (),
01357                                    "pixbuf", pixmap,
01358                                    "x", (double) ((width2)-
01359                                                 gdk_pixbuf_get_width(pixmap)*xratio*0.8)/2 -
01360                                    card_shadow_w,
01361                                    "y", (double) ((height2)-
01362                                                 gdk_pixbuf_get_height(pixmap)*yratio*0.8)/2 -
01363                                    card_shadow_h,
01364                                    "width", (double) gdk_pixbuf_get_width(pixmap)*xratio*0.8,
01365                                    "height", (double) gdk_pixbuf_get_height(pixmap)*yratio*0.8,
01366                                    "width_set", TRUE,
01367                                    "height_set", TRUE,
01368                                    NULL);
01369              gdk_pixbuf_unref(pixmap);
01370 
01371            } else {
01372              gchar *font;
01373              if (memoryItem->type & (TYPE_ADD|TYPE_MINUS|TYPE_MULT|TYPE_DIV))
01374               font = op_fonts[gcomprisBoard->level];
01375              else
01376               font = TEXT_FONT;
01377              /* It's a letter */
01378              memoryItem->frontcardItem =   \
01379               gnome_canvas_item_new (GNOME_CANVAS_GROUP(memoryItem->rootItem),
01380                                    gnome_canvas_text_get_type (),
01381                                    "text", memoryItem->data,
01382                                    "font", font,
01383                                    "x", (double) (width2*0.9)/2,
01384                                    "y", (double) (height2*0.9)/2,
01385                                    "anchor", GTK_ANCHOR_CENTER,
01386                                    "fill_color_rgba", 0x559ADDFF,
01387                                    NULL);
01388 
01389            }
01390          }
01391 
01392          gnome_canvas_item_hide(memoryItem->frontcardItem);
01393          gtk_signal_connect(GTK_OBJECT(memoryItem->rootItem), "event",
01394                           (GtkSignalFunc) item_event,
01395                           memoryItem);
01396 
01397        }
01398     }
01399 
01400   //return (NULL);
01401 }
01402 
01403 static void player_win()
01404 {
01405   gc_sound_play_ogg ("sounds/bonus.ogg", NULL);
01406   /* Try the next level */
01407   if (tux_pairs <= player_pairs)
01408     gcomprisBoard->level++;
01409   if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
01410     gc_bonus_end_display(BOARD_FINISHED_RANDOM);
01411     return;
01412   }
01413   gc_bonus_display((tux_pairs <= player_pairs), BONUS_RANDOM);
01414 
01415 }
01416 
01417 static void display_card(MemoryItem *memoryItem, CardStatus cardStatus)
01418 {
01419 
01420   if (currentUiMode == UIMODE_SOUND){
01421     switch (cardStatus)
01422       {
01423       case ON_FRONT:
01424        g_assert(memoryItem->hidden == FALSE);
01425        gnome_canvas_item_hide(memoryItem->backcardItem);
01426        gnome_canvas_item_show(memoryItem->frontcardItem);
01427        playing_sound = TRUE;
01428        gc_sound_play_ogg_cb (memoryItem->data, sound_callback);
01429        break;
01430       case ON_BACK:
01431        gnome_canvas_item_show(memoryItem->backcardItem);
01432        gnome_canvas_item_hide(memoryItem->frontcardItem);
01433        break;
01434       case HIDDEN:
01435        gnome_canvas_item_hide(memoryItem->backcardItem);
01436        gnome_canvas_item_hide(memoryItem->frontcardItem);
01437        memoryItem->hidden = TRUE;
01438        break;
01439       }
01440   }
01441   else {
01442     switch (cardStatus)
01443       {
01444       case ON_FRONT:
01445        g_assert(memoryItem->hidden == FALSE);
01446        gnome_canvas_item_hide(memoryItem->backcardItem);
01447        gnome_canvas_item_show(memoryItem->framecardItem);
01448        gnome_canvas_item_show(memoryItem->frontcardItem);
01449        break;
01450       case ON_BACK:
01451        gnome_canvas_item_show(memoryItem->backcardItem);
01452        gnome_canvas_item_hide(memoryItem->framecardItem);
01453        gnome_canvas_item_hide(memoryItem->frontcardItem);
01454        break;
01455       case HIDDEN:
01456        gnome_canvas_item_hide(memoryItem->backcardItem);
01457        gnome_canvas_item_hide(memoryItem->framecardItem);
01458        gnome_canvas_item_hide(memoryItem->frontcardItem);
01459        memoryItem->hidden = TRUE;
01460        break;
01461       }
01462   }
01463 
01464 }
01465 
01466 /*
01467  * Used to hide card after a timer
01468  *
01469  */
01470 static gint hide_card (GtkWidget *widget, gpointer data)
01471 {
01472   if (currentMode == MODE_TUX){
01473     GList *list = NULL;
01474     GList *to_remove = NULL;
01475 
01476     for (list =  winning_pairs; list != NULL; list=list->next)
01477       if ((((WINNING *) list->data)->first == firstCard) || (((WINNING *) list->data)->first == secondCard) || (((WINNING *) list->data)->second == firstCard) || (((WINNING *) list->data)->second == secondCard) ){
01478        to_remove = g_list_append( to_remove, list->data);
01479       }
01480 
01481     for (list =  to_remove; list != NULL; list=list->next){
01482       void *data = list->data;
01483       winning_pairs = g_list_remove (winning_pairs, list->data);
01484       g_free (data);
01485       g_warning("Again %d winning pairs in tux list! ", g_list_length(winning_pairs));
01486     }
01487 
01488     g_list_free(to_remove);
01489 
01490     if (to_tux)
01491       tux_pairs++;
01492     else
01493       player_pairs++;
01494 
01495     update_scores();
01496   }
01497 
01498   if(firstCard!=NULL)
01499     {
01500       display_card(firstCard, HIDDEN);
01501       if (currentMode == MODE_TUX)
01502        remove_card_from_tux_memory(firstCard);
01503       firstCard  = NULL;
01504     }
01505 
01506   if(secondCard!=NULL)
01507     {
01508       display_card(secondCard, HIDDEN);
01509       if (currentMode == MODE_TUX)
01510        remove_card_from_tux_memory(secondCard);
01511       secondCard  = NULL;
01512     }
01513   win_id = 0;
01514 
01515   remainingCards -= 2;
01516   if(remainingCards<=0){
01517     if (currentMode == MODE_TUX){
01518       if (tux_id){
01519        g_source_remove(tux_id);
01520        tux_id = 0;
01521        to_tux = FALSE;
01522       }
01523     }
01524     player_win();
01525   }
01526 
01527   return (FALSE);
01528 }
01529 
01530 static void check_win()
01531 {
01532 
01533   gint timeout, timeout_tux;
01534 
01535   if (currentUiMode == UIMODE_SOUND){
01536     timeout = 200;
01537     timeout_tux = 500;
01538   }
01539   else {
01540     timeout = 1000;
01541     timeout_tux = 2000;
01542   }
01543 
01544   // Check win
01545   if (compare_card((gpointer) firstCard, (gpointer) secondCard) == 0) {
01546     gc_sound_play_ogg ("sounds/gobble.ogg", NULL);
01547     win_id = g_timeout_add (timeout,
01548                          (GSourceFunc) hide_card, NULL);
01549     return;
01550   }
01551 
01552   if (currentMode == MODE_TUX){
01553                /* time to tux to play, after a delay */
01554     to_tux = TRUE;
01555     g_warning("Now tux will play !");
01556     tux_id = g_timeout_add (timeout_tux,
01557                          (GSourceFunc) tux_play, NULL);
01558     return;
01559   }
01560 
01561 }
01562 
01563 static gint
01564 item_event(GnomeCanvasItem *item, GdkEvent *event, MemoryItem *memoryItem)
01565 {
01566 
01567   if(!gcomprisBoard)
01568     return FALSE;
01569 
01570    switch (event->type)
01571      {
01572      case GDK_BUTTON_PRESS:
01573        switch(event->button.button)
01574          {
01575          case 1:
01576 
01577           if (currentMode == MODE_TUX){
01578             if (to_tux){
01579               g_warning("He ! it's tux turn !");
01580               return FALSE;
01581             }
01582           }
01583 
01584           if (playing_sound){
01585             g_warning("wait a minute, the sound is playing !");
01586             //return FALSE;
01587           }
01588 
01589           if(win_id)
01590             return FALSE;
01591 
01592           if(secondCard)
01593             {
01594               display_card(firstCard, ON_BACK);
01595               firstCard = NULL;
01596               display_card(secondCard, ON_BACK);
01597               secondCard = NULL;
01598             }
01599 
01600           if(!firstCard)
01601             {
01602               firstCard = memoryItem;
01603               if (currentMode == MODE_TUX)
01604                add_card_in_tux_memory(memoryItem);
01605               display_card(memoryItem, ON_FRONT);
01606               return TRUE;
01607             }
01608           else
01609             {
01610               // Check he/she did not click on the same card twice
01611               if(firstCard==memoryItem)
01612                return FALSE;
01613 
01614               secondCard = memoryItem;
01615               if (currentMode == MODE_TUX)
01616                add_card_in_tux_memory(memoryItem);
01617               display_card(memoryItem, ON_FRONT);
01618               if (currentUiMode == UIMODE_SOUND)
01619                // Check win is called from callback return
01620                return TRUE;
01621               else {
01622                check_win();
01623                return TRUE;
01624               }
01625 
01626             }
01627           break;
01628         default:
01629           break;
01630         }
01631      default:
01632        break;
01633      }
01634    return FALSE;
01635 }
01636 
01637 void add_card_in_tux_memory(MemoryItem *card)
01638 {
01639   MemoryItem *first = NULL;
01640 
01641   g_warning("Adding card %s in tux memory ", card->data);
01642 
01643   /* check if card is already in memory */
01644   remove_card_from_tux_memory(card);
01645 
01646   first = find_card_in_tux_memory(card);
01647 
01648   if (first){
01649     g_warning("found %s and %s !", first->data, card->data);
01650     WINNING *win = g_malloc0(sizeof(WINNING));
01651     win->first = card;
01652     win->second = first;
01653     winning_pairs = g_list_append( winning_pairs, win);
01654     g_warning("Now %d winning pairs in tux list! ", g_list_length(winning_pairs));
01655 
01656     remove_card_from_tux_memory(first);
01657   }
01658 
01659   g_queue_push_head(tux_memory, card);
01660 
01661   if (g_queue_get_length (tux_memory)>tux_memory_size){
01662     g_queue_pop_tail(tux_memory);
01663 
01664   g_warning("Now tuxmemory size = %d", g_queue_get_length (tux_memory));
01665 
01666   }
01667 }
01668 
01669 static gint
01670 compare_card (gconstpointer a,
01671              gconstpointer b)
01672 {
01673   MemoryItem *card1 = (MemoryItem *)a;
01674   MemoryItem *card2 = (MemoryItem *)b;
01675 
01676   if (card1->type & (TYPE_ADD|TYPE_MINUS|TYPE_MULT|TYPE_DIV)){
01677     if ((!card1->second_value) && ( card2->second_value)){
01678       return strcmp(card1->data,card2->second_value);
01679     }
01680     if ((!card2->second_value) && ( card1->second_value)){
01681       return strcmp(card2->data,card1->second_value);
01682     }
01683     return -1;
01684   }
01685   return ((card1->data == card2->data) ? 0 : -1);
01686 }
01687 
01688 MemoryItem *find_card_in_tux_memory(MemoryItem *card)
01689 {
01690   GList *link;
01691 
01692   if ((link = g_queue_find_custom(tux_memory, card, compare_card)) != NULL)
01693     return link->data;
01694   else
01695     return NULL;
01696 }
01697 
01698 void remove_card_from_tux_memory(MemoryItem *card)
01699 {
01700   g_queue_remove(tux_memory, card);
01701 }
01702 
01703 static gint tux_play(){
01704   int rx, ry;
01705 
01706   if (Paused){
01707     g_warning("Paused");
01708     return TRUE;
01709   }
01710 
01711   g_warning("Now tux playing !");
01712 
01713   if(secondCard)
01714     {
01715       display_card(firstCard, ON_BACK);
01716       firstCard = NULL;
01717       display_card(secondCard, ON_BACK);
01718       secondCard = NULL;
01719     }
01720 
01721   if (winning_pairs){
01722     g_warning("I will won !");
01723     if (!firstCard){
01724       g_warning("case 1");
01725       firstCard = ((WINNING *) winning_pairs->data)->first ;
01726       display_card(firstCard, ON_FRONT);
01727       if (currentUiMode == UIMODE_SOUND)
01728        return FALSE;
01729       else
01730        return TRUE;
01731     } else {
01732       g_warning("case 2");
01733       secondCard = ((WINNING *) winning_pairs->data)->second;
01734       display_card(secondCard, ON_FRONT);
01735       if (currentUiMode == UIMODE_SOUND)
01736        return FALSE;
01737       else {
01738        gc_sound_play_ogg ("sounds/gobble.ogg", NULL);
01739        win_id = g_timeout_add (1000,
01740                             (GSourceFunc) hide_card, NULL);
01741        return TRUE;
01742       }
01743     }
01744   }
01745 
01746   // Randomly set the pair
01747   rx = (int)(numberOfColumn*((double)rand()/RAND_MAX));
01748   ry = (int)(numberOfLine*((double)rand()/RAND_MAX));
01749 
01750   gboolean  stay_unknown = (remainingCards > (g_queue_get_length (tux_memory)
01751                                          + (firstCard ? 1 : 0)));
01752 
01753   g_warning("remainingCards %d tux_memory %d -> stay_unknown %d ",
01754            remainingCards,
01755            g_queue_get_length (tux_memory),
01756            stay_unknown );
01757 
01758   while((memoryArray[rx][ry]->hidden) || (memoryArray[rx][ry] == firstCard)
01759        || (stay_unknown && g_queue_find(tux_memory,memoryArray[rx][ry])))
01760     {
01761       g_warning("Loop to find %d %d %s", rx, ry, memoryArray[rx][ry]->data);
01762       rx++;
01763       // Wrap
01764       if(rx>=numberOfColumn)
01765        {
01766          rx=0;
01767          ry++;
01768          if(ry>=numberOfLine)
01769            ry=0;
01770        }
01771     }
01772 
01773   if (!firstCard){
01774     g_warning("case 3");
01775     firstCard = memoryArray[rx][ry];
01776     add_card_in_tux_memory(firstCard);
01777     display_card(firstCard, ON_FRONT);
01778     g_warning("Now tux replay !");
01779     if (currentUiMode == UIMODE_SOUND)
01780       return FALSE;
01781     else
01782       return TRUE;
01783   } else {
01784     g_warning("case 4");
01785     secondCard = memoryArray[rx][ry];
01786     add_card_in_tux_memory(secondCard);
01787     display_card(secondCard, ON_FRONT);
01788     if (currentUiMode == UIMODE_SOUND)
01789       return FALSE;
01790     else {
01791       if (compare_card(firstCard, secondCard)==0){
01792        gc_sound_play_ogg ("sounds/gobble.ogg", NULL);
01793        g_warning("Now tux win !");
01794        win_id = g_timeout_add (1000,
01795                             (GSourceFunc) hide_card, NULL);
01796        return TRUE;
01797       } else{
01798        to_tux = FALSE;
01799        return FALSE;
01800       }
01801     }
01802   }
01803   return FALSE;
01804 }
01805 
01806 static void sound_callback(gchar *file)
01807 {
01808   if (! gcomprisBoard)
01809     return;
01810 
01811   g_warning("sound_callback %s", file);
01812 
01813   playing_sound = FALSE;
01814   if (currentMode == MODE_TUX){
01815     if (to_tux) {
01816       if (firstCard && secondCard){
01817        if (compare_card(firstCard, secondCard)==0){
01818          gc_sound_play_ogg ("sounds/gobble.ogg", NULL);
01819          win_id = g_timeout_add (1000,
01820                               (GSourceFunc) hide_card, NULL);
01821          tux_id = g_timeout_add (2000,
01822                               (GSourceFunc) tux_play, NULL);
01823          return;
01824        } else {
01825          to_tux = FALSE;
01826          return;
01827        }
01828       } else {
01829        g_warning("Now tux will replay !");
01830        tux_id = g_timeout_add (2000,
01831                            (GSourceFunc) tux_play, NULL);
01832        return;
01833       }
01834     }
01835   }
01836   if (firstCard && secondCard)
01837     check_win();
01838 }
01839 
01840 
01841 static void start_callback(gchar *file){
01842   if (!gcomprisBoard)
01843     return;
01844 
01845   if (currentUiMode != UIMODE_SOUND)
01846     return;
01847 
01848   playing_sound = FALSE;
01849 }