Back to index

gcompris  8.2.2
magic_hat.c
Go to the documentation of this file.
00001 /* gcompris - magic_hat.c
00002  *
00003  * Copyright (C) 2006 Marc BRUN
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU General Public License as published by
00007  *   the Free Software Foundation; either version 2 of the License, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHMINUS ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details.
00014  *
00015  *   You should have received a copy of the GNU General Public License
00016  *   along with this program; if not, write to the Free Software
00017  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #include "gcompris/gcompris.h"
00021 #include <string.h>
00022 
00023 #define MH_FRAME1_X 420            // Coordonates for the first frame (first operand of the operation)
00024 #define MH_FRAME1_Y 60
00025 #define MH_FRAME2_X 420            // Coordonates for the second frame (second operand of the operation)
00026 #define MH_FRAME2_Y 200 
00027 #define MH_FRAME_PLAYER_X 420      // Coordonates for the 'player' frame
00028 #define MH_FRAME_PLAYER_Y 380
00029 
00030 #define MH_HAT_X     190    // Coordonates for the hat  
00031 #define MH_HAT_Y     90
00032 #define MH_HAT_HEIGHT       250
00033 #define MH_HAT_WIDTH 130
00034 #define POINT        0      // Which hat to draw ? The one with an interrogation point or
00035 #define STARS        1      // the one with stars ?
00036 
00037 #define NORMAL              0
00038 #define EMPTY        1
00039 #define UNDERHAT     2
00040 #define DYNAMIC             3
00041 
00042 #define MAX_ITEM 10         // Max number for an item in a list
00043 #define MAX_LIST 3          // Max number of list of items
00044 #define ITEM_SIZE 30        // Items are squares (or square-included)
00045 #define SPACE_BETWEEN_ITEMS 5
00046 
00047 #define MODE_MINUS   0
00048 #define MODE_PLUS    1
00049 #define DEFAULT_MODE MODE_MINUS
00050 
00051 // Types
00052 
00053 // This structure describes a frame (there are 3 of them on the board) 
00054 typedef struct {
00055   int         id;           
00056   double      coord_x;
00057   double      coord_y;
00058   int         nb_stars[MAX_LIST];
00059   int         array_star_type[MAX_LIST][MAX_ITEM];
00060   GnomeCanvasItem *array_item[MAX_LIST][MAX_ITEM];
00061 } frame;
00062 
00063 // This structure decribes a movement
00064 typedef struct {
00065   int i;                // i index in array_item
00066   int j;                // j index in array_item
00067   double dx;
00068   double dy;
00069   int nb;               // how much of x/y movement (to give a smooth effect) ?
00070   int frame;         // number of the concerned frame (1 or 2)
00071 } move_object;
00072 
00073 // Global variables
00074 static GcomprisBoard *gcomprisBoard = NULL;
00075 static gboolean board_paused = TRUE;
00076 static GnomeCanvasGroup *boardRootItem = NULL;
00077 static gint timer_id = 0;
00078 static gint board_mode = DEFAULT_MODE;
00079 static gint hat_event_id;   // value returned by gtk_signal_connect. Used by gtk_signal_disconnect
00080 
00081 static GnomeCanvasItem      *hat;
00082 static frame frame1;
00083 static frame frame2;
00084 static frame frame_player;
00085 
00086 // gcompris functions
00087 static void    start_board (GcomprisBoard *agcomprisBoard);
00088 static void    pause_board (gboolean pause);
00089 static void    end_board (void);
00090 static gboolean       is_our_board (GcomprisBoard *gcomprisBoard);
00091 static void    process_ok ();
00092 static void    set_level (guint level);
00093 static int     gamewon;
00094 static void    game_won(void);
00095 
00096 static GnomeCanvasItem      *magic_hat_create_item();
00097 static void           magic_hat_destroy_all_items(void);
00098 static void           magic_hat_next_level(void);
00099 
00100 // magic_hat functions
00101 static void draw_frame(frame *);
00102 static void draw_table(void);
00103 static void draw_hat(int);
00104 static void place_item(frame *, int);
00105 static gint hat_event(GnomeCanvasItem *, GdkEvent *, gpointer);
00106 static gint item_event(GnomeCanvasItem *, GdkEvent *, gpointer);
00107 static int  nb_list();
00108 static gint smooth_move(move_object *);
00109 static gint move_stars(frame *);
00110 static gint close_hat();
00111 
00112 /* Description of this plugin */
00113 static BoardPlugin menu_bp =
00114   {
00115     NULL,
00116     NULL,
00117     "Give the result of an operation.",
00118     "Click on the bottom left stars to give the result of the operation.",
00119     "Marc BRUN",
00120     NULL,
00121     NULL,
00122     NULL,
00123     NULL,
00124     start_board,
00125     pause_board,
00126     end_board,
00127     is_our_board,
00128     NULL,
00129     process_ok,
00130     set_level,
00131     NULL,
00132     NULL,
00133     NULL,
00134     NULL
00135   };
00136 
00137 /*
00138  * Main entry point mandatory for each Gcompris's game
00139  * ---------------------------------------------------
00140  *
00141  */
00142 
00143 GET_BPLUGIN_INFO(magic_hat)
00144 
00145 static void pause_board (gboolean pause)
00146 {
00147   if (gcomprisBoard == NULL)
00148     return;
00149 
00150   if (timer_id) {
00151     gtk_timeout_remove (timer_id);
00152     timer_id = 0;
00153   }
00154 
00155   /* the game is won */
00156   if (gamewon == TRUE && pause == FALSE)
00157        game_won();
00158 
00159   board_paused = pause;
00160 }
00161 
00162 static void start_board (GcomprisBoard *agcomprisBoard)
00163 {
00164 
00165   if (agcomprisBoard != NULL) {
00166         gchar *img;
00167 
00168        gcomprisBoard = agcomprisBoard;
00169        gcomprisBoard->level = 1;
00170        gcomprisBoard->maxlevel = 9;
00171        gcomprisBoard->sublevel = 1;
00172        gcomprisBoard->number_of_sublevel = 1;    // Go to next level after this number of 'play'
00173        gc_bar_set(GC_BAR_LEVEL|GC_BAR_OK);
00174 
00175        if (strcmp(gcomprisBoard->mode, "minus") == 0)
00176               board_mode = MODE_MINUS;
00177        else if (strcmp(gcomprisBoard->mode, "plus") == 0)
00178               board_mode = MODE_PLUS;
00179        else
00180               board_mode = DEFAULT_MODE;
00181 
00182        img = gc_skin_image_get("gcompris-bg.jpg");
00183        gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), img);
00184        g_free(img);
00185 
00186        magic_hat_next_level();
00187 
00188        gamewon = FALSE;
00189        pause_board(FALSE);
00190   }
00191 }
00192 
00193 static void end_board () {
00194 
00195   if (timer_id) {
00196        gtk_timeout_remove (timer_id);
00197        timer_id = 0;
00198   }
00199 
00200   if (gcomprisBoard != NULL) {
00201        pause_board(TRUE);
00202        magic_hat_destroy_all_items();
00203   }
00204 
00205   gcomprisBoard = NULL;
00206 }
00207 
00208 // Check if player has won
00209 static void process_ok() {
00210 
00211   int i;
00212   int ok = TRUE;
00213 
00214   if (board_mode == MODE_MINUS) {
00215        for (i = 0 ; i < nb_list() ; i++) {
00216               if (frame1.nb_stars[i] != (frame2.nb_stars[i] + frame_player.nb_stars[i]))
00217                      ok = FALSE;
00218        }
00219   } else {
00220        for (i = 0 ; i < nb_list() ; i++) {
00221               if (frame_player.nb_stars[i] != (frame1.nb_stars[i] + frame2.nb_stars[i]))
00222                      ok = FALSE;
00223        }
00224   }
00225 
00226   if (ok) {
00227        gamewon = TRUE;
00228        gc_sound_play_ogg ("sounds/bonus.ogg", NULL);
00229   }
00230 
00231   gc_bonus_display(gamewon, BONUS_FLOWER);
00232 
00233 }
00234 
00235 /* ======================================= */
00236 static void set_level (guint level) {
00237 
00238   if (gcomprisBoard != NULL) {
00239          
00240       gcomprisBoard->level = level;
00241       gcomprisBoard->sublevel = 1;
00242       magic_hat_next_level();
00243   }
00244 }
00245 /* ======================================= */
00246 static gboolean is_our_board (GcomprisBoard *gcomprisBoard) {
00247 
00248   if (gcomprisBoard) {
00249 
00250       if (g_strcasecmp(gcomprisBoard->type, "magic_hat") == 0) {
00251 
00252          /* Set the plugin entry */
00253          gcomprisBoard->plugin = &menu_bp;
00254          return TRUE;
00255        }
00256   }
00257 
00258   return FALSE;
00259 }
00260 
00261 /*-------------------------------------------------------------------------------*/
00262 /*-------------------------------------------------------------------------------*/
00263 /* set initial values for the next level */
00264 static void magic_hat_next_level() {
00265 
00266   gc_bar_set_level(gcomprisBoard);
00267 
00268   magic_hat_destroy_all_items();
00269   gamewon = FALSE;
00270 
00271   /* Try the next level */
00272   magic_hat_create_item();
00273 }
00274   
00275 /* ==================================== */
00276 /* Destroy all the items */
00277 static void magic_hat_destroy_all_items()
00278 {
00279   if (timer_id) {
00280     gtk_timeout_remove (timer_id);
00281     timer_id = 0;
00282   }
00283 
00284   if(boardRootItem != NULL)
00285        gtk_object_destroy (GTK_OBJECT(boardRootItem));
00286 
00287   boardRootItem = NULL;
00288 }
00289 
00290 /* ==================================== */
00291 static GnomeCanvasItem *magic_hat_create_item()
00292 {
00293   int i, j;
00294   GdkPixbuf *pixmap;
00295   int step;
00296 
00297   boardRootItem = GNOME_CANVAS_GROUP(gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
00298                                  gnome_canvas_group_get_type (),
00299                                  "x", (double) 0,
00300                                  "y", (double) 0,
00301                                  NULL));
00302 
00303   if (board_mode == MODE_MINUS)
00304        pixmap = gc_pixmap_load("magic_hat/magic_hat_minus_bg.png");
00305   else
00306        pixmap = gc_pixmap_load("magic_hat/magic_hat_plus_bg.png");
00307 
00308   gnome_canvas_item_new (boardRootItem,
00309                       gnome_canvas_pixbuf_get_type(),
00310                       "pixbuf", pixmap,
00311                       "x", 0.0,
00312                       "y", 0.0,
00313                       "anchor", GTK_ANCHOR_NW,
00314                       NULL);
00315   gdk_pixbuf_unref(pixmap);
00316 
00317   // Initialisation for frame1
00318   frame1.id = 1;
00319   frame1.coord_x = MH_FRAME1_X;
00320   frame1.coord_y = MH_FRAME1_Y;
00321 
00322   // Initialisation for frame1
00323   frame2.id = 2;
00324   frame2.coord_x = MH_FRAME2_X;
00325   frame2.coord_y = MH_FRAME2_Y;
00326 
00327   // Initialisation for frame1
00328   frame_player.id = 3;
00329   frame_player.coord_x = MH_FRAME_PLAYER_X;
00330   frame_player.coord_y = MH_FRAME_PLAYER_Y;
00331 
00332   // The three frames of this activity : one for the sentence of the magician (top left), one for
00333   // the items out of the hat (top right), one for the answer of the payer (bottom right)
00334   draw_frame(&frame1);
00335   draw_frame(&frame2);
00336   draw_frame(&frame_player);
00337 
00338   // Description of the 9 levels for substraction
00339   // Level 1 : one list (yellow stars), from 2 to 4 stars in frame 1
00340   // Level 2 : one list (yellow stars), from 2 to 7 stars in frame 1
00341   // Level 3 : one list (yellow stars), from 2 to 10 stars in frame 1
00342   // Level 4 : two lists (yellow and green stars), from 2 to 4 stars in frame 1
00343   // Level 5 : two lists (yellow and green stars), from 2 to 7 stars in frame 1
00344   // Level 6 : two lists (yellow and green stars), from 2 to 10 stars in frame 1
00345   // Level 7 : three lists (yellow, green and blue stars), from 2 to 4 stars in frame 1
00346   // Level 8 : three lists (yellow, green and blue stars), from 2 to 7 stars in frame 1
00347   // Level 9 : three lists (yellow, green and blue stars), from 2 to 10 stars in frame 1
00348   //
00349   // Description of the 9 levels for addition
00350   // Level 1 : one list (yellow stars), from 2 to 4 for the total
00351   // Level 2 : one list (yellow stars), from 2 to 7 for the total
00352   // Level 3 : one list (yellow stars), from 2 to 10 for the total
00353   // Level 4 : two lists (yellow and green stars), from 2 to 4 for the total
00354   // Level 5 : two lists (yellow and green stars), from 2 to 7 for the total
00355   // Level 6 : two lists (yellow and green stars), from 2 to 10 for the total
00356   // Level 7 : three lists (yellow, green and blue stars), from 2 to 4 for the total
00357   // Level 8 : three lists (yellow, green and blue stars), from 2 to 7 for the total
00358   // Level 9 : three lists (yellow, green and blue stars), from 2 to 10 for the total
00359   
00360   step = 3;
00361 
00362   for (i = 0 ; i < nb_list() ; i++) {
00363 
00364        // Frame 1
00365        if (board_mode == MODE_MINUS)
00366               frame1.nb_stars[i] = RAND(2, (1 + (step * nb_list()))); // Minimum 2 to avoid '0' value (which is not easy to understand for kids)
00367        else
00368               frame1.nb_stars[i] = RAND(1, (step * nb_list()));
00369 
00370        for (j = 0 ; j < frame1.nb_stars[i] ; j++) frame1.array_star_type[i][j] = i;
00371        for ( ; j < MAX_ITEM ; j++) frame1.array_star_type[i][j] = -1;
00372        for (j = 0 ; j < MAX_ITEM ; j++) frame1.array_item[i][j] = gnome_canvas_item_new (boardRootItem, gnome_canvas_pixbuf_get_type(), NULL);
00373 
00374        // Frame 2
00375        if (board_mode == MODE_MINUS)
00376               frame2.nb_stars[i] = RAND(1, (frame1.nb_stars[i]) - 1); // Minimum 1 to avoid '0'
00377        else
00378               frame2.nb_stars[i] = RAND(1, ((step * nb_list()) - frame1.nb_stars[i] + 1));
00379 
00380        for (j = 0 ; j < frame2.nb_stars[i] ; j++) frame2.array_star_type[i][j] = i;
00381        for ( ; j < MAX_ITEM ; j++) frame2.array_star_type[i][j] = -1;
00382        for (j = 0 ; j < MAX_ITEM ; j++) frame2.array_item[i][j] = gnome_canvas_item_new (boardRootItem, gnome_canvas_pixbuf_get_type(), NULL);
00383 
00384        // Player frame
00385        frame_player.nb_stars[i] = 0;
00386        for (j = 0 ; j < MAX_ITEM ; j++) frame_player.array_star_type[i][j] = -1;
00387   }
00388 
00389   if (board_mode == MODE_MINUS) {
00390     place_item(&frame1, NORMAL);   // design the 'total' stars, with all the items
00391     place_item(&frame2, UNDERHAT); // design 'out' stars, all the items are hidden under the hat
00392   } else {
00393     place_item(&frame1, NORMAL);   // design the first frame stars, with all the items
00394     place_item(&frame2, NORMAL);   // design the second frame stars, with all the items
00395   }
00396 
00397   // The magic hat !! And its table
00398   // The hat is designed after the 'minus' items so that it hides them
00399   draw_hat(STARS);
00400   draw_table();
00401 
00402   return NULL;
00403 }
00404 
00405 // Display a 'end of game' animation
00406 static void finished() {
00407 
00408   gc_bonus_end_display(BOARD_FINISHED_RANDOM);
00409   timer_id = 0;
00410 }
00411 
00412 // One more level completed
00413 static void game_won() {
00414 
00415   gcomprisBoard->sublevel++;
00416 
00417   if (gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) {
00418        /* Try the next level */
00419        gcomprisBoard->sublevel = 1;
00420        gcomprisBoard->level++;
00421 
00422        if (gcomprisBoard->level>gcomprisBoard->maxlevel) { // all levels completed : the current board is finished
00423               timer_id = g_timeout_add (2000, (GtkFunction) finished, NULL);
00424               return;
00425        }
00426   }
00427   magic_hat_next_level();
00428 }
00429 
00430 // Draw a frame with empty small squares
00431 static void draw_frame(frame *my_frame) {
00432 
00433   GnomeCanvasItem *item_frame = NULL;
00434   int i, j;
00435   double x = my_frame->coord_x;
00436   double y = my_frame->coord_y;
00437   GnomeCanvasPoints *track;
00438 
00439   track = gnome_canvas_points_new(5);
00440 
00441   for (i = 0 ; i < nb_list() ; i++) {
00442 
00443          for (j = 0 ; j < MAX_ITEM ; j++) {
00444 
00445               track->coords[0] = x + (j * (ITEM_SIZE + SPACE_BETWEEN_ITEMS));
00446               track->coords[1] = y + (i * (ITEM_SIZE + SPACE_BETWEEN_ITEMS));
00447               track->coords[2] = x + (j * (ITEM_SIZE + SPACE_BETWEEN_ITEMS)) + ITEM_SIZE;
00448               track->coords[3] = y + (i * (ITEM_SIZE + SPACE_BETWEEN_ITEMS));
00449               track->coords[4] = x + (j * (ITEM_SIZE + SPACE_BETWEEN_ITEMS)) + ITEM_SIZE;
00450               track->coords[5] = y + (i * (ITEM_SIZE + SPACE_BETWEEN_ITEMS)) + ITEM_SIZE;
00451               track->coords[6] = x + (j * (ITEM_SIZE + SPACE_BETWEEN_ITEMS));
00452               track->coords[7] = y + (i * (ITEM_SIZE + SPACE_BETWEEN_ITEMS)) + ITEM_SIZE;
00453               track->coords[8] = x + (j * (ITEM_SIZE + SPACE_BETWEEN_ITEMS));
00454               track->coords[9] = y + (i * (ITEM_SIZE + SPACE_BETWEEN_ITEMS));
00455 
00456               item_frame = gnome_canvas_item_new (boardRootItem,
00457                      gnome_canvas_line_get_type (),
00458                      "points", track,
00459                      "width_pixels", 1,
00460                      "fill_color", "#948d85",
00461                      NULL);
00462        }
00463   }
00464   gnome_canvas_points_free(track);
00465 
00466   place_item(my_frame, EMPTY);
00467 
00468 }
00469 
00470 // Draw the table (line)
00471 static void draw_table() {
00472 
00473   GnomeCanvasItem *item_frame = NULL;
00474   GnomeCanvasPoints *track;
00475 
00476   track = gnome_canvas_points_new(2);
00477 
00478   track->coords[0] = MH_HAT_X;
00479   track->coords[1] = MH_HAT_Y + MH_HAT_HEIGHT + 5;
00480   track->coords[2] = MH_HAT_X + MH_HAT_WIDTH;
00481   track->coords[3] = MH_HAT_Y + MH_HAT_HEIGHT + 5;
00482 
00483   item_frame = gnome_canvas_item_new (boardRootItem,
00484               gnome_canvas_line_get_type (),
00485               "points", track,
00486               "width_pixels", 1,
00487               "fill_color", "black",
00488               NULL);
00489 
00490   gnome_canvas_points_free(track);
00491 }
00492 
00493 // Draw the hat
00494 static void draw_hat(int type) {
00495 
00496   GdkPixbuf *image;
00497 
00498   if (type == STARS)
00499        image = gc_pixmap_load("magic_hat/hat.png");
00500   else
00501        image = gc_pixmap_load("magic_hat/hat-point.png");
00502 
00503   hat = gnome_canvas_item_new (boardRootItem,
00504               gnome_canvas_pixbuf_get_type(),
00505               "pixbuf", image,
00506               "x", (double) MH_HAT_X,
00507               "y", (double) MH_HAT_Y,
00508               "width", (double) MH_HAT_WIDTH,
00509               "height", (double) MH_HAT_HEIGHT,
00510               "width_set", TRUE,
00511               "height_set", TRUE,
00512               "anchor", GTK_ANCHOR_NW,
00513               NULL);
00514 
00515   gdk_pixbuf_unref(image);
00516 
00517   if (type == STARS) {
00518         hat_event_id = gtk_signal_connect(GTK_OBJECT(hat), "event", (GtkSignalFunc) hat_event, NULL);
00519         gtk_signal_connect(GTK_OBJECT(hat), "event", (GtkSignalFunc) gc_item_focus_event, NULL);
00520   }
00521 }
00522 
00523 // Place items on the board
00524 //     frame * my_frame : which frame to create the items on ?
00525 //     int type         : four possible values
00526 //                          EMPTY => only grey stars, which symbolise an empty item
00527 //                          NORMAL => a coloured star
00528 //                          UNDERHAT => objects are not visible, they are localised under the hat
00529 //                          DYNAMIC => the items are made clicable (for the player frame)
00530 static void place_item(frame * my_frame, int type) {
00531 
00532   GnomeCanvasItem *item = NULL;
00533   int i, j;
00534   int k, nb_item;
00535   GdkPixbuf *image;
00536   double item_x, item_y;
00537   double x, y;
00538 
00539   GdkPixbuf *image_name[MAX_LIST];
00540   GdkPixbuf *image_star_clear = gc_pixmap_load("magic_hat/star-clear.png");
00541 
00542   image_name[0] = gc_pixmap_load("magic_hat/star1.png");
00543   image_name[1] = gc_pixmap_load("magic_hat/star2.png");
00544   image_name[2] = gc_pixmap_load("magic_hat/star3.png");
00545 
00546   x = my_frame->coord_x;
00547   y = my_frame->coord_y;
00548 
00549   for (i = 0 ; i < nb_list() ; i++) {
00550 
00551        for (j = 0 ; j < MAX_ITEM ; j++) {
00552 
00553               if ((j < my_frame->nb_stars[i]) && (type != EMPTY))
00554                      image = image_name[i];
00555               else
00556                      image = image_star_clear;
00557 
00558               if (type == UNDERHAT) {
00559                      item_x = (MH_HAT_X + ((MH_HAT_WIDTH - ITEM_SIZE) / 2));
00560                      item_y = (MH_HAT_Y + MH_HAT_HEIGHT -  2 * ITEM_SIZE);
00561               } else {
00562                      item_x = x + (j * (ITEM_SIZE + SPACE_BETWEEN_ITEMS));
00563                      item_y = y + (i * (ITEM_SIZE + SPACE_BETWEEN_ITEMS));
00564               }
00565 
00566               // If NORMAL, we have to create two items : the first one stays on the frame, the
00567               // other one moves to the hat
00568               if (type == NORMAL)
00569                      nb_item = 2;
00570               else
00571                      nb_item = 1;
00572 
00573               for (k = 0 ; k < nb_item ; k++) {
00574                      item = gnome_canvas_item_new (boardRootItem,
00575                             gnome_canvas_pixbuf_get_type(),
00576                             "pixbuf", image,
00577                             "x", item_x,
00578                             "y", item_y,
00579                             "width", (double) (ITEM_SIZE - 2),
00580                             "height", (double) (ITEM_SIZE - 2),
00581                             "width_set", TRUE,
00582                             "height_set", TRUE,
00583                             "anchor", GTK_ANCHOR_NW,
00584                             NULL);
00585               }
00586 
00587               if (type == DYNAMIC)
00588                      gtk_signal_connect(GTK_OBJECT(item), "event", 
00589                                       (GtkSignalFunc) item_event, 
00590                                       GINT_TO_POINTER(MAX_ITEM * i + j));
00591 
00592               if (type == UNDERHAT || type == NORMAL)
00593                      my_frame->array_item[i][j] = item;
00594        }
00595   }
00596 
00597   gdk_pixbuf_unref(image_star_clear);
00598   gdk_pixbuf_unref(image_name[0]);
00599   gdk_pixbuf_unref(image_name[1]);
00600   gdk_pixbuf_unref(image_name[2]);
00601 
00602 }
00603 
00604 // When clicked, an star from the player frame changes its appearance (grey or coloured) and the counter is re-evaluated
00605 static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
00606 
00607        int index = GPOINTER_TO_INT(data);
00608 
00609        if (board_paused)
00610               return FALSE;
00611 
00612        if (event->type == GDK_MOTION_NOTIFY) // Mouse moved
00613               return FALSE;
00614 
00615        if ((event->type == GDK_BUTTON_PRESS) && (event->button.button == 1)) {
00616 
00617               if (frame_player.array_star_type[index / MAX_ITEM][index % MAX_ITEM] >= 0) {
00618                 GdkPixbuf *pixmap;
00619                      
00620                 // Desactivate the star
00621                 frame_player.nb_stars[index / MAX_ITEM]--;
00622                 frame_player.array_star_type[index / MAX_ITEM][index % MAX_ITEM] = -1;
00623 
00624                 pixmap = gc_pixmap_load("magic_hat/star-clear.png");
00625 
00626                 gnome_canvas_item_set(item, "pixbuf", pixmap, NULL);
00627 
00628                 gdk_pixbuf_unref(pixmap);
00629 
00630               } else {
00631                 GdkPixbuf *pixmap = NULL;
00632 
00633                 // Activate the star
00634                 frame_player.nb_stars[index / MAX_ITEM]++;
00635                 frame_player.array_star_type[index / MAX_ITEM][index % MAX_ITEM] = index / MAX_ITEM;
00636 
00637                 switch(index / MAX_ITEM)
00638                   {
00639                   case 0: pixmap = gc_pixmap_load("magic_hat/star1.png"); break;
00640                   case 1: pixmap = gc_pixmap_load("magic_hat/star2.png"); break;
00641                   case 2: pixmap = gc_pixmap_load("magic_hat/star3.png"); break;
00642                   }
00643                 gnome_canvas_item_set(item, "pixbuf", pixmap, NULL);
00644 
00645                 gdk_pixbuf_unref(pixmap);
00646               }
00647               gc_sound_play_ogg ("sounds/gobble.ogg", NULL);
00648        }
00649        
00650        return FALSE;
00651 }
00652 
00653 // When clicked, the hat rotates and a few items can go out of or into it
00654 // Then the hat go back in its previous position, and the game can start
00655 static gint hat_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
00656 
00657        if (board_paused)
00658               return FALSE;
00659 
00660        if (event->type == GDK_MOTION_NOTIFY) // Mouse moved
00661               return FALSE;
00662 
00663        if ((event->type == GDK_BUTTON_PRESS) && (event->button.button == 1)) {
00664 
00665               // disconnect hat and hat_event, so that hat can not be clicked any more
00666               gtk_signal_disconnect(GTK_OBJECT(hat), hat_event_id);
00667 
00668               // 'open' the hat
00669               gc_item_rotate_with_center(hat, -20.0, 0, MH_HAT_HEIGHT);
00670 
00671               // Make the items move from/out the hat, depending on the mode
00672               // Wait a few seconds between the two frames
00673               move_stars(&frame1);
00674               timer_id = g_timeout_add(1200, (GtkFunction) move_stars, &frame2);
00675 
00676               // Wait again a few seconds before closing the hat. Then the game is ready to start
00677               timer_id = g_timeout_add(2600, (GtkFunction) close_hat, NULL);
00678        }
00679 
00680        return FALSE;
00681 }
00682 
00683 // Return nb_list to be displayed, depending of the game level :
00684 // levels 1, 2 and 3 : one list
00685 // levels 4, 5 and 6 : two lists
00686 // levels 7, 8 and 9 : three lists
00687 static int nb_list() {
00688 
00689   if(gcomprisBoard == NULL)
00690     return 0;
00691 
00692   return (1 + (gcomprisBoard->level - 1) / MAX_LIST) ;
00693 
00694 }
00695 
00696 // Move all the stars of one frame to or from the hat
00697 static gint move_stars(frame *my_frame) {
00698 
00699   int i, j;
00700   move_object *my_move = NULL;
00701   
00702   for (i = 0 ; i < nb_list() ; i++) {
00703        for (j = 0 ; j < my_frame->nb_stars[i] ; j++) {
00704               if ((my_move = g_malloc(sizeof(move_object))) == NULL) {        // Freed in function smooth_move
00705                      g_error ("Malloc error in hat_event");
00706               }
00707               my_move->i = i;
00708               my_move->j = j;
00709               my_move->nb = 20;
00710               my_move->dx = - ((my_frame->coord_x + (my_move->j * (ITEM_SIZE + SPACE_BETWEEN_ITEMS)) -
00711                             (MH_HAT_X + ((MH_HAT_WIDTH - ITEM_SIZE) / 2))) / my_move->nb);
00712               my_move->dy = - ((my_frame->coord_y + (my_move->i * (ITEM_SIZE + SPACE_BETWEEN_ITEMS)) -
00713                             (MH_HAT_Y + MH_HAT_HEIGHT -  2 * ITEM_SIZE)) / my_move->nb);
00714 
00715               if (board_mode == MODE_MINUS && my_frame->id == 2) {
00716                      my_move->dx = -my_move->dx;
00717                      my_move->dy = -my_move->dy;
00718               }
00719 
00720               my_move->frame = my_frame->id;
00721               timer_id = g_timeout_add(50, (GtkFunction) smooth_move, my_move);
00722        }
00723   }
00724   return FALSE;
00725 }
00726 
00727 // Close the hat, then the game can start
00728 static gint close_hat() {
00729 
00730   // erase the hat with stars
00731   gtk_object_destroy(GTK_OBJECT(hat));
00732 
00733   // draw a hat with an interrogation point
00734   draw_hat(POINT);
00735 
00736   // draw an empty dynamic frame, each item is activable by left click
00737   // before this, the player_frame is not clicable
00738   place_item(&frame_player, DYNAMIC);
00739 
00740   return FALSE;
00741 }
00742 
00743 // Move a star smoothly from under the hat to its final location, on the minus frame
00744 static gint smooth_move(move_object *my_move) {
00745 
00746   if (!my_move->nb-- || boardRootItem == NULL) {
00747        g_free(my_move);
00748        return FALSE;
00749   }
00750 
00751   if (my_move->frame == 1)
00752        gnome_canvas_item_move(frame1.array_item[my_move->i][my_move->j], my_move->dx, my_move->dy); 
00753   else
00754        gnome_canvas_item_move(frame2.array_item[my_move->i][my_move->j], my_move->dx, my_move->dy); 
00755 
00756   return TRUE;
00757 
00758 }