/* gcompris - memory.c
*
* Copyright (C) 2000, 2008 Bruno Coudoin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
// FIXME: Cleanup of MemoryItem created struct is not done
#include
#include
#include "gcompris/gcompris.h"
#define MAX_MEMORY_WIDTH 8
#define MAX_MEMORY_HEIGHT 4
//#define TEXT_FONT gc_skin_font_board_huge_bold
#define TEXT_FONT "sans bold 28"
static gchar *op_fonts[10] =
{
"",
"sans bold 28",
"sans bold 24",
"sans bold 20",
"sans bold 20",
"sans bold 17",
"sans bold 13",
"sans bold 13",
"sans bold 13",
"sans bold 11",
};
static GcomprisBoard *gcomprisBoard = NULL;
static GooCanvasItem *boardRootItem = NULL;
static gint win_id = 0;
typedef enum
{
MODE_NORMAL = 0,
MODE_TUX = 1,
} Mode;
static Mode currentMode = MODE_NORMAL;
typedef enum
{
UIMODE_NORMAL = 0,
UIMODE_SOUND = 1,
} UiMode;
static UiMode currentUiMode = UIMODE_NORMAL;
typedef enum
{
BOARDMODE_NORMAL = 0,
BOARDMODE_SOUND = 1,
BOARDMODE_ADD = 2,
BOARDMODE_MINUS = 3,
BOARDMODE_MULT = 4,
BOARDMODE_DIV = 5,
BOARDMODE_ADD_MINUS = 6,
BOARDMODE_MULT_DIV = 7,
BOARDMODE_ADD_MINUS_MULT_DIV = 8,
BOARDMODE_ENUMERATE = 9,
BOARDMODE_WORDNUMBER = 10,
} BoardMode;
static BoardMode currentBoardMode = BOARDMODE_NORMAL;
typedef enum
{
ON_FRONT = 0,
ON_BACK = 1,
HIDDEN = 2
} CardStatus;
static gchar *numbers;
static gchar *alphabet_lowercase;
static gchar *alphabet_uppercase;
static gchar *operators;
static gchar *op_add = NULL;
static gchar *op_minus = NULL;
static gchar *op_mult = NULL;
static gchar *op_div = NULL;
typedef struct {
gchar *data;
gint type;
guint status;
GooCanvasItem *rootItem;
GooCanvasItem *backcardItem;
GooCanvasItem *framecardItem;
GooCanvasItem *frontcardItem;
gboolean hidden;
gchar *second_value;
} MemoryItem;
static MemoryItem *firstCard = NULL;
static MemoryItem *secondCard = NULL;
/* Define the page area where memory cards can be displayed for CARD MODE */
#define BASE_CARD_X1 50
#define BASE_CARD_Y1 40
#define BASE_CARD_X2 790
#define BASE_CARD_Y2 470
#define BASE_CARD_X1_TUX 200
/* Define the page area where memory cards can be displayed for SOUND MODE */
#define BASE_SOUND_X1 250
#define BASE_SOUND_Y1 30
#define BASE_SOUND_X2 600
#define BASE_SOUND_Y2 200
#define BASE_SOUND_X1_TUX BASE_SOUND_X1
/* The current page area where memory cards can be displayed */
gint base_x1;
gint base_y1;
gint base_x2;
gint base_y2;
gint base_x1_tux;
gint current_x;
gint current_y;
gint numberOfLine;
gint numberOfColumn;
gint remainingCards;
static void start_board (GcomprisBoard *agcomprisBoard);
static void pause_board (gboolean pause);
static void end_board (void);
static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
static void set_level (guint level);
static void create_item(GooCanvasItem *parent);
static void memory_destroy_all_items(void);
static void memory_next_level(void);
static gboolean item_event (GooCanvasItem *item,
GooCanvasItem *target,
GdkEventButton *event,
MemoryItem *memoryItem);
static gint compare_card (gconstpointer a, gconstpointer b);
static void player_win();
static void display_card(MemoryItem *memoryItem, CardStatus cardStatus);
static void sound_callback(gchar *file);
static void start_callback(gchar *file);
static gboolean playing_sound = FALSE;
static void gcompris_adapt_font_size(GooCanvasText *textItem, gdouble width, gdouble height);
// Number of images for x and y by level
static guint levelDescription[] =
{
0,0,
3,2,
4,2,
5,2,
4,3,
6,3,
5,4,
6,4,
7,4,
MAX_MEMORY_WIDTH,MAX_MEMORY_HEIGHT
};
static MemoryItem *memoryArray[MAX_MEMORY_WIDTH][MAX_MEMORY_HEIGHT];
/* List of images to use in the memory */
static gchar *imageList[] =
{
"memory/01_cat.png",
"memory/02_pig.png",
"memory/03_bear.png",
"memory/04_hippopotamus.png",
"memory/05_penguin.png",
"memory/06_cow.png",
"memory/07_sheep.png",
"memory/08_turtle.png",
"memory/09_panda.png",
"memory/10_chicken.png",
"memory/11_redbird.png",
"memory/12_wolf.png",
"memory/13_monkey.png",
"memory/14_fox.png",
"memory/15_bluebirds.png",
"memory/16_elephant.png",
"memory/17_lion.png",
"memory/18_gnu.png",
"memory/19_bluebaby.png",
"memory/20_greenbaby.png",
"memory/21_frog.png",
};
#define NUMBER_OF_IMAGES G_N_ELEMENTS(imageList)
/* List of sounds to use in the memory */
static gchar *soundList[] =
{
"memory/LRApplauses_1_LA_cut.ogg",
"memory/LRBark_1_LA_cut.ogg",
"memory/LRBark_3_LA_cut.ogg",
"memory/LRBuddhist_gong_05_LA.ogg",
"memory/LRDoor_Open_2_LA.ogg",
"memory/LRFactory_noise_01_LA.ogg",
"memory/LRFactory_noise_02_LA.ogg",
"memory/LRFactory_noise_03_LA.ogg",
"memory/LRFactory_noise_04_LA.ogg",
"memory/LRFactory_noise_05_LA.ogg",
"memory/LRFactory_noise_06_LA.ogg",
"memory/LRFireballs_01_LA.ogg",
"memory/LRFrogsInPondDuringStormLACut.ogg",
"memory/LRHeart_beat_01_LA.ogg",
"memory/LRHits_01_LA.ogg",
"memory/LRLaPause_short.ogg",
"memory/LRObject_falling_01_LA.ogg",
"memory/LRObject_falling_02_LA.ogg",
"memory/LRRain_in_garden_01_LA_cut.ogg",
"memory/LRRing_01_LA.ogg",
"memory/LRStartAndStopCarEngine1LACut.ogg",
"memory/LRTrain_slowing_down_01_LA_cut.ogg",
"memory/LRWeird_1_LA.ogg",
"memory/LRWeird_2_LA.ogg",
"memory/LRWeird_3_LA.ogg",
"memory/LRWeird_4_LA.ogg",
"memory/LRWeird_5_LA.ogg",
"memory/LRWeird_6_LA.ogg",
"memory/guitar_melody.ogg",
"memory/guitar_son1.ogg",
"memory/guitar_son2.ogg",
"memory/guitar_son3.ogg",
"memory/guitar_son4.ogg",
"memory/plick.ogg",
"memory/space1.ogg",
"memory/space2.ogg",
"memory/tachos_melody.ogg",
"memory/tachos_son1.ogg",
"memory/tachos_son2.ogg",
"memory/tachos_son3.ogg",
"memory/tachos_son4.ogg",
"memory/tick.ogg",
"memory/tri.ogg",
};
#define NUMBER_OF_SOUNDS G_N_ELEMENTS(soundList)
/* List of images to use in the enumerate memory */
static gchar *enumerateList[] =
{
"memory/math_0.svg",
"memory/math_1.svg",
"memory/math_2.svg",
"memory/math_3.svg",
"memory/math_4.svg",
"memory/math_5.svg",
"memory/math_6.svg",
"memory/math_7.svg",
"memory/math_8.svg",
"memory/math_9.svg",
};
#define NUMBER_OF_ENUMERATES G_N_ELEMENTS(enumerateList)
/* List of images to use in the enumerate memory */
static gchar *wordnumberList[] =
{
N_("zero"),
N_("one"),
N_("two"),
N_("three"),
N_("four"),
N_("five"),
N_("six"),
N_("seven"),
N_("eight"),
N_("nine"),
};
#define NUMBER_OF_WORDNUMBERS G_N_ELEMENTS(wordnumberList)
static SoundPolicy sound_policy;
/* Description of this plugin */
static BoardPlugin menu_bp =
{
NULL,
NULL,
N_("Memory"),
N_("Find the matching pair"),
"Bruno Coudoin ",
NULL,
NULL,
NULL,
NULL,
start_board,
pause_board,
end_board,
is_our_board,
NULL,
NULL,
set_level,
NULL,
NULL,
NULL,
NULL
};
/*
* Against computer version
* ------------------------
*
*/
static gboolean to_tux = FALSE;
static gboolean lock_user = FALSE;
static GQueue *tux_memory = NULL;
static gint tux_memory_size;
static gint tux_memory_sizes[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
static gint tux_pairs = 0;
static gint player_pairs = 0;
static void add_card_in_tux_memory(MemoryItem *card);
static MemoryItem *find_card_in_tux_memory(MemoryItem *card);
static void remove_card_from_tux_memory(MemoryItem *card);
static gint tux_play();
typedef struct {
MemoryItem *first;
MemoryItem *second;
} WINNING;
static GList *winning_pairs = NULL;
static gint tux_id = 0;
/*
*
* Operation versions
*
*/
/* max number 1 / max number 2 */
/* to allow level with calculus like 7*12 */
static guint add_levelDescription[10][2] =
{
{0,0},
{5,5},
{5,7},
{7,7},
{7,10},
{10,10},
{10,15},
{15,15},
{25,25},
{50,50},
};
static guint minus_levelDescription[10][2] =
{
{0,0},
{5,5},
{5,7},
{7,7},
{7,10},
{10,10},
{10,15},
{15,15},
{25,25},
{50,50},
};
static guint mult_levelDescription[10][2] =
{
{0,0},
{5,5},
{5,7},
{7,7},
{7,10},
{10,10},
{12,12},
{15,15},
{20,20},
{25,25},
};
static guint div_levelDescription[10][2] =
{
{0,0},
{5,5},
{5,7},
{7,7},
{7,10},
{10,10},
{12,12},
{15,15},
{20,20},
{25,25},
};
/*
* random without repeted token
* ------------------------
*
*/
#define TYPE_IMAGE 1
#define TYPE_NUMBER 2
#define TYPE_UPPERCASE 4
#define TYPE_LOWERCASE 8
#define TYPE_SOUND 16
#define TYPE_ADD 32
#define TYPE_MINUS 64
#define TYPE_MULT 128
#define TYPE_DIV 256
#define TYPE_ENUMERATE 512
#define TYPE_ENUMERATE_IMAGE 1024
#define TYPE_WORDNUMBER 2048
static GList *passed_token = NULL;
static GooCanvasItem *tux;
static GooCanvasItem *tux_score;
static GooCanvasItem *player_score;
/* set the type of the token returned in string in returned_type */
void get_random_token(int token_type, gint *returned_type, gchar **string, gchar **second_value)
{
gchar *result = NULL;
gchar *second = NULL;
gboolean skip;
gint max_token;
gint j, i, k;
gint type;
typedef struct {
gint bound;
gint type;
} DATUM ;
GList *data= NULL;
GList *list;
max_token = 0;
if (token_type & TYPE_IMAGE){
max_token += NUMBER_OF_IMAGES;
DATUM *dat = g_malloc0(sizeof(DATUM));
dat->bound = max_token;
dat->type = TYPE_IMAGE;
data = g_list_append(data, dat);
}
if (token_type & TYPE_NUMBER) {
max_token += g_utf8_strlen (numbers, -1);
DATUM *dat = g_malloc0(sizeof(DATUM));
dat->bound = max_token;
dat->type = TYPE_NUMBER;
data = g_list_append(data, dat);
}
if (token_type & TYPE_UPPERCASE){
max_token += g_utf8_strlen (alphabet_uppercase, -1);
DATUM *dat = g_malloc0(sizeof(DATUM));
dat->bound = max_token;
dat->type = TYPE_UPPERCASE;
data = g_list_append(data, dat);
}
if (token_type & TYPE_LOWERCASE){
max_token += g_utf8_strlen (alphabet_lowercase, -1);;
DATUM *dat = g_malloc0(sizeof(DATUM));
dat->bound = max_token;
dat->type = TYPE_LOWERCASE;
data = g_list_append(data, dat);
}
if (token_type & TYPE_SOUND){
max_token += NUMBER_OF_SOUNDS;
DATUM *dat = g_malloc0(sizeof(DATUM));
dat->bound = max_token;
dat->type = TYPE_SOUND;
data = g_list_append(data, dat);
}
if (token_type & TYPE_ADD){
max_token += (add_levelDescription[gcomprisBoard->level][0]+1)*(add_levelDescription[gcomprisBoard->level][1]+1);
DATUM *dat = g_malloc0(sizeof(DATUM));
dat->bound = max_token;
dat->type = TYPE_ADD;
data = g_list_append(data, dat);
}
if (token_type & TYPE_MINUS){
max_token += (minus_levelDescription[gcomprisBoard->level][0]+1)*(minus_levelDescription[gcomprisBoard->level][1]+1);
DATUM *dat = g_malloc0(sizeof(DATUM));
dat->bound = max_token;
dat->type = TYPE_MINUS;
data = g_list_append(data, dat);
}
if (token_type & TYPE_MULT){
max_token += (mult_levelDescription[gcomprisBoard->level][0]+1)*(mult_levelDescription[gcomprisBoard->level][1]+1);
DATUM *dat = g_malloc0(sizeof(DATUM));
dat->bound = max_token;
dat->type = TYPE_MULT;
data = g_list_append(data, dat);
}
if (token_type & TYPE_DIV){
max_token += (div_levelDescription[gcomprisBoard->level][0]+1)*(div_levelDescription[gcomprisBoard->level][1]+1);
DATUM *dat = g_malloc0(sizeof(DATUM));
dat->bound = max_token;
dat->type = TYPE_DIV;
data = g_list_append(data, dat);
}
if (token_type & TYPE_ENUMERATE){
max_token += NUMBER_OF_ENUMERATES;
DATUM *dat = g_malloc0(sizeof(DATUM));
dat->bound = max_token;
dat->type = TYPE_ENUMERATE;
data = g_list_append(data, dat);
}
if (token_type & TYPE_WORDNUMBER){
max_token += NUMBER_OF_WORDNUMBERS;
DATUM *dat = g_malloc0(sizeof(DATUM));
dat->bound = max_token;
dat->type = TYPE_WORDNUMBER;
data = g_list_append(data, dat);
}
g_assert(max_token >0);
i = g_random_int()%max_token;
for (list = data; list != NULL; list = list->next)
if ( i < ((DATUM *)list->data)->bound)
break;
j=-1;
do {
skip = FALSE;
g_free(result);
result = NULL;
g_free(second);
j++;
if ((i+j) == max_token) {
list = data;
}
if ((i+j)%max_token == ((DATUM *)list->data)->bound)
list = list->next;
/* calculate index in right table */
k = (i+j)%max_token - (list->prev ? ((DATUM *)list->prev->data)->bound : 0);
type = ((DATUM *)list->data)->type;
switch (type) {
case TYPE_IMAGE:
result= g_strdup(imageList[k]);
break;
case TYPE_NUMBER:
result = g_malloc0(2*sizeof(gunichar));
g_utf8_strncpy(result, g_utf8_offset_to_pointer (numbers,k),1);
break;
case TYPE_UPPERCASE:
result = g_malloc0(2*sizeof(gunichar));
g_utf8_strncpy(result, g_utf8_offset_to_pointer (alphabet_uppercase,k),1);
break;
case TYPE_LOWERCASE:
result = g_malloc0(2*sizeof(gunichar));
g_utf8_strncpy(result, g_utf8_offset_to_pointer (alphabet_lowercase,k),1);
break;
case TYPE_SOUND:
result = g_strdup(soundList[k]);
break;
case TYPE_ADD:
{
int i, j;
i = k % add_levelDescription[gcomprisBoard->level][0];
j = k / add_levelDescription[gcomprisBoard->level][0];
result = g_strdup_printf("%d %s %d",i,op_add,j);
second = g_strdup_printf("%d",i+j);;
break;
}
case TYPE_MINUS:
{
int i, j;
i = k % minus_levelDescription[gcomprisBoard->level][0];
j = k / minus_levelDescription[gcomprisBoard->level][0];
result = g_strdup_printf("%d %s %d",i+j,op_minus,i);
second = g_strdup_printf("%d",j);;
break;
}
case TYPE_MULT:
{
int i, j;
i = k % mult_levelDescription[gcomprisBoard->level][0];
j = k / mult_levelDescription[gcomprisBoard->level][0];
result = g_strdup_printf("%d %s %d",i,op_mult,j);
second = g_strdup_printf("%d",i*j);;
break;
}
case TYPE_DIV:
{
int i1, i2;
i1 = k % div_levelDescription[gcomprisBoard->level][0];
if (i1==0) skip=TRUE;
i2 = k / div_levelDescription[gcomprisBoard->level][0];
result = g_strdup_printf("%d %s %d",i1*i2,op_div,i1);
second = g_strdup_printf("%d",i2);
break;
}
case TYPE_ENUMERATE:
{
result = g_malloc0(2*sizeof(gunichar));
g_utf8_strncpy(result, g_utf8_offset_to_pointer (numbers,k),1);
second = g_strdup(enumerateList[k]);
break;
}
case TYPE_WORDNUMBER:
{
result = g_malloc0(2*sizeof(gunichar));
g_utf8_strncpy(result, g_utf8_offset_to_pointer (numbers,k),1);
second = g_strdup(gettext(wordnumberList[k]));
break;
}
default:
/* should never append */
g_error("never !");
break;
}
} while (skip || ((j < max_token )
&& (passed_token && result && g_list_find_custom(passed_token, result, (GCompareFunc)strcmp))));
g_assert (j < max_token);
passed_token = g_list_append( passed_token, result);
*returned_type = type;
*string = result;
if (second_value)
*second_value = second;
for (list = data; list != NULL; list=list->next)
g_free(list->data);
g_list_free(data);
}
/*
* Main entry point mandatory for each Gcompris's game
* ---------------------------------------------------
*
*/
GET_BPLUGIN_INFO(memory)
/*
* in : boolean TRUE = PAUSE : FALSE = UNPAUSE
*
*/
static gboolean Paused = FALSE;
static void pause_board (gboolean pause)
{
if(gcomprisBoard==NULL)
return;
Paused = pause;
if(pause){
if (currentMode == MODE_TUX){
if (tux_id){
g_source_remove(tux_id);
tux_id = 0;
}
}
}
else {
if (remainingCards<=0)
memory_next_level();
else {
if (currentMode == MODE_TUX){
if (to_tux){
tux_id = g_timeout_add (2000,
(GSourceFunc) tux_play, NULL);
}
}
}
}
}
/*
*/
static void start_board (GcomprisBoard *agcomprisBoard)
{
if(agcomprisBoard!=NULL)
{
gcomprisBoard=agcomprisBoard;
gcomprisBoard->level = 1;
gcomprisBoard->maxlevel = 9;
gc_bar_set(GC_BAR_LEVEL);
/* Default mode */
if(!gcomprisBoard->mode){
currentMode=MODE_NORMAL;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_NORMAL;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "tux")==0){
currentMode=MODE_TUX;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_NORMAL;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "sound")==0){
currentMode=MODE_NORMAL;
currentUiMode=UIMODE_SOUND;
currentBoardMode=BOARDMODE_SOUND;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "sound_tux")==0){
currentMode=MODE_TUX;
currentUiMode=UIMODE_SOUND;
currentBoardMode=BOARDMODE_SOUND;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "add")==0){
currentMode=MODE_NORMAL;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_ADD;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "add_tux")==0){
currentMode=MODE_TUX;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_ADD;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "minus")==0){
currentMode=MODE_NORMAL;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_MINUS;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "minus_tux")==0){
currentMode=MODE_TUX;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_MINUS;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "mult")==0){
currentMode=MODE_NORMAL;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_MULT;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "mult_tux")==0){
currentMode=MODE_TUX;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_MULT;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "div")==0){
currentMode=MODE_NORMAL;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_DIV;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "div_tux")==0){
currentMode=MODE_TUX;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_DIV;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "add_minus")==0){
currentMode=MODE_NORMAL;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_ADD_MINUS;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "add_minus_tux")==0){
currentMode=MODE_TUX;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_ADD_MINUS;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "mult_div")==0){
currentMode=MODE_NORMAL;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_MULT_DIV;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "mult_div_tux")==0){
currentMode=MODE_TUX;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_MULT_DIV;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "add_minus_mult_div")==0){
currentMode=MODE_NORMAL;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_ADD_MINUS_MULT_DIV;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "add_minus_mult_div_tux")==0){
currentMode=MODE_TUX;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_ADD_MINUS_MULT_DIV;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "enumerate")==0){
currentMode=MODE_NORMAL;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_ENUMERATE;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "enumerate_tux")==0){
currentMode=MODE_TUX;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_ENUMERATE;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "wordnumber")==0){
currentMode=MODE_NORMAL;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_WORDNUMBER;
} else {
if(g_ascii_strcasecmp(gcomprisBoard->mode, "wordnumber_tux")==0){
currentMode=MODE_TUX;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_WORDNUMBER;
} else {
currentMode=MODE_NORMAL;
currentUiMode=UIMODE_NORMAL;
currentBoardMode=BOARDMODE_NORMAL;
g_warning("Fallback mode set to images");
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
if (currentUiMode == UIMODE_SOUND)
{
GcomprisProperties *properties = gc_prop_get();
gc_sound_bg_pause();
/* initial state to restore */
sound_policy = gc_sound_policy_get();
// Will set the PLAY_AND_INTERRUPT policy on first
// user click so that intro sounds is not
gc_set_background(goo_canvas_get_root_item(gcomprisBoard->canvas),
"memory/gcompris_band.svg");
base_x1 = BASE_SOUND_X1;
base_y1 = BASE_SOUND_Y1;
base_x2 = BASE_SOUND_X2;
base_y2 = BASE_SOUND_Y2;
base_x1_tux = BASE_SOUND_X1_TUX;
if(!properties->fx) {
gc_dialog(_("Error: this activity cannot be played with the\n"
"sound effects disabled.\nGo to the configuration dialog to\n"
"enable the sound"), gc_board_stop);
return;
}
}
else
{
if ((currentBoardMode==BOARDMODE_ENUMERATE)||(currentBoardMode==BOARDMODE_WORDNUMBER))
{
gcomprisBoard->maxlevel = 6;
}
gc_set_background(goo_canvas_get_root_item(gcomprisBoard->canvas),
"memory/scenery_background.png");
base_x1 = BASE_CARD_X1;
base_y1 = BASE_CARD_Y1;
base_x2 = BASE_CARD_X2;
base_y2 = BASE_CARD_Y2;
base_x1_tux = BASE_CARD_X1_TUX;
}
/* TRANSLATORS: Put here the numbers in your language */
numbers=_("0123456789");
g_assert(g_utf8_validate(numbers,-1,NULL)); // require by all utf8-functions
/* TRANSLATORS: Put here the alphabet lowercase in your language */
alphabet_lowercase=_("abcdefghijklmnopqrstuvwxyz");
g_assert(g_utf8_validate(alphabet_lowercase,-1,NULL)); // require by all utf8-functions
g_warning("Using lowercase %s", alphabet_lowercase);
/* TRANSLATORS: Put here the alphabet uppercase in your language */
alphabet_uppercase=_("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
g_assert(g_utf8_validate(alphabet_uppercase,-1,NULL)); // require by all utf8-functions
g_warning("Using uppercase %s", alphabet_uppercase);
/* TRANSLATORS: Put here the mathematical operators '+-x/' for your language. */
operators=_("+-×÷");
g_assert(g_utf8_validate(operators,-1,NULL)); // require by all utf8-functions
g_warning("Using operators %s", operators);
op_add = g_malloc0(2*sizeof(gunichar));
g_utf8_strncpy(op_add, g_utf8_offset_to_pointer (operators,0),1);
op_minus = g_malloc0(2*sizeof(gunichar));
g_utf8_strncpy(op_minus, g_utf8_offset_to_pointer (operators,1),1);
op_mult = g_malloc0(2*sizeof(gunichar));
g_utf8_strncpy(op_mult, g_utf8_offset_to_pointer (operators,2),1);
op_div = g_malloc0(2*sizeof(gunichar));
g_utf8_strncpy(op_div, g_utf8_offset_to_pointer (operators,3),1);
g_warning("Using operators %s %s %s %s", op_add, op_minus,
op_mult, op_div);
if (currentMode == MODE_TUX){
tux_memory_size = tux_memory_sizes[gcomprisBoard->level];
tux_memory = g_queue_new ();
}
Paused = FALSE;
memory_next_level();
}
}
static void
end_board ()
{
if (currentUiMode == UIMODE_SOUND) {
gc_sound_policy_set(sound_policy);
gc_sound_bg_resume();
}
if(gcomprisBoard!=NULL)
{
pause_board(TRUE);
memory_destroy_all_items();
if (currentMode == MODE_TUX){
if (tux_memory)
g_queue_free(tux_memory);
tux_memory = NULL;
}
}
g_free(op_add);
op_add = NULL;
g_free(op_minus);
op_minus = NULL;
g_free(op_mult);
op_mult = NULL;
g_free(op_div);
op_div = NULL;
gcomprisBoard = NULL;
}
static void
set_level (guint level)
{
if(gcomprisBoard!=NULL)
{
gcomprisBoard->level=level;
memory_next_level();
}
}
static gboolean
is_our_board (GcomprisBoard *gcomprisBoard)
{
if (gcomprisBoard)
{
if(g_ascii_strcasecmp(gcomprisBoard->type, "memory")==0)
{
/* Set the plugin entry */
gcomprisBoard->plugin=&menu_bp;
return TRUE;
}
}
return FALSE;
}
/*-------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------*/
static void update_scores()
{
gchar *tux_score_str;
gchar *player_score_str;
tux_score_str = g_strdup_printf("%d", tux_pairs);
player_score_str = g_strdup_printf("%d", player_pairs);
g_object_set(tux_score, "text", tux_score_str, NULL);
g_object_set(player_score, "text", player_score_str, NULL);
g_free(tux_score_str);
g_free(player_score_str);
}
/* set initial values for the next level */
static void memory_next_level()
{
gc_bar_set_level(gcomprisBoard);
to_tux = FALSE;
if (currentUiMode == UIMODE_SOUND){
/* We play a sound here to cancel any pending sounds callback from a previous play */
playing_sound = TRUE;
gc_sound_play_ogg_cb("memory/LRBuddhist_gong_05_LA.ogg",start_callback);
} else
playing_sound = FALSE;
memory_destroy_all_items();
boardRootItem = goo_canvas_group_new (goo_canvas_get_root_item(gcomprisBoard->canvas),
NULL);
numberOfColumn = levelDescription[gcomprisBoard->level*2];
numberOfLine = levelDescription[gcomprisBoard->level*2+1];
remainingCards = numberOfColumn * numberOfLine;
gcomprisBoard->number_of_sublevel=1;
gcomprisBoard->sublevel=0;
create_item(boardRootItem);
lock_user = FALSE;
if (currentMode == MODE_TUX){
tux_memory_size = tux_memory_sizes[gcomprisBoard->level];
g_warning("tux_memory_size %d", tux_memory_size );
tux_pairs = 0;
player_pairs = 0;
update_scores();
}
}
/* Destroy all the items */
static void memory_destroy_all_items()
{
gint x, y;
firstCard = NULL;
secondCard = NULL;
/* Remove timers first */
if (win_id) {
g_source_remove (win_id);
}
win_id = 0;
if (currentMode == MODE_TUX){
to_tux = FALSE;
if (tux_id) {
g_source_remove (tux_id);
}
tux_id =0;
}
/* Now destroy all items */
if(boardRootItem!=NULL)
goo_canvas_item_remove(boardRootItem);
boardRootItem=NULL;
// Clear the memoryArray
for(x=0; xsecond_value);
g_free(memoryArray[x][y]);
memoryArray[x][y] = NULL;
}
GList *list;
for (list = passed_token; list != NULL; list=list->next)
g_free(list->data);
g_list_free(passed_token);
passed_token = NULL;
if (currentMode == MODE_TUX){
for (list = winning_pairs; list != NULL; list=list->next)
g_free(list->data);
g_list_free(winning_pairs);
winning_pairs = NULL;
if (tux_memory)
while (g_queue_pop_head (tux_memory));
}
}
/*
* Takes care to return a random pair of images (one by one)
* the image is loaded in memoryItem->image
*
*/
static void get_image(MemoryItem *memoryItem, guint x, guint y)
{
guint rx, ry;
memoryItem->hidden = FALSE;
if(memoryArray[x][y])
{
// Get the pair's image
if (memoryArray[x][y]->type & (TYPE_ADD|TYPE_MINUS|TYPE_MULT|TYPE_DIV|TYPE_ENUMERATE|TYPE_WORDNUMBER)){
/* translate word for numbers */
if(memoryArray[x][y]->type == TYPE_WORDNUMBER) {
memoryItem->data = gettext(memoryArray[x][y]->second_value);
} else {
memoryItem->data = memoryArray[x][y]->second_value;
}
if (memoryArray[x][y]->type == TYPE_ENUMERATE) {
memoryItem->type = TYPE_ENUMERATE_IMAGE;
} else {
memoryItem->type = memoryArray[x][y]->type;
}
memoryArray[x][y] = memoryItem;
// if created by g_malloc0, this is not usefull;
//memoryItem->second_value = NULL;
}
else {
memoryItem->data = memoryArray[x][y]->data;
memoryItem->type = memoryArray[x][y]->type;
memoryArray[x][y] = memoryItem;
}
return;
}
memoryArray[x][y] = memoryItem;
switch (currentBoardMode) {
case BOARDMODE_SOUND:
get_random_token ( TYPE_SOUND, &memoryItem->type, &memoryItem->data, NULL);
g_assert (memoryItem->type == TYPE_SOUND);
break;
case BOARDMODE_NORMAL:
switch(gcomprisBoard->level) {
case 0:
case 1:
case 2:
case 3:
case 4:
/* Image mode */
get_random_token ( TYPE_IMAGE, &memoryItem->type, &memoryItem->data, NULL);
g_assert (memoryItem->type == TYPE_IMAGE);
break;
case 5:
/* Limited Text mode Numbers only */
get_random_token ( TYPE_NUMBER, &memoryItem->type, &memoryItem->data, NULL);
g_assert (memoryItem->type == TYPE_NUMBER);
break;
case 6:
/* Limited Text mode Numbers + Capitals */
get_random_token ( TYPE_NUMBER | TYPE_UPPERCASE, &memoryItem->type, &memoryItem->data, NULL);
g_assert((memoryItem->type == TYPE_NUMBER)||(memoryItem->type==TYPE_UPPERCASE));
break;
default:
/* Text mode ALL */
get_random_token ( TYPE_NUMBER | TYPE_UPPERCASE | TYPE_LOWERCASE, &memoryItem->type, &memoryItem->data, NULL);
g_assert (memoryItem->type & ( TYPE_NUMBER | TYPE_UPPERCASE | TYPE_LOWERCASE));
break;
}
break;
case BOARDMODE_ADD:
get_random_token ( TYPE_ADD, &memoryItem->type, &memoryItem->data, &memoryItem->second_value);
g_assert (memoryItem->type == TYPE_ADD);
break;
case BOARDMODE_MINUS:
get_random_token ( TYPE_MINUS, &memoryItem->type, &memoryItem->data, &memoryItem->second_value);
g_assert (memoryItem->type == TYPE_MINUS);
break;
case BOARDMODE_MULT:
get_random_token ( TYPE_MULT, &memoryItem->type, &memoryItem->data, &memoryItem->second_value);
g_assert (memoryItem->type == TYPE_MULT);
break;
case BOARDMODE_DIV:
get_random_token ( TYPE_DIV, &memoryItem->type, &memoryItem->data, &memoryItem->second_value);
g_assert (memoryItem->type == TYPE_DIV);
break;
case BOARDMODE_ADD_MINUS:
get_random_token ( TYPE_ADD | TYPE_MINUS, &memoryItem->type, &memoryItem->data, &memoryItem->second_value);
g_assert (memoryItem->type & (TYPE_ADD | TYPE_MINUS));
break;
case BOARDMODE_MULT_DIV:
get_random_token ( TYPE_MULT | TYPE_DIV, &memoryItem->type, &memoryItem->data, &memoryItem->second_value);
g_assert (memoryItem->type & (TYPE_MULT | TYPE_DIV));
break;
case BOARDMODE_ADD_MINUS_MULT_DIV:
get_random_token ( TYPE_ADD | TYPE_MINUS |TYPE_MULT | TYPE_DIV , &memoryItem->type, &memoryItem->data, &memoryItem->second_value);
g_assert (memoryItem->type & (TYPE_ADD | TYPE_MINUS |TYPE_MULT | TYPE_DIV));
break;
case BOARDMODE_ENUMERATE:
get_random_token ( TYPE_ENUMERATE , &memoryItem->type, &memoryItem->data, &memoryItem->second_value);
g_assert (memoryItem->type & TYPE_ENUMERATE);
break;
case BOARDMODE_WORDNUMBER:
get_random_token ( TYPE_WORDNUMBER , &memoryItem->type, &memoryItem->data, &memoryItem->second_value);
g_assert (memoryItem->type & TYPE_WORDNUMBER);
break;
default:
g_error("Don't now in what mode run !");
break;
}
g_warning("returned token %s for item x=%d y=%d", memoryItem->data, x, y);
// Randomly set the pair
rx = g_random_int_range( 0, numberOfColumn);
ry = g_random_int_range(0, numberOfLine);
while(memoryArray[rx][ry])
{
rx++;
// Wrap
if(rx>=numberOfColumn)
{
rx=0;
ry++;
if(ry>=numberOfLine)
ry=0;
}
}
// Makes the pair point to this memoryItem for now
memoryArray[rx][ry] = memoryItem;
}
static void create_item(GooCanvasItem *parent)
{
MemoryItem *memoryItem;
gint x, y;
double height, width;
double height2, width2;
GdkPixbuf *pixmap = NULL;
// Calc width and height of one card
width = (base_x2-(currentMode == MODE_TUX ? base_x1_tux : base_x1))/numberOfColumn;
height = (base_y2-base_y1)/numberOfLine;
// Respect the card ratio
if( width * 1.418 > height)
width = height * 0.704;
else
height = width * 1.418;
/* Remove a little bit of space for the card shadow */
height2 = height * 0.95;
width2 = width * 0.95;
if (currentUiMode == UIMODE_SOUND) {
goo_canvas_rect_new (parent,
(currentMode == MODE_TUX ? base_x1_tux : base_x1) - 20,
base_y1 - 15,
width * numberOfColumn + 20*2,
height * numberOfLine + 15*2,
"stroke_color_rgba", 0xFFFFFFFFL,
"fill_color_rgba", 0x66666690L,
"line-width", (double) 2,
"radius-x", (double) 10,
"radius-y", (double) 10,
NULL);
}
if (currentMode == MODE_TUX){
GdkPixbuf *pixmap_tux = gc_pixmap_load("memory/tux-teacher.png");
tux = goo_canvas_image_new (parent,
pixmap_tux,
50,
140,
NULL);
#if GDK_PIXBUF_MAJOR <= 2 && GDK_PIXBUF_MINOR <= 24
gdk_pixbuf_unref(pixmap_tux);
#else
g_object_unref(pixmap_tux);
#endif
tux_score = goo_canvas_text_new (parent,
"",
(double) 115,
(double) 235,
-1,
GTK_ANCHOR_CENTER,
"font", gc_skin_font_board_huge_bold,
"fill_color_rgba", 0xFF0F0FFF,
NULL);
player_score = goo_canvas_text_new (parent,
"",
(double) 100,
(double) BASE_CARD_Y2 - 20,
-1,
GTK_ANCHOR_CENTER,
"font", gc_skin_font_board_huge_bold,
"fill_color_rgba", 0xFF0F0FFF,
NULL);
}
for(x=0; xrootItem = \
goo_canvas_group_new (parent,
NULL);
goo_canvas_item_translate(memoryItem->rootItem,
(currentMode == MODE_TUX ? base_x1_tux : base_x1) + x*width,
base_y1 + y*height);
if (currentUiMode == UIMODE_SOUND)
pixmap = gc_pixmap_load("memory/Tux_mute.png");
else
pixmap = gc_pixmap_load("memory/backcard.png");
memoryItem->backcardItem = \
goo_canvas_image_new (memoryItem->rootItem,
pixmap,
0,
0,
NULL);
goo_canvas_item_scale(memoryItem->backcardItem,
width2 / gdk_pixbuf_get_width(pixmap),
height2 / gdk_pixbuf_get_height(pixmap));
#if GDK_PIXBUF_MAJOR <= 2 && GDK_PIXBUF_MINOR <= 24
gdk_pixbuf_unref(pixmap);
#else
g_object_unref(pixmap);
#endif
if (currentUiMode != UIMODE_SOUND){
pixmap = gc_pixmap_load("memory/emptycard.png");
memoryItem->framecardItem = \
goo_canvas_image_new (memoryItem->rootItem,
pixmap,
0,
0,
NULL);
goo_canvas_item_scale(memoryItem->framecardItem,
(width2 / gdk_pixbuf_get_width(pixmap)),
(height2 / gdk_pixbuf_get_height(pixmap)));
g_object_set (memoryItem->framecardItem, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
#if GDK_PIXBUF_MAJOR <= 2 && GDK_PIXBUF_MINOR <= 24
gdk_pixbuf_unref(pixmap);
#else
g_object_unref(pixmap);
#endif
}
// Display the image itself while taking care of its size and maximize the ratio
get_image(memoryItem, x, y);
if (currentUiMode == UIMODE_SOUND){
pixmap = gc_pixmap_load("memory/Tux_play.png");
memoryItem->frontcardItem = \
goo_canvas_image_new (memoryItem->rootItem,
pixmap,
0,
0,
NULL);
goo_canvas_item_scale(memoryItem->frontcardItem,
(width2 / gdk_pixbuf_get_width(pixmap)),
(height2 / gdk_pixbuf_get_height(pixmap)));
#if GDK_PIXBUF_MAJOR <= 2 && GDK_PIXBUF_MINOR <= 24
gdk_pixbuf_unref(pixmap);
#else
g_object_unref(pixmap);
#endif
}
else {
if(memoryItem->type & (TYPE_IMAGE|TYPE_ENUMERATE_IMAGE)) {
pixmap = gc_pixmap_load(memoryItem->data);
memoryItem->frontcardItem = \
goo_canvas_image_new (memoryItem->rootItem,
pixmap,
0.0,
0.0,
NULL);
/* scale only in ENUMERATE (image size too big) */
if(memoryItem->type == TYPE_ENUMERATE_IMAGE) {
goo_canvas_item_scale(memoryItem->frontcardItem,
(0.9*width2 / gdk_pixbuf_get_width(pixmap)),
(0.9*height2 / gdk_pixbuf_get_height(pixmap)));
goo_canvas_item_translate(memoryItem->frontcardItem,
0.1 * width2,
0.1 * height2);
} else {
goo_canvas_item_translate(memoryItem->frontcardItem,
(width2 - gdk_pixbuf_get_width(pixmap))/2,
(height2 - gdk_pixbuf_get_height(pixmap))/2);
}
#if GDK_PIXBUF_MAJOR <= 2 && GDK_PIXBUF_MINOR <= 24
gdk_pixbuf_unref(pixmap);
#else
g_object_unref(pixmap);
#endif
} else {
gchar *font;
if (memoryItem->type & (TYPE_ADD|TYPE_MINUS|TYPE_MULT|TYPE_DIV))
font = op_fonts[gcomprisBoard->level];
else
font = TEXT_FONT;
/* It's a letter */
memoryItem->frontcardItem = \
goo_canvas_text_new (memoryItem->rootItem,
memoryItem->data,
(double) (width2)/2,
(double) (height2)/2,
-1,
GTK_ANCHOR_CENTER,
"font", font,
"fill_color_rgba", 0x000000FF,
NULL);
if(memoryItem->type == TYPE_WORDNUMBER){
gcompris_adapt_font_size(GOO_CANVAS_TEXT(memoryItem->frontcardItem), width2, height2);
}
}
}
g_object_set (memoryItem->frontcardItem, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
g_signal_connect(memoryItem->rootItem, "button_press_event",
(GCallback) item_event,
memoryItem);
}
}
//return (NULL);
}
static void player_win()
{
gc_sound_play_ogg ("sounds/bonus.wav", NULL);
/* Try the next level */
if (tux_pairs <= player_pairs)
gcomprisBoard->level++;
if(gcomprisBoard->level>gcomprisBoard->maxlevel)
gcomprisBoard->level = gcomprisBoard->maxlevel;
gc_bonus_display((tux_pairs <= player_pairs), GC_BONUS_LION);
}
static void display_card(MemoryItem *memoryItem, CardStatus cardStatus)
{
if (currentUiMode == UIMODE_SOUND){
switch (cardStatus)
{
case ON_FRONT:
g_assert(memoryItem->hidden == FALSE);
g_object_set (memoryItem->backcardItem, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
g_object_set (memoryItem->frontcardItem, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
playing_sound = TRUE;
gc_sound_play_ogg_cb (memoryItem->data, sound_callback);
break;
case ON_BACK:
g_object_set (memoryItem->backcardItem, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
g_object_set (memoryItem->frontcardItem, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
break;
case HIDDEN:
g_object_set (memoryItem->backcardItem, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
g_object_set (memoryItem->frontcardItem, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
memoryItem->hidden = TRUE;
break;
}
}
else {
switch (cardStatus)
{
case ON_FRONT:
g_assert(memoryItem->hidden == FALSE);
g_object_set (memoryItem->backcardItem, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
g_object_set (memoryItem->framecardItem, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
g_object_set (memoryItem->frontcardItem, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
break;
case ON_BACK:
g_object_set (memoryItem->backcardItem, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
g_object_set (memoryItem->framecardItem, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
g_object_set (memoryItem->frontcardItem, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
break;
case HIDDEN:
g_object_set (memoryItem->backcardItem, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
g_object_set (memoryItem->framecardItem, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
g_object_set (memoryItem->frontcardItem, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
memoryItem->hidden = TRUE;
break;
}
}
}
/*
* Used to hide card after a timer
*
*/
static gint hide_card (GtkWidget *widget, gpointer data)
{
if (currentMode == MODE_TUX){
GList *list = NULL;
GList *to_remove = NULL;
for (list = winning_pairs; list != NULL; list=list->next)
if ((((WINNING *) list->data)->first == firstCard) ||
(((WINNING *) list->data)->first == secondCard) ||
(((WINNING *) list->data)->second == firstCard) ||
(((WINNING *) list->data)->second == secondCard) ){
to_remove = g_list_append( to_remove, list->data);
}
for (list = to_remove; list != NULL; list=list->next){
void *data = list->data;
winning_pairs = g_list_remove (winning_pairs, list->data);
g_free (data);
g_warning("Again %d winning pairs in tux list! ", g_list_length(winning_pairs));
}
g_list_free(to_remove);
if (to_tux)
tux_pairs++;
else
player_pairs++;
update_scores();
}
if(firstCard!=NULL)
{
display_card(firstCard, HIDDEN);
if (currentMode == MODE_TUX)
remove_card_from_tux_memory(firstCard);
firstCard = NULL;
}
if(secondCard!=NULL)
{
display_card(secondCard, HIDDEN);
if (currentMode == MODE_TUX)
remove_card_from_tux_memory(secondCard);
secondCard = NULL;
}
win_id = 0;
remainingCards -= 2;
if(remainingCards<=0){
if (currentMode == MODE_TUX){
if (tux_id){
g_source_remove(tux_id);
tux_id = 0;
to_tux = FALSE;
}
}
player_win();
}
return (FALSE);
}
static void check_win()
{
gint timeout, timeout_tux;
if (currentUiMode == UIMODE_SOUND){
timeout = 200;
timeout_tux = 500;
}
else {
timeout = 1000;
timeout_tux = 2000;
}
// Check win
if (compare_card((gpointer) firstCard, (gpointer) secondCard) == 0) {
gc_sound_play_ogg ("sounds/flip.wav", NULL);
win_id = g_timeout_add (timeout,
(GSourceFunc) hide_card, NULL);
lock_user = FALSE;
return;
}
if (currentMode == MODE_TUX){
/* time to tux to play, after a delay */
to_tux = TRUE;
g_warning("Now tux will play !");
tux_id = g_timeout_add (timeout_tux,
(GSourceFunc) tux_play, NULL);
lock_user = FALSE;
return;
}
}
static gboolean item_event (GooCanvasItem *item,
GooCanvasItem *target,
GdkEventButton *event,
MemoryItem *memoryItem)
{
if(!gcomprisBoard)
return FALSE;
if (currentUiMode == UIMODE_SOUND)
gc_sound_policy_set(PLAY_AND_INTERRUPT);
if (event->type != GDK_BUTTON_PRESS ||
event->button != 1)
return FALSE;
if (currentMode == MODE_TUX){
if (to_tux || lock_user){
g_warning("He ! it's tux turn !");
return FALSE;
}
}
if (playing_sound){
g_warning("wait a minute, the sound is playing !");
//return FALSE;
}
if(win_id)
return FALSE;
if (currentUiMode == UIMODE_NORMAL)
gc_sound_play_ogg ("sounds/bleep.wav", NULL);
if(secondCard)
{
display_card(firstCard, ON_BACK);
firstCard = NULL;
display_card(secondCard, ON_BACK);
secondCard = NULL;
}
if(!firstCard)
{
firstCard = memoryItem;
if (currentMode == MODE_TUX)
add_card_in_tux_memory(memoryItem);
display_card(memoryItem, ON_FRONT);
return TRUE;
}
else
{
// Check he/she did not click on the same card twice
if(firstCard==memoryItem)
return FALSE;
secondCard = memoryItem;
if (currentMode == MODE_TUX)
add_card_in_tux_memory(memoryItem);
display_card(memoryItem, ON_FRONT);
if (currentUiMode == UIMODE_SOUND) {
// Check win is called from callback return
// The user lost, make sure she won't play again before tux
lock_user = TRUE;
return TRUE;
} else {
check_win();
return TRUE;
}
}
return FALSE;
}
void add_card_in_tux_memory(MemoryItem *card)
{
MemoryItem *first = NULL;
g_warning("Adding card %s in tux memory ", card->data);
/* check if card is already in memory */
remove_card_from_tux_memory(card);
first = find_card_in_tux_memory(card);
if (first){
g_warning("found %s and %s !", first->data, card->data);
WINNING *win = g_malloc0(sizeof(WINNING));
win->first = card;
win->second = first;
winning_pairs = g_list_append( winning_pairs, win);
g_warning("Now %d winning pairs in tux list! ", g_list_length(winning_pairs));
remove_card_from_tux_memory(first);
}
g_queue_push_head(tux_memory, card);
if (g_queue_get_length (tux_memory)>tux_memory_size){
g_queue_pop_tail(tux_memory);
g_warning("Now tuxmemory size = %d", g_queue_get_length (tux_memory));
}
}
static gint
compare_card (gconstpointer a,
gconstpointer b)
{
MemoryItem *card1 = (MemoryItem *)a;
MemoryItem *card2 = (MemoryItem *)b;
if (card1->type & (TYPE_ADD|TYPE_MINUS|TYPE_MULT|TYPE_DIV|TYPE_ENUMERATE|TYPE_ENUMERATE_IMAGE|TYPE_WORDNUMBER)){
if ((!card1->second_value) && ( card2->second_value)){
return strcmp(card1->data,card2->second_value);
}
if ((!card2->second_value) && ( card1->second_value)){
return strcmp(card2->data,card1->second_value);
}
return -1;
}
return ((card1->data == card2->data) ? 0 : -1);
}
MemoryItem *find_card_in_tux_memory(MemoryItem *card)
{
GList *link;
if ((link = g_queue_find_custom(tux_memory, card, compare_card)) != NULL)
return link->data;
else
return NULL;
}
void remove_card_from_tux_memory(MemoryItem *card)
{
g_queue_remove(tux_memory, card);
}
static gint tux_play(){
int rx, ry;
if (Paused){
g_warning("Paused");
return TRUE;
}
if ( ! to_tux )
return TRUE;
if(secondCard)
{
display_card(firstCard, ON_BACK);
firstCard = NULL;
display_card(secondCard, ON_BACK);
secondCard = NULL;
}
if (winning_pairs){
if (!firstCard){
firstCard = ((WINNING *) winning_pairs->data)->first ;
display_card(firstCard, ON_FRONT);
if (currentUiMode == UIMODE_SOUND)
return FALSE;
else
return TRUE;
} else {
secondCard = ((WINNING *) winning_pairs->data)->second;
display_card(secondCard, ON_FRONT);
if (currentUiMode == UIMODE_SOUND)
return FALSE;
else {
gc_sound_play_ogg ("sounds/flip.wav", NULL);
win_id = g_timeout_add (1000,
(GSourceFunc) hide_card, NULL);
return TRUE;
}
}
}
// Randomly set the pair
rx = g_random_int_range( 0, numberOfColumn);
ry = g_random_int_range(0, numberOfLine);
gboolean stay_unknown = (remainingCards > (g_queue_get_length (tux_memory)
+ (firstCard ? 1 : 0)));
g_warning("remainingCards %d tux_memory %d -> stay_unknown %d",
remainingCards,
g_queue_get_length (tux_memory),
stay_unknown );
while((memoryArray[rx][ry]->hidden) || (memoryArray[rx][ry] == firstCard)
|| (stay_unknown && g_queue_find(tux_memory,memoryArray[rx][ry])))
{
g_warning("Loop to find %d %d %s", rx, ry, memoryArray[rx][ry]->data);
rx++;
// Wrap
if(rx>=numberOfColumn)
{
rx=0;
ry++;
if(ry>=numberOfLine)
ry=0;
}
}
if (!firstCard){
firstCard = memoryArray[rx][ry];
add_card_in_tux_memory(firstCard);
display_card(firstCard, ON_FRONT);
if (currentUiMode == UIMODE_SOUND)
return FALSE;
else
return TRUE;
} else {
secondCard = memoryArray[rx][ry];
add_card_in_tux_memory(secondCard);
display_card(secondCard, ON_FRONT);
if (currentUiMode == UIMODE_SOUND)
return FALSE;
else {
if (compare_card(firstCard, secondCard)==0){
gc_sound_play_ogg ("sounds/flip.wav", NULL);
win_id = g_timeout_add (1000,
(GSourceFunc) hide_card, NULL);
return TRUE;
} else{
to_tux = FALSE;
return FALSE;
}
}
}
return FALSE;
}
static void sound_callback(gchar *file)
{
if (! gcomprisBoard)
return;
if (!playing_sound)
return;
playing_sound = FALSE;
if (currentMode == MODE_TUX){
if (to_tux) {
if (firstCard && secondCard){
if (compare_card(firstCard, secondCard)==0){
gc_sound_play_ogg ("sounds/gobble.wav", NULL);
win_id = g_timeout_add (1000,
(GSourceFunc) hide_card, NULL);
tux_id = g_timeout_add (2000,
(GSourceFunc) tux_play, NULL);
return;
} else {
to_tux = FALSE;
return;
}
} else {
tux_id = g_timeout_add (2000,
(GSourceFunc) tux_play, NULL);
return;
}
}
}
if (firstCard && secondCard)
check_win();
}
static void start_callback(gchar *file){
if (!gcomprisBoard)
return;
if (currentUiMode != UIMODE_SOUND)
return;
playing_sound = FALSE;
}
static void gcompris_adapt_font_size(GooCanvasText *textItem, gdouble width, gdouble height) {
g_assert ((width > 0) && (height > 0));
gdouble wscale, hscale, scale;
/* Get size of the text */
PangoRectangle ink, log;
goo_canvas_text_get_natural_extents (textItem,
&ink,
&log);
/* get real size */
gint lwidth = PANGO_PIXELS(log.width);
gint lheight = PANGO_PIXELS(log.height);
/* Calculate scale to get text fit in width and height */
wscale = lwidth > ((int) width) ? width / lwidth : 1.0;
hscale = lheight > ((int) height) ? height / lheight : 1.0;
/* scale is MIN */
scale = wscale < hscale ? wscale : hscale;
if(scale == 1.0)
return;
/* get and change the font description */
PangoFontDescription *desc;
g_object_get(textItem, "font-desc", &desc, NULL);
gint size = pango_font_description_get_size(desc) * scale;
pango_font_description_set_size(desc, size);
g_object_set(textItem, "font-desc", desc, NULL);
}