reversecount.c 20.3 KB
Newer Older
1 2
/* gcompris - reversecount.c
 *
3
 * Copyright (C) 2002,2003 Bruno Coudoin
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 *   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 2 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, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <ctype.h>
#include <math.h>
#include <assert.h>

#include "gcompris/gcompris.h"

#define SOUNDLISTFILE PACKAGE

28 29
static GcomprisBoard	*gcomprisBoard = NULL;
static gboolean	 board_paused = TRUE;
30
static gint	 animate_id = 0;
31
static int	 leavenow;
32 33

static void	 start_board (GcomprisBoard *agcomprisBoard);
34
static gint	 key_press(guint keyval, gchar *commit_str, gchar *preedit_str);
35 36 37 38 39 40 41
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 int	 gamewon;
static void	 game_won(void);

42 43 44 45
#define TUX_IMG_NORTH "gcompris/misc/tux_top_north.png"
#define TUX_IMG_SOUTH "gcompris/misc/tux_top_south.png"
#define TUX_IMG_WEST  "gcompris/misc/tux_top_west.png"
#define TUX_IMG_EAST  "gcompris/misc/tux_top_east.png"
Bruno Coudoin's avatar
Bruno Coudoin committed
46
#define TUX_TO_BORDER_GAP 10
47 48 49 50

static GnomeCanvasGroup *boardRootItem = NULL;

static void		 process_ok(void);
51
static void		 process_error(void);
52 53 54 55
static GnomeCanvasItem	*reversecount_create_item(GnomeCanvasGroup *parent);
static void		 reversecount_destroy_all_items(void);
static void		 reversecount_next_level(void);
static gint		 item_event(GnomeCanvasItem *item, GdkEvent *event, gint *dice_index);
56
static GnomeCanvasItem	*display_item_at(gchar *imagename, int block, double ratio);
57
static void		 display_random_fish();
58 59
static void		 create_clock(double x, double y, int value);
static void		 update_clock(int value);
60
static gint		 animate_tux();
61

62
static int number_of_item   = 0;
63 64 65
static int number_of_item_x = 0;
static int number_of_item_y = 0;

66 67 68 69
static int errors           = 0;
static int number_of_dices  = 0;
static int max_dice_number  = 0;
static int number_of_fish   = 0;
70

71 72 73 74 75 76
static int tux_index	    = 0;
static int tux_destination  = 0;
static int fish_index	    = 0;
static int animate_speed    = 0;

#define ANIMATE_SPEED	800
77

78 79
static double tux_ratio = 0;

80 81 82
static int dicevalue_array[10];
static GnomeCanvasItem *fishItem;
static GnomeCanvasItem *tuxItem;
83
static GnomeCanvasItem *clock_image_item;
84 85 86 87

// List of images to use in the game
static gchar *imageList[] =
{
88 89 90 91 92 93 94
  "reversecount/baleine.png",
  "reversecount/phoque.png",
  "reversecount/ourspolaire.png",
  "reversecount/morse.png",
  "reversecount/elephant_mer.png",
  "reversecount/epaulard.png",
  "reversecount/narval.png",
95
};
96
#define NUMBER_OF_IMAGES 10
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132

// List of fish to use in the game
static gchar *fishList[] =
{
  "fishes/blueking2_0.png",
  "fishes/butfish_0.png",
  "fishes/cichlid1_0.png",
  "fishes/cichlid4_0.png",
  "fishes/collaris_0.png",
  "fishes/discus2_0.png",
  "fishes/discus3_0.png",
  "fishes/eel_0.png",
  "fishes/f00_0.png",
  "fishes/f01_0.png",
  "fishes/f02_0.png",
  "fishes/f03_0.png",
  "fishes/f04_0.png",
  "fishes/f05_0.png",
  "fishes/f06_0.png",
  "fishes/f07_0.png",
  "fishes/f08_0.png",
  "fishes/f09_0.png",
  "fishes/f10_0.png",
  "fishes/f11_0.png",
  "fishes/f12_0.png",
  "fishes/f13_0.png",
  "fishes/manta_0.png",
  "fishes/newf1_0.png",
  "fishes/QueenAngel_0.png",
  "fishes/shark1_0.png",
  "fishes/six_barred_0.png",
  "fishes/teeth_0.png"
};
#define NUMBER_OF_FISHES 27

/* Description of this plugin */
133
static BoardPlugin menu_bp =
134 135 136
  {
    NULL,
    NULL,
137 138
    "Reverse count",
    "Practice substraction with a funny game",
139 140 141 142 143 144 145 146 147 148 149 150 151
    "Bruno Coudoin <bruno.coudoin@free.fr>",
    NULL,
    NULL,
    NULL,
    NULL,
    start_board,
    pause_board,
    end_board,
    is_our_board,
    key_press,
    process_ok,
    set_level,
    NULL,
152 153
    NULL,
    NULL,
154 155 156 157 158 159 160 161 162
    NULL
  };

/*
 * Main entry point mandatory for each Gcompris's game
 * ---------------------------------------------------
 *
 */

163
GET_BPLUGIN_INFO(reversecount)
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178

/*
 * in : boolean TRUE = PAUSE : FALSE = CONTINUE
 *
 */
static void pause_board (gboolean pause)
{
  if(gcomprisBoard==NULL)
    return;

  if(gamewon == TRUE && pause == FALSE) /* the game is won */
    {
      game_won();
    }

179
  if(leavenow == TRUE && pause == FALSE)
180
    gc_bonus_end_display(BOARD_FINISHED_TOOMANYERRORS);
181

182 183 184 185 186 187 188 189 190 191 192
  board_paused = pause;
}

/*
 */
static void start_board (GcomprisBoard *agcomprisBoard)
{

  if(agcomprisBoard!=NULL)
    {
      gcomprisBoard=agcomprisBoard;
193 194 195 196

      /* disable im_context */
      gcomprisBoard->disable_im_context = TRUE;

197 198 199 200
      gcomprisBoard->level=1;
      gcomprisBoard->maxlevel=7;
      gcomprisBoard->sublevel=1;
      gcomprisBoard->number_of_sublevel=1; /* Go to next level after this number of 'play' */
201
      gc_bar_set(GC_BAR_LEVEL|GC_BAR_OK);
202 203 204 205

      reversecount_next_level();

      gamewon = FALSE;
206
      leavenow = FALSE;
207

208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
      pause_board(FALSE);
    }
}
/* ======================================= */
static void end_board ()
{
  if(gcomprisBoard!=NULL)
    {
      pause_board(TRUE);
      reversecount_destroy_all_items();
    }
  gcomprisBoard = NULL;
}

/* ======================================= */
static void set_level (guint level)
{

  if(gcomprisBoard!=NULL)
    {
      gcomprisBoard->level=level;
      gcomprisBoard->sublevel=1;
      reversecount_next_level();
    }
}

/* ======================================= */
gboolean is_our_board (GcomprisBoard *gcomprisBoard)
{
  if (gcomprisBoard)
    {
      if(g_strcasecmp(gcomprisBoard->type, "reversecount")==0)
	{
	  /* Set the plugin entry */
	  gcomprisBoard->plugin=&menu_bp;

	  return TRUE;
	}
    }
  return FALSE;
}

/* ======================================= */
251
gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str)
252 253 254
{

  if(!gcomprisBoard)
255
    return FALSE;
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286

  /* Add some filter for control and shift key */
  switch (keyval)
    {
      /* Avoid all this keys to be interpreted by this game */
    case GDK_Shift_L:
    case GDK_Shift_R:
    case GDK_Control_L:
    case GDK_Control_R:
    case GDK_Caps_Lock:
    case GDK_Shift_Lock:
    case GDK_Meta_L:
    case GDK_Meta_R:
    case GDK_Alt_L:
    case GDK_Alt_R:
    case GDK_Super_L:
    case GDK_Super_R:
    case GDK_Hyper_L:
    case GDK_Hyper_R:
    case GDK_Num_Lock:
      return FALSE; 
    case GDK_KP_Enter:
    case GDK_Return:
      process_ok();
      return TRUE;
    }

  return TRUE;
}


287 288
static void process_error()
{
289
  gc_sound_play_ogg ("sounds/crash.ogg", NULL);
290 291 292 293 294 295
  errors--;
  if(errors==0)
    {
      gamewon = FALSE;
      leavenow = TRUE;
      reversecount_destroy_all_items();
296
      gc_bonus_display(gamewon, BONUS_SMILEY);
297 298 299 300 301 302 303
    }
  else
    {
      update_clock(errors);
    }
}

304 305 306 307 308
/* ======================================= */
static void process_ok()
{
  guint i;

309 310
  tux_destination = tux_index;

311
  for(i=0; i<number_of_dices; i++)
312
      tux_destination += dicevalue_array[i];
313 314

  // Wrapping
315 316
  if(tux_destination >= number_of_item)
    tux_destination = tux_destination - (number_of_item);
317

318 319 320
  // Do not allow going at a position after the fish
  if((tux_destination > fish_index)
     || (tux_destination == tux_index))
321
    {
322 323
      process_error();
      return;
324
    }
325 326 327 328 329

  if(!animate_id) {
    animate_id = gtk_timeout_add (animate_speed, (GtkFunction) animate_tux, NULL);
  }
  
330 331 332 333
}

/*-------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------*/
334

335 336 337 338
/* set initial values for the next level */
static void reversecount_next_level()
{

339
  gc_set_background(gnome_canvas_root(gcomprisBoard->canvas),
340
			  imageList[gcomprisBoard->level-1]);
341

342
  gc_bar_set_level(gcomprisBoard);
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373

  reversecount_destroy_all_items();
  gamewon = FALSE;

  /* Select level difficulty */
  switch(gcomprisBoard->level)
    {
    case 1:
      number_of_item_x = 5;
      number_of_item_y = 5;
      number_of_dices = 1;
      max_dice_number = 3;
      number_of_fish = 3;
      break;
    case 2:
      number_of_item_x = 5;
      number_of_item_y = 5;
      number_of_dices = 1;
      max_dice_number = 6;
      number_of_fish = 6;
      break;
    case 3:
      number_of_item_x = 6;
      number_of_item_y = 6;
      number_of_dices = 1;
      max_dice_number = 9;
      number_of_fish = 6;
      break;
    case 4:
      number_of_item_x = 8;
      number_of_item_y = 6;
374
      number_of_dices = 1;
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
      max_dice_number = 3;
      number_of_fish = 6;
      break;
    case 5:
      number_of_item_x = 8;
      number_of_item_y = 6;
      number_of_dices = 2;
      max_dice_number = 6;
      number_of_fish = 10;
      break;
    case 6:
      number_of_item_x = 8;
      number_of_item_y = 8;
      number_of_dices = 2;
      max_dice_number = 9;
      number_of_fish = 10;
      break;
    default:
      number_of_item_x = 10;
      number_of_item_y = 10;
      number_of_dices = 3;
      max_dice_number = 9;
      number_of_fish = 10;
      break;
    }

401 402
  animate_speed = ANIMATE_SPEED - gcomprisBoard->level * 60;

403 404 405 406 407 408 409 410 411
  number_of_item = number_of_item_x * 2 + (number_of_item_y - 2) * 2;

  /* Try the next level */
  reversecount_create_item(gnome_canvas_root(gcomprisBoard->canvas));
}
/* ==================================== */
/* Destroy all the items */
static void reversecount_destroy_all_items()
{
412

413
  gc_timer_end();
414

415 416 417 418 419 420 421 422 423 424 425 426
  if(boardRootItem!=NULL)
    gtk_object_destroy (GTK_OBJECT(boardRootItem));

  boardRootItem = NULL;
}
/* ==================================== */
static GnomeCanvasItem *reversecount_create_item(GnomeCanvasGroup *parent)
{
  int i,j,d;
  GnomeCanvasItem *item = NULL;
  GdkPixbuf   *pixmap = NULL;
  double block_width, block_height;
427 428
  double dice_area_x;
  double xratio, yratio;
429
  GcomprisProperties	*properties = gc_prop_get();
430 431 432 433 434 435 436 437 438 439 440 441

  boardRootItem = GNOME_CANVAS_GROUP(
				     gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
							    gnome_canvas_group_get_type (),
							    "x", (double) 0,
							    "y", (double) 0,

							    NULL));

  block_width =  BOARDWIDTH/number_of_item_x;
  block_height = BOARDHEIGHT/number_of_item_y;

442 443 444 445 446 447 448 449 450 451 452 453 454
  /* Timer is not requested */
  if(properties->timer>0)
    {
      errors = number_of_dices + 4 - (MIN(properties->timer, 4));
      create_clock(BOARDWIDTH - block_width - 100, BOARDHEIGHT - block_height - 100,
		   errors) ;
    }
  else
    {
      errors = -1;
    }

  /* Calc the tux best ratio to display it */
455
  pixmap = gc_pixmap_load(TUX_IMG_EAST);
456 457 458 459 460
  xratio =  block_width  / (gdk_pixbuf_get_width (pixmap) + TUX_TO_BORDER_GAP);
  yratio =  block_height / (gdk_pixbuf_get_height(pixmap) + TUX_TO_BORDER_GAP);
  tux_ratio = yratio = MIN(xratio, yratio);
  gdk_pixbuf_unref(pixmap);

461
  pixmap = gc_pixmap_load("reversecount/iceblock.png");
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518

  for(i=0; i<BOARDWIDTH; i+=block_width)
    {
      j=0;
      item = gnome_canvas_item_new (boardRootItem,
				    gnome_canvas_pixbuf_get_type (),
				    "pixbuf", pixmap, 
				    "x", (double) i,
				    "y", (double) j,
				    "width", (double) block_width,
				    "height", (double)  block_height,
				    "width_set", TRUE, 
				    "height_set", TRUE,
					NULL);

      j=BOARDHEIGHT-block_height;
      item = gnome_canvas_item_new (boardRootItem,
				    gnome_canvas_pixbuf_get_type (),
				    "pixbuf", pixmap, 
				    "x", (double) i,
				    "y", (double) j,
				    "width", (double) block_width,
				    "height", (double)  block_height,
				    "width_set", TRUE, 
				    "height_set", TRUE,
					NULL);
    }

  for(j=block_height; j<=BOARDHEIGHT-(block_height*2); j+=block_height)
    {
      i = 0;
      item = gnome_canvas_item_new (boardRootItem,
				    gnome_canvas_pixbuf_get_type (),
				    "pixbuf", pixmap, 
				    "x", (double) i,
				    "y", (double) j,
				    "width", (double) block_width,
				    "height", (double)  block_height,
				    "width_set", TRUE, 
				    "height_set", TRUE,
					NULL);

      i = BOARDWIDTH - block_width;
      item = gnome_canvas_item_new (boardRootItem,
				    gnome_canvas_pixbuf_get_type (),
				    "pixbuf", pixmap, 
				    "x", (double) i,
				    "y", (double) j,
				    "width", (double) block_width,
				    "height", (double)  block_height,
				    "width_set", TRUE, 
				    "height_set", TRUE,
					NULL);
    }

  gdk_pixbuf_unref(pixmap);

519 520 521

  //----------------------------------------
  // Create the dice area
522
  pixmap = gc_pixmap_load("reversecount/dice_area.png");
523 524 525 526 527 528 529 530 531 532

  dice_area_x = BOARDWIDTH - block_width - gdk_pixbuf_get_width (pixmap) - 20;

  gnome_canvas_item_new (boardRootItem,
			 gnome_canvas_pixbuf_get_type (),
			 "pixbuf", pixmap, 
			 "x", (double) dice_area_x,
			 "y", (double) block_height + 20,
			 NULL);

Bruno Coudoin's avatar
Bruno Coudoin committed
533
  gdk_pixbuf_unref(pixmap);
534

535 536
  //----------------------------------------
  // Create the dices
537
  pixmap = gc_pixmap_load("gcompris/dice/gnome-dice1.png");
538 539 540 541 542

  for(d=0; d<number_of_dices; d++)
    {
      int *val;

543
      i = dice_area_x + gdk_pixbuf_get_width(pixmap) * d + 30;
544
      j = block_height + 25 + d*7;
545 546 547 548 549 550 551 552 553 554 555 556 557

      item = gnome_canvas_item_new (boardRootItem,
				    gnome_canvas_pixbuf_get_type (),
				    "pixbuf", pixmap, 
				    "x", (double) i,
				    "y", (double) j,
				    NULL);
      dicevalue_array[d] = 1;
      val = g_new(gint, 1);
      *val = d;
      gtk_signal_connect(GTK_OBJECT(item), "event", (GtkSignalFunc) item_event, 
			 val);
      gtk_signal_connect(GTK_OBJECT(item), "event",
558
			 (GtkSignalFunc) gc_item_focus_event,
559 560 561 562 563 564
			 NULL);

    }
  gdk_pixbuf_unref(pixmap);

  tux_index = 0;
565
  tuxItem = display_item_at(TUX_IMG_EAST, tux_index, tux_ratio);
566 567 568 569 570 571 572 573 574 575 576

  // Display the first fish
  display_random_fish();

  return NULL;
}

static void display_random_fish()
{

  fish_index = tux_index + 
577
    rand()%(max_dice_number*number_of_dices) + 1;
578 579 580 581 582 583

  // Wrapping
  if(fish_index >= number_of_item)
    fish_index = fish_index - (number_of_item);

  fishItem = display_item_at(fishList[rand()%NUMBER_OF_FISHES],
584
			     fish_index, -1);
585 586 587 588
}

/* ==================================== */
/**
Bruno Coudoin's avatar
Bruno Coudoin committed
589
 * Display given imagename on the given ice block.
590
 */
591
static GnomeCanvasItem *display_item_at(gchar *imagename, int block, double ratio)
592 593
{
  double block_width, block_height;
Bruno Coudoin's avatar
Bruno Coudoin committed
594
  double xratio, yratio;
595 596 597 598
  GnomeCanvasItem *item = NULL;
  GdkPixbuf   *pixmap = NULL;
  int i,j;

Bruno Coudoin's avatar
Bruno Coudoin committed
599
  block_width  = BOARDWIDTH/number_of_item_x;
600 601
  block_height = BOARDHEIGHT/number_of_item_y;

602
  pixmap = gc_pixmap_load(imagename);
603 604 605 606

  if(block < number_of_item_x)
    {
      // Upper line
607
      g_warning("      // Upper line\n");
608 609 610
      i = block_width * block;
      j = 0;
    } 
611
  else if(block < number_of_item_x + number_of_item_y - 2)
612 613
    {
      // Right line
614
      g_warning("      // Right line\n");
615 616 617 618 619 620
      i = block_width * (number_of_item_x - 1);
      j = block_height * (block - (number_of_item_x-1));
    }
  else if(block < number_of_item_x*2 + number_of_item_y - 2)
    {
      // Bottom line
621
      g_warning("      // Bottom line\n");
622 623
      i = block_width * (number_of_item_x - (block-
					     (number_of_item_x+number_of_item_y-1))-2);
624 625 626 627 628
      j = block_height * (number_of_item_y-1);
    }
  else
    {
      // Left line
629
      g_warning("      // Left line\n");
630 631 632 633 634
      i = 0;
      j = block_height * (number_of_item_y - (block - (number_of_item_x*2 + 
						      number_of_item_y-4)));
    }

635
  g_warning("display_tux %d i=%d j=%d\n", block, i, j);
636

Bruno Coudoin's avatar
Bruno Coudoin committed
637
  /* Calculation to thrink the item while keeping the ratio */
638 639 640 641 642 643 644 645 646 647
  if(ratio==-1)
    {
      xratio =  block_width  / (gdk_pixbuf_get_width (pixmap) + TUX_TO_BORDER_GAP);
      yratio =  block_height / (gdk_pixbuf_get_height(pixmap) + TUX_TO_BORDER_GAP);
      xratio = yratio = MIN(xratio, yratio);
    }
  else
    {
      xratio = yratio = ratio;
    }
Bruno Coudoin's avatar
Bruno Coudoin committed
648

649 650 651
  item = gnome_canvas_item_new (boardRootItem,
				gnome_canvas_pixbuf_get_type (),
				"pixbuf", pixmap, 
Bruno Coudoin's avatar
Bruno Coudoin committed
652 653 654 655 656 657
				"x", (double) i + (block_width -
						   (gdk_pixbuf_get_width (pixmap) * xratio)) / 2,
				"y", (double) j + (block_height -
						   (gdk_pixbuf_get_height (pixmap) * yratio)) / 2,
				"width", (double) gdk_pixbuf_get_width (pixmap) * xratio,
				"height", (double)  gdk_pixbuf_get_height (pixmap) * yratio,
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676
				"width_set", TRUE, 
				"height_set", TRUE,
				NULL);

  gdk_pixbuf_unref(pixmap);

  return(item);
}

/* ==================================== */
static void game_won()
{
  gcomprisBoard->sublevel++;

  if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) {
    /* Try the next level */
    gcomprisBoard->sublevel=1;
    gcomprisBoard->level++;
    if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
677
      gc_bonus_end_display(BOARD_FINISHED_RANDOM);
678 679
      return;
    }
680
    gc_sound_play_ogg ("sounds/bonus.ogg", NULL);
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
  }
  reversecount_next_level();
}

/* ==================================== */
/**
 * Increment the dices when they are clicked
 */

static gint
item_event(GnomeCanvasItem *item, GdkEvent *event, gint *dice_index)
{
  gchar *str;
  GdkPixbuf   *pixmap = NULL;
  gint i = *dice_index;

  if(board_paused)
    return FALSE;

  switch (event->type) 
    {
    case GDK_BUTTON_PRESS:
      switch(event->button.button) 
	{
	case 1:
	  if(dicevalue_array[i]++ >= max_dice_number)
707
	    dicevalue_array[i] = (number_of_dices==1 ? 1 : 0);
708 709 710
	  break;
	case 2:
	case 3:
711
	  if(dicevalue_array[i]-- == (number_of_dices==1 ? 1 : 0))
712 713 714 715 716 717 718 719
	    dicevalue_array[i] = max_dice_number;
	  break;
	default:
	  break;
	}

      str = g_strdup_printf("gcompris/dice/gnome-dice%d.png", dicevalue_array[i]);
      
720
      pixmap = gc_pixmap_load(str);
721 722 723 724 725 726

      /* Warning changing the image needs to update pixbuf_ref for the focus usage */
      g_object_set_data (G_OBJECT (item), "pixbuf_ref", pixmap);
      gnome_canvas_item_set (item,
      			     "pixbuf", pixmap,
      			     NULL);
727
      gdk_pixbuf_unref(pixmap);
728

729 730 731 732 733 734 735 736 737
      g_free(str);
      break;

    default:
      break;
    }

  return FALSE;
}
738 739 740 741 742 743 744

/*
 * Clock management
 */
static void create_clock(double x, double y, int value) 
{
  GdkPixbuf   *pixmap = NULL;
745
  char	      *str = NULL;
746 747 748 749

  if(value<0)
    return;

750
  str = g_strdup_printf("%s%d.png", "gcompris/timers/clock",value);
751

752
  pixmap = gc_pixmap_load(str);
753 754 755 756 757 758 759 760 761 762 763 764 765 766 767

  clock_image_item = gnome_canvas_item_new (boardRootItem,
					    gnome_canvas_pixbuf_get_type (),
					    "pixbuf", pixmap,
					    "x", (double) x,
					    "y", (double) y,
					    NULL);
  
  gdk_pixbuf_unref(pixmap);
  g_free(str);
}

static void update_clock(int value) 
{
  GdkPixbuf   *pixmap = NULL;
768
  char        *str = NULL;
769 770 771 772

  if(value<0)
    return;

773
  str = g_strdup_printf("%s%d.png", "gcompris/timers/clock",value);
774

775
  pixmap = gc_pixmap_load(str);
776 777 778 779 780 781 782 783

  gnome_canvas_item_set (clock_image_item,
			 "pixbuf", pixmap,
			 NULL);
  
  gdk_pixbuf_unref(pixmap);
  g_free(str);
}
784 785 786 787 788 789 790 791 792

static gint animate_tux()
{
  // Move tux
  if(tuxItem!=NULL)
    gtk_object_destroy(GTK_OBJECT(tuxItem));

  tux_index++;

793
  g_warning("=========== tux_index=%d tux_destination=%d fish_index=%d\n", tux_index, tux_destination, fish_index);
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828

  // Wrapping
  if(tux_index >= number_of_item)
    tux_index = tux_index - (number_of_item);

  /* Caclulate which tux should be displayed */
  if(tux_index<number_of_item_x-1)
    tuxItem = display_item_at(TUX_IMG_EAST, tux_index, tux_ratio);
  else if(tux_index<number_of_item_x+number_of_item_y-2)
    tuxItem = display_item_at(TUX_IMG_SOUTH, tux_index, tux_ratio);
  else if(tux_index<2*number_of_item_x+number_of_item_y-3)
    tuxItem = display_item_at(TUX_IMG_WEST, tux_index, tux_ratio);
  else
    tuxItem = display_item_at(TUX_IMG_NORTH, tux_index, tux_ratio);

  /* Rearm the timer to go to the next spot */
  if(tux_index != tux_destination)
    {
      animate_id = gtk_timeout_add (animate_speed,
      				    (GtkFunction) animate_tux, NULL);
    }
  else
    {
      animate_id = 0;

      if(tux_destination != fish_index)
	{
	  process_error();
	}
      else
	{
	  // Remove the fish
	  if(fishItem!=NULL)
	    gtk_object_destroy(GTK_OBJECT(fishItem));
	  
829
	  gc_sound_play_ogg ("sounds/gobble.ogg", NULL);
830 831 832 833 834
	  
	  if(--number_of_fish == 0)
	    {
	      gamewon = TRUE;
	      reversecount_destroy_all_items();
835
	      gc_bonus_display(gamewon, BONUS_SMILEY);
836 837 838 839 840 841 842 843 844 845
	    }
	  else
	    {
	      display_random_fish();
	    }
	}
    }

  return(FALSE);
}