Back to index

gcompris  8.2.2
superbrain.c
Go to the documentation of this file.
00001 /* gcompris - superbrain.c
00002  *
00003  * Copyright (C) 2002 Bruno Coudoin
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU General Public License as published by
00007  *   the Free Software Foundation; either version 2 of the License, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details.
00014  *
00015  *   You should have received a copy of the GNU General Public License
00016  *   along with this program; if not, write to the Free Software
00017  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018  */
00019 
00020 #include "gcompris/gcompris.h"
00021 
00022 #define SOUNDLISTFILE PACKAGE
00023 
00024 static GcomprisBoard *gcomprisBoard = NULL;
00025 static gboolean board_paused = TRUE;
00026 
00027 /*
00028  * Contains the points that represents the anchors
00029  */
00030 typedef struct {
00031   GnomeCanvasGroup   *rootitem;
00032   GList                     *listitem;
00033   guint                      selecteditem;
00034   GnomeCanvasItem    *good;
00035   GnomeCanvasItem    *misplaced;
00036   gboolean           completed;
00037 } Piece;
00038 
00039 static GList * listPieces = NULL;
00040 
00041 static guint colors[] =
00042   {
00043     0x0000FF80,
00044     0x00FF0080,
00045     0xFF000080,
00046     0x00FFFF80,
00047     0xFF00FF80,
00048     0xFFFF0080,
00049     0x00007F80,
00050     0x007F0080,
00051     0x7F000080,
00052     0x7F007F80,
00053   };
00054 
00055 #define MAX_COLORS   10
00056 
00057 #define PIECE_WIDTH  20
00058 #define PIECE_HEIGHT 20
00059 #define PIECE_GAP    18
00060 #define PIECE_GAP_GOOD      5
00061 #define SCROLL_LIMIT 160
00062 #define PLAYING_AREA_X      190
00063 #define PLAYING_HELP_X      (BOARDWIDTH-80)
00064 
00065 #define COLOR_GOOD   0x00000080
00066 #define COLOR_MISPLACED     0xFFFFFF80
00067 
00068 #define PIECE_DISPLAY_X     40
00069 #define PIECE_DISPLAY_Y     35
00070 
00071 static void    process_ok(void);
00072 static void    start_board (GcomprisBoard *agcomprisBoard);
00073 static void    pause_board (gboolean pause);
00074 static void    end_board (void);
00075 static gboolean       is_our_board (GcomprisBoard *gcomprisBoard);
00076 static void    set_level (guint level);
00077 static int     gamewon;
00078 static void    game_won(void);
00079 
00080 static GnomeCanvasGroup *boardRootItem = NULL;
00081 static GnomeCanvasGroup     *boardLogoItem = NULL;
00082 
00083 
00084 static GnomeCanvasItem      *superbrain_create_item(GnomeCanvasGroup *parent);
00085 static void           superbrain_destroy_all_items(void);
00086 static void           superbrain_next_level(void);
00087 static gint           item_event(GnomeCanvasItem *item, GdkEvent *event, Piece *piece);
00088 static void           mark_pieces(void);
00089 
00090 static guint number_of_color    = 0;
00091 static guint number_of_piece    = 0;
00092 static gint current_y_position  = 0;
00093 
00094 #define MAX_PIECES   10
00095 static guint solution[MAX_PIECES];
00096 
00097 #define LEVEL_MAX_FOR_HELP  4
00098 
00099 #define Y_STEP       (PIECE_HEIGHT+PIECE_GAP)
00100 
00101 /* Description of this plugin */
00102 static BoardPlugin menu_bp =
00103   {
00104     NULL,
00105     NULL,
00106     N_("Super Brain"),
00107     N_("Tux has hidden several items. Find them again in the correct order"),
00108     "Bruno Coudoin <bruno.coudoin@free.fr>",
00109     NULL,
00110     NULL,
00111     NULL,
00112     NULL,
00113     start_board,
00114     pause_board,
00115     end_board,
00116     is_our_board,
00117     NULL,
00118     process_ok,
00119     set_level,
00120     NULL,
00121     NULL,
00122     NULL,
00123     NULL
00124   };
00125 
00126 /*
00127  * Main entry point mandatory for each Gcompris's game
00128  * ---------------------------------------------------
00129  *
00130  */
00131 
00132 GET_BPLUGIN_INFO(superbrain)
00133 
00134 /*
00135  * in : boolean TRUE = PAUSE : FALSE = CONTINUE
00136  *
00137  */
00138 static void pause_board (gboolean pause)
00139 {
00140   if(gcomprisBoard==NULL)
00141     return;
00142 
00143   if(gamewon == TRUE && pause == FALSE) /* the game is won */
00144     {
00145       game_won();
00146     }
00147 
00148   board_paused = pause;
00149 }
00150 
00151 /*
00152  */
00153 static void start_board (GcomprisBoard *agcomprisBoard)
00154 {
00155 
00156   if(agcomprisBoard!=NULL)
00157     {
00158       gcomprisBoard=agcomprisBoard;
00159       gcomprisBoard->level=1;
00160       gcomprisBoard->maxlevel=6;
00161       gcomprisBoard->sublevel=1;
00162       gcomprisBoard->number_of_sublevel=1; /* Go to next level after this number of 'play' */
00163       gc_bar_set(GC_BAR_OK|GC_BAR_LEVEL);
00164 
00165       superbrain_next_level();
00166 
00167       gamewon = FALSE;
00168       pause_board(FALSE);
00169     }
00170 }
00171 /* ======================================= */
00172 static void end_board ()
00173 {
00174   if(gcomprisBoard!=NULL)
00175     {
00176       pause_board(TRUE);
00177       superbrain_destroy_all_items();
00178     }
00179   gcomprisBoard = NULL;
00180 }
00181 
00182 /* ======================================= */
00183 static void set_level (guint level)
00184 {
00185 
00186   if(gcomprisBoard!=NULL)
00187     {
00188       gcomprisBoard->level=level;
00189       gcomprisBoard->sublevel=1;
00190       superbrain_next_level();
00191     }
00192 }
00193 /* ======================================= */
00194 static gboolean is_our_board (GcomprisBoard *gcomprisBoard)
00195 {
00196   if (gcomprisBoard)
00197     {
00198       if(g_strcasecmp(gcomprisBoard->type, "superbrain")==0)
00199        {
00200          /* Set the plugin entry */
00201          gcomprisBoard->plugin=&menu_bp;
00202 
00203          return TRUE;
00204        }
00205     }
00206   return FALSE;
00207 }
00208 
00209 /* ======================================= */
00210 static void process_ok() {
00211 
00212   mark_pieces();
00213 
00214   if(gamewon)
00215     gc_bonus_display(gamewon, BONUS_SMILEY);
00216 }
00217 
00218 /*-------------------------------------------------------------------------------*/
00219 /*-------------------------------------------------------------------------------*/
00220 /* set initial values for the next level */
00221 static void superbrain_next_level()
00222 {
00223   guint i;
00224   gboolean selected_color[MAX_COLORS];
00225 
00226   gc_set_background(gnome_canvas_root(gcomprisBoard->canvas),
00227                        "images/superbrain_background.jpg");
00228 
00229   gc_bar_set_level(gcomprisBoard);
00230 
00231   superbrain_destroy_all_items();
00232   gamewon = FALSE;
00233 
00234   /* Select level difficulty : should not go above MAX_PIECES */
00235   /* number_of_color must be upper than number_of_piece to allow unicity */
00236 
00237   if(gcomprisBoard->level < LEVEL_MAX_FOR_HELP)
00238     {
00239       number_of_piece = gcomprisBoard->level + 2;
00240       number_of_color = gcomprisBoard->level + 4;
00241     }
00242   else
00243     {
00244       number_of_piece = gcomprisBoard->level - LEVEL_MAX_FOR_HELP + 3;
00245       number_of_color = gcomprisBoard->level - LEVEL_MAX_FOR_HELP + 5;
00246     }
00247 
00248 
00249   current_y_position = BOARDHEIGHT - 50;
00250 
00251   /* Init a random solution : colors choosen are uniquely choosen */
00252   for(i=0; i<number_of_color; i++)
00253     {
00254       selected_color[i] = FALSE;
00255     }
00256 
00257   for(i=0; i<number_of_piece; i++)
00258     {
00259       guint j;
00260 
00261       j = (guint)RAND(1, number_of_color);
00262       while(selected_color[j])
00263        j = (guint)RAND(1, number_of_color);
00264 
00265       solution[i] = j;
00266       selected_color[j] = TRUE;
00267     }
00268 
00269 
00270 
00271   boardRootItem = GNOME_CANVAS_GROUP(
00272                                  gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
00273                                                      gnome_canvas_group_get_type (),
00274                                                      "x", (double) 0,
00275                                                      "y", (double) 0,
00276                                                      NULL));
00277 
00278   boardLogoItem = GNOME_CANVAS_GROUP(
00279                                  gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
00280                                                      gnome_canvas_group_get_type (),
00281                                                      "x", (double) 0,
00282                                                      "y", (double) 0,
00283                                                      NULL));
00284 
00285   /* The list of the pieces */
00286   for(i=0; i<number_of_color; i++)
00287     {
00288       gnome_canvas_item_new (boardLogoItem,
00289                           gnome_canvas_ellipse_get_type(),
00290                           "x1", (double) PIECE_DISPLAY_X,
00291                           "y1", (double) PIECE_DISPLAY_Y + i*PIECE_WIDTH*1.2 + (i*PIECE_GAP*1.2),
00292                           "x2", (double) PIECE_DISPLAY_X + PIECE_WIDTH*1.2,
00293                           "y2", (double) PIECE_DISPLAY_Y + i*PIECE_WIDTH*1.2 + PIECE_HEIGHT*1.2 + (i*PIECE_GAP*1.2),
00294                           "fill_color_rgba", colors[i],
00295                           "outline_color", "white",
00296                           "width_units", (double)1,
00297                           NULL);
00298     }
00299 
00300 
00301   superbrain_create_item(boardRootItem);
00302 }
00303 /* ==================================== */
00304 /* Destroy all the items */
00305 static void superbrain_destroy_all_items()
00306 {
00307   if(boardRootItem!=NULL)
00308     gtk_object_destroy (GTK_OBJECT(boardRootItem));
00309 
00310   boardRootItem = NULL;
00311 
00312   if(boardLogoItem!=NULL)
00313     gtk_object_destroy (GTK_OBJECT(boardLogoItem));
00314 
00315   boardLogoItem = NULL;
00316 }
00317 /* ==================================== */
00318 static GnomeCanvasItem *superbrain_create_item(GnomeCanvasGroup *parent)
00319 {
00320   int i, j, x;
00321   double x1, x2;
00322   GnomeCanvasItem *item = NULL;
00323   Piece *piece = NULL;
00324   GnomeCanvasPoints  *points;
00325 
00326   if(current_y_position < SCROLL_LIMIT)
00327     {
00328       gnome_canvas_item_move(GNOME_CANVAS_ITEM(boardRootItem), 0.0, (double)Y_STEP);
00329     }
00330 
00331   x = (BOARDWIDTH - number_of_piece*(PIECE_WIDTH+PIECE_GAP))/2 + PLAYING_AREA_X;
00332 
00333   /* Draw a line to separate cleanly */
00334   x1 = x + PIECE_WIDTH/2;
00335   x2 = (BOARDWIDTH + (number_of_piece-1)*(PIECE_WIDTH+PIECE_GAP))/2 - PIECE_WIDTH/2 + PLAYING_AREA_X;
00336 
00337   points = gnome_canvas_points_new(2);
00338   points->coords[0] = (double) x1;
00339   points->coords[1] = (double) current_y_position + PIECE_HEIGHT + PIECE_GAP/2;
00340   points->coords[2] = (double) x2;
00341   points->coords[3] = (double) current_y_position + PIECE_HEIGHT + PIECE_GAP/2;
00342 
00343   gnome_canvas_item_new (boardRootItem,
00344                       gnome_canvas_line_get_type (),
00345                       "points", points,
00346                       "fill_color", "white",
00347                       "width_pixels", 1,
00348                       NULL);
00349 
00350   points->coords[0] = (double) x1 + 2;
00351   points->coords[1] = (double) current_y_position + PIECE_HEIGHT + PIECE_GAP/2 + 1;
00352   points->coords[2] = (double) x2 + 2;
00353   points->coords[3] = (double) current_y_position + PIECE_HEIGHT + PIECE_GAP/2 + 1;
00354 
00355   gnome_canvas_item_new (boardRootItem,
00356                       gnome_canvas_line_get_type (),
00357                       "points", points,
00358                       "fill_color", "black",
00359                       "width_pixels", 1,
00360                       NULL);
00361 
00362   /* Continuing the line */
00363   //  x1 = (BOARDWIDTH + (number_of_piece+2)*(PIECE_WIDTH+PIECE_GAP))/2 + PLAYING_AREA_X;
00364   x1 = PLAYING_HELP_X;
00365   x2 = x1 + number_of_piece*PIECE_WIDTH/2;
00366 
00367   points->coords[0] = (double) x1;
00368   points->coords[1] = (double) current_y_position + PIECE_HEIGHT + PIECE_GAP/2;
00369   points->coords[2] = (double) x2;
00370   points->coords[3] = (double) current_y_position + PIECE_HEIGHT + PIECE_GAP/2;
00371 
00372   gnome_canvas_item_new (boardRootItem,
00373                       gnome_canvas_line_get_type (),
00374                       "points", points,
00375                       "fill_color", "white",
00376                       "width_pixels", 1,
00377                       NULL);
00378 
00379   points->coords[0] = (double) x1 + 2;
00380   points->coords[1] = (double) current_y_position + PIECE_HEIGHT + PIECE_GAP/2 + 1;
00381   points->coords[2] = (double) x2 + 2;
00382   points->coords[3] = (double) current_y_position + PIECE_HEIGHT + PIECE_GAP/2 + 1;
00383 
00384   gnome_canvas_item_new (boardRootItem,
00385                       gnome_canvas_line_get_type (),
00386                       "points", points,
00387                       "fill_color", "black",
00388                       "width_pixels", 1,
00389                       NULL);
00390 
00391   gnome_canvas_points_unref(points);
00392 
00393   /* Draw the pieces */
00394   listPieces = g_list_alloc();
00395 
00396   for(i=0; i<number_of_piece; i++)
00397     {
00398 
00399       piece = g_new(Piece, 1);
00400       piece->listitem = g_list_alloc();
00401       piece->completed = FALSE;
00402       listPieces = g_list_append(listPieces, piece);
00403 
00404       piece->rootitem = GNOME_CANVAS_GROUP(
00405                                       gnome_canvas_item_new (parent,
00406                                                           gnome_canvas_group_get_type (),
00407                                                           "x", (double) 0,
00408                                                           "y", (double) 0,
00409 
00410                                                           NULL));
00411 
00412 
00413       // Good
00414       piece->good = gnome_canvas_item_new (piece->rootitem,
00415                                       gnome_canvas_rect_get_type (),
00416                                       "x1", (double) x + i*PIECE_WIDTH + (i*PIECE_GAP) - PIECE_GAP_GOOD,
00417                                       "y1", (double) current_y_position - PIECE_GAP_GOOD,
00418                                       "x2", (double) x + i*PIECE_WIDTH  + PIECE_WIDTH + (i*PIECE_GAP) + PIECE_GAP_GOOD,
00419                                       "y2", (double) current_y_position + PIECE_HEIGHT + PIECE_GAP_GOOD,
00420                                       "fill_color_rgba", COLOR_GOOD,
00421                                       "outline_color", "white",
00422                                       "width_units", (double)1,
00423                                       NULL);
00424       gnome_canvas_item_hide(piece->good);
00425 
00426       // Misplaced
00427       piece->misplaced = gnome_canvas_item_new (piece->rootitem,
00428                                           gnome_canvas_rect_get_type (),
00429                                           "x1", (double) x + i*PIECE_WIDTH + (i*PIECE_GAP) - PIECE_GAP_GOOD,
00430                                           "y1", (double) current_y_position - PIECE_GAP_GOOD,
00431                                           "x2", (double) x + i*PIECE_WIDTH  + PIECE_WIDTH + (i*PIECE_GAP) + PIECE_GAP_GOOD,
00432                                           "y2", (double) current_y_position + PIECE_HEIGHT + PIECE_GAP_GOOD,
00433                                           "fill_color_rgba", COLOR_MISPLACED,
00434                                           "outline_color", "white",
00435                                           "width_units", (double)1,
00436                                           NULL);
00437       gnome_canvas_item_hide(piece->misplaced);
00438 
00439       for(j=0; j<number_of_color; j++)
00440        {
00441          item = gnome_canvas_item_new (piece->rootitem,
00442                                    gnome_canvas_ellipse_get_type(),
00443                                    "x1", (double) x + i*PIECE_WIDTH + (i*PIECE_GAP),
00444                                    "y1", (double) current_y_position,
00445                                    "x2", (double) x + i*PIECE_WIDTH  + PIECE_WIDTH + (i*PIECE_GAP),
00446                                    "y2", (double) current_y_position + PIECE_HEIGHT,
00447                                    "fill_color_rgba", colors[j],
00448                                    "outline_color", "white",
00449                                    "width_units", (double)1,
00450                                    NULL);
00451 
00452          gnome_canvas_item_hide(item);
00453          piece->listitem = g_list_append(piece->listitem, item);
00454 
00455          gtk_signal_connect(GTK_OBJECT(item), "event", (GtkSignalFunc) item_event, piece);
00456        }
00457 
00458       piece->selecteditem = 1;
00459       item = g_list_nth_data(piece->listitem,
00460                           piece->selecteditem);
00461       gnome_canvas_item_show(item);
00462 
00463     }
00464 
00465   return NULL;
00466 }
00467 /* ==================================== */
00468 static void game_won()
00469 {
00470   gcomprisBoard->sublevel++;
00471 
00472   if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) {
00473     /* Try the next level */
00474     gcomprisBoard->sublevel=1;
00475     gcomprisBoard->level++;
00476     if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
00477       gc_bonus_end_display(BOARD_FINISHED_RANDOM);
00478       return;
00479     }
00480     gc_sound_play_ogg ("sounds/bonus.ogg", NULL);
00481   }
00482   superbrain_next_level();
00483 }
00484 
00485 /* ==================================== */
00486 static gint
00487 item_event(GnomeCanvasItem *item, GdkEvent *event, Piece *piece)
00488 {
00489   GnomeCanvasItem *newitem;
00490 
00491   if(board_paused)
00492     return FALSE;
00493 
00494   switch (event->type)
00495     {
00496     case GDK_BUTTON_PRESS:
00497       if(!piece->completed)
00498        {
00499          gnome_canvas_item_hide(item);
00500 
00501          switch(event->button.button)
00502            {
00503            case 1:
00504            case 4:
00505              piece->selecteditem++;
00506              if(piece->selecteditem>=g_list_length(piece->listitem))
00507               piece->selecteditem = 1;
00508              break;
00509            case 2:
00510            case 3:
00511            case 5:
00512              piece->selecteditem--;
00513              if(piece->selecteditem<=0)
00514               piece->selecteditem = g_list_length(piece->listitem)-1;
00515              break;
00516            }
00517 
00518          newitem = g_list_nth_data(piece->listitem,
00519                                 piece->selecteditem);
00520          gnome_canvas_item_show(newitem);
00521        }
00522       break;
00523     default:
00524       break;
00525     }
00526 
00527   return FALSE;
00528 }
00529 
00530 static void mark_pieces()
00531 {
00532   guint i, j;
00533   guint x;
00534   Piece       *piece = NULL;
00535   guint nbgood = 0;
00536   guint nbmisplaced = 0;
00537   guint solution_tmp[MAX_PIECES];
00538 
00539   for(i=0; i<number_of_piece; i++)
00540     {
00541       solution_tmp[i] = solution[i];
00542     }
00543 
00544   gamewon = TRUE;
00545 
00546   /* Mark good placed */
00547   for(i=1; i<g_list_length(listPieces);  i++)
00548     {
00549       piece = g_list_nth_data(listPieces, i);
00550       if(piece->selecteditem == solution_tmp[i-1])
00551        {
00552          if(gcomprisBoard->level<LEVEL_MAX_FOR_HELP)
00553            gnome_canvas_item_show(piece->good);
00554          nbgood++;
00555          solution_tmp[i-1] = G_MAXINT;
00556        }
00557       else
00558        {
00559          gamewon = FALSE;
00560        }
00561 
00562       piece->completed = TRUE;
00563     }
00564 
00565   /* Mark misplaced */
00566   for(i=1; i<=number_of_piece;  i++)
00567     {
00568       gboolean done;
00569 
00570       piece = g_list_nth_data(listPieces, i);
00571 
00572       /* Search if this color is elsewhere */
00573       j = 1;
00574       done = FALSE;
00575       do {
00576        if(piece->selecteditem != solution[i-1] &&
00577           piece->selecteditem == solution_tmp[j-1])
00578          {
00579            nbmisplaced++;
00580            solution_tmp[j-1] = G_MAXINT;
00581            if(gcomprisBoard->level<LEVEL_MAX_FOR_HELP)
00582              gnome_canvas_item_show(piece->misplaced);
00583            done = TRUE;
00584          }
00585       } while (!done && j++!=number_of_piece);
00586     }
00587 
00588   /* Display the matermind information to the user */
00589   //  x = (BOARDWIDTH + (number_of_piece+2)*(PIECE_WIDTH+PIECE_GAP))/2;
00590   x = PLAYING_HELP_X;
00591   for(i=0; i<nbgood;  i++)
00592     {
00593       gnome_canvas_item_new (boardRootItem,
00594                           gnome_canvas_ellipse_get_type(),
00595                           "x1", (double) x + i*PIECE_WIDTH/2 + (i*PIECE_GAP/2),
00596                           "y1", (double) current_y_position,
00597                           "x2", (double) x + i*PIECE_WIDTH/2  + PIECE_WIDTH/2 + (i*PIECE_GAP/2),
00598                           "y2", (double) current_y_position + PIECE_HEIGHT/2,
00599                           "fill_color", "black",
00600                           "outline_color", "white",
00601                           "width_units", (double)1,
00602                           NULL);
00603     }
00604 
00605   for(i=0; i<nbmisplaced;  i++)
00606     {
00607       gnome_canvas_item_new (boardRootItem,
00608                           gnome_canvas_ellipse_get_type(),
00609                           "x1", (double) x + i*PIECE_WIDTH/2 + (i*PIECE_GAP/2),
00610                           "y1", (double) current_y_position + PIECE_HEIGHT/2 + PIECE_GAP/3,
00611                           "x2", (double) x + i*PIECE_WIDTH/2  + PIECE_WIDTH/2 + (i*PIECE_GAP/2),
00612                           "y2", (double) current_y_position + PIECE_HEIGHT + PIECE_GAP/3,
00613                           "fill_color", "white",
00614                           "outline_color", "black",
00615                           "width_units", (double)1,
00616                           NULL);
00617     }
00618 
00619   current_y_position -= Y_STEP;
00620 
00621   g_list_free(listPieces);
00622 
00623   superbrain_create_item(boardRootItem);
00624 
00625 }