Esempio n. 1
0
static VALUE
rg_set_simple_transform(VALUE self, VALUE x, VALUE y,
                                        VALUE scale, VALUE rotation)
{
    goo_canvas_item_set_simple_transform(SELF(self), NUM2DBL(x), NUM2DBL(y),
                                         NUM2DBL(scale), NUM2DBL(rotation));
    return self;
}
Esempio n. 2
0
static void
wire_changed_callback (Wire *wire, WireItem *item)
{
	Coords start_pos, length;
	GooCanvasPoints *points;

	g_return_if_fail (wire != NULL);
	g_return_if_fail (IS_ITEM_DATA (wire));
	g_return_if_fail (item != NULL);
	g_return_if_fail (IS_WIRE_ITEM (item));


	wire_get_pos_and_length (wire, &start_pos, &length);

	Sheet *sheet = SHEET (goo_canvas_item_get_canvas (GOO_CANVAS_ITEM (item)));
	if (G_UNLIKELY(!sheet)) {
		g_warning ("Failed to determine the Sheet the item is glued to. This should never happen. Ever!");
	} else {
		item_data_snap (ITEM_DATA (wire), sheet->grid);
	}

	// Move the canvas item and invalidate the bbox cache.
	goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (item),
	                                      start_pos.x,
	                                      start_pos.y,
	                                      1.0,
	                                      0.0);
	item->priv->cache_valid = FALSE;

	points = goo_canvas_points_new (2);
	points->coords[0] = 0;
	points->coords[1] = 0;
	points->coords[2] = length.x;
	points->coords[3] = length.y;

	// this does handle cleanup of previous points internally
	g_object_set (item->priv->line,
	              "points", points,
	              NULL);
	goo_canvas_points_unref (points);

	g_object_set (item->priv->resize1,
	              "x", -RESIZER_SIZE,
	              "y", -RESIZER_SIZE,
	              "width", 2 * RESIZER_SIZE,
	              "height", 2 * RESIZER_SIZE,
	              NULL);

	g_object_set (item->priv->resize2,
	              "x", length.x-RESIZER_SIZE,
	              "y", length.y-RESIZER_SIZE,
	              "width", 2 * RESIZER_SIZE,
	              "height", 2 * RESIZER_SIZE,
	              NULL);

	goo_canvas_item_request_update (GOO_CANVAS_ITEM (item->priv->line));
}
Esempio n. 3
0
static void
start_animation_clicked (GtkWidget *button, gpointer data)
{
  /* Absolute. */
  goo_canvas_item_set_simple_transform (ellipse1, 100, 100, 1, 0);
  goo_canvas_item_animate (ellipse1, 500, 100, 2, 720, TRUE, 2000, 40,
			   GOO_CANVAS_ANIMATE_BOUNCE);

  goo_canvas_item_set_simple_transform (rect1, 100, 200, 1, 0);
  goo_canvas_item_animate (rect1, 100, 200, 1, 350, TRUE, 40 * 36, 40,
			   GOO_CANVAS_ANIMATE_RESTART);

  goo_canvas_item_set_simple_transform (rect3, 200, 200, 1, 0);
  goo_canvas_item_animate (rect3, 200, 200, 3, 0, TRUE, 400, 40,
			   GOO_CANVAS_ANIMATE_BOUNCE);

  /* Relative. */
  goo_canvas_item_set_simple_transform (ellipse2, 100, 400, 1, 0);
  goo_canvas_item_animate (ellipse2, 400, 0, 2, 720, FALSE, 2000, 40,
			   GOO_CANVAS_ANIMATE_BOUNCE);

  goo_canvas_item_set_simple_transform (rect2, 100, 500, 1, 0);
  goo_canvas_item_animate (rect2, 0, 0, 1, 350, FALSE, 40 * 36, 40,
			   GOO_CANVAS_ANIMATE_RESTART);

  goo_canvas_item_set_simple_transform (rect4, 200, 500, 1, 0);
  goo_canvas_item_animate (rect4, 0, 0, 3, 0, FALSE, 400, 40,
			   GOO_CANVAS_ANIMATE_BOUNCE);
}
Esempio n. 4
0
// This is called when the wire data was moved. Update the view accordingly.
static void
wire_moved_callback (ItemData *data, SheetPos *pos, SheetItem *item)
{
	WireItem *wire_item;

	g_return_if_fail (data != NULL);
	g_return_if_fail (IS_ITEM_DATA (data));
	g_return_if_fail (item != NULL);
	g_return_if_fail (IS_WIRE_ITEM (item));

	if (pos == NULL)
		return;

	wire_item = WIRE_ITEM (item);

	// Move the canvas item and invalidate the bbox cache.
	goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (item),
	                                      pos->x,
	                                      pos->y,
	                                      1.0,
	                                      0.0);
	wire_item->priv->cache_valid = FALSE;
}
Esempio n. 5
0
static void
update_preview (Browser *br)
{
	LibraryPart *library_part;
	gdouble new_x, new_y, x1, y1, x2, y2;
	gdouble text_width;
	gdouble width, height;
	GooCanvasBounds bounds;
	gdouble scale; 
	cairo_matrix_t transf, affine;
	gchar *part_name;
	char *description;
	GtkTreeModel *model;
	GtkTreeIter iter;
	GtkTreeSelection *selection;

	// Get the current selected row
	selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (br->list));
	model = gtk_tree_view_get_model (GTK_TREE_VIEW (br->list));

	if (!GTK_IS_TREE_SELECTION (selection)) return;
	
	if (!gtk_tree_selection_get_selected (selection, NULL, &iter)) {
		return;
	}

	gtk_tree_model_get (model, &iter, 0, &part_name, -1);

	library_part = library_get_part (br->library, part_name);
	
	// If there is already a preview part-item, destroy its group and create a
	// new one.
	if (br->preview != NULL) {
		goo_canvas_item_remove (GOO_CANVAS_ITEM (br->preview));
	}
	
	br->preview = GOO_CANVAS_GROUP (goo_canvas_group_new (
	    goo_canvas_get_root_item (GOO_CANVAS (br->canvas)),
	    NULL));

	goo_canvas_set_bounds (GOO_CANVAS (br->canvas), 0.0, 0.0, 250.0, 110.0);

	g_object_get (br->preview, 
	              "width", &width, 
	              "height", &height, 
	              NULL);
	
	if (!library_part)
		return;

	part_item_create_canvas_items_for_preview (br->preview, library_part);

	// Unconstraint the canvas width & height to adjust for the part description
	g_object_set (br->preview,
	              "width", -1.0,
	              "height", -1.0,
	              NULL);
	
	// Get the coordonates */
	goo_canvas_item_get_bounds (GOO_CANVAS_ITEM (br->preview), &bounds);
	x1 = bounds.x1;
	x2 = bounds.x2;
	y1 = bounds.y1;
	y2 = bounds.y2;

	// Translate in such a way that the canvas centre remains in (0, 0) 
	cairo_matrix_init_translate (&transf, -(x2 + x1) / 2.0f + PREVIEW_WIDTH / 2,
	                             -(y2 + y1) / 2.0f + PREVIEW_HEIGHT / 2);

	// Compute the scale of the widget 
	if ((x2 - x1 != 0) || (y2 - y1 != 0)) {
		if ((x2 - x1) < (y2 - y1))
			scale = 0.60f * PREVIEW_HEIGHT / (y2 - y1);
		else
			scale = 0.60f * PREVIEW_WIDTH / (x2 - x1);
	} 
	else
		scale = 5;

	cairo_matrix_init_scale (&affine, scale, scale);
	cairo_matrix_multiply (&transf, &transf, &affine);

	// Apply the transformation 
	goo_canvas_item_set_transform (GOO_CANVAS_ITEM (br->preview), &transf);
	
	// Compute the motion to centre the Preview widget 
	new_x = 100 + (PREVIEW_WIDTH - x1 - x2) / 2;
	new_y = (PREVIEW_HEIGHT - y1 - y2) / 2 - 10;

	// Apply the transformation 
	if (scale > 5.0) scale = 3.0;
	goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (br->preview), 
	                                      new_x,
	                                      new_y,
	                                      scale,
	                                      0.0);
    	
	description = g_strdup (library_part->description);
	wrap_string (description, 20);
	g_object_set (br->description,
	              "text", description, 
	              NULL);
	g_free (description);

	g_object_get (G_OBJECT (br->description),
	              "width", &text_width, 
	              NULL);
	
	goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (br->description), 
	                                      50.0, 
	                                      -20.0,
	                                      1.0,
	                                      0.0);
	g_free (part_name);
}
Esempio n. 6
0
/**
 * whenever the model changes, this one gets called to update the view representation
 * @attention this recalculates the matrix every time, this makes sure no errors stack up
 * @attention further reading on matrix manipulations
 * @attention http://www.cairographics.org/matrix_transform/
 * @param data the model item, a bare C struct derived from ItemData
 * @param sheet_item the view item, derived from goo_canvas_group/item
 */
static void
part_changed_callback (ItemData *data, SheetItem *sheet_item)
{
	//TODO add static vars in order to skip the redraw if nothing changed
	//TODO may happen once in a while and the check is really cheap
	GSList *iter;
	GooCanvasAnchorType anchor;
	GooCanvasGroup *group;
	GooCanvasItem *canvas_item;
	PartItem *item;
	PartItemPriv *priv;
	Part *part;
	int index = 0;
	Coords pos;
	double scale_h, scale_v;


	// states
	int rotation;
	IDFlip flip;

	g_return_if_fail (sheet_item != NULL);
	g_return_if_fail (IS_PART_ITEM (sheet_item));

	item = PART_ITEM (sheet_item);
	group = GOO_CANVAS_GROUP (item);
	part = PART (data);

	priv = item->priv;

	// init the states

	flip = part_get_flip (part);
	rotation = part_get_rotation (part);

	DEGSANITY (rotation);

	scale_h = (flip & ID_FLIP_HORIZ) ? -1. : 1.;
	scale_v = (flip & ID_FLIP_VERT) ? -1. : 1.;


	item_data_get_pos (data, &pos);
	// Move the canvas item and invalidate the bbox cache.
	goo_canvas_item_set_simple_transform (GOO_CANVAS_ITEM (sheet_item),
	                                      pos.x,
	                                      pos.y,
	                                      1.0,
	                                      0.0);

	cairo_matrix_t morph, inv;
	cairo_status_t done;

	cairo_matrix_init_rotate (&morph, DEG2RAD (rotation));
	cairo_matrix_scale (&morph, scale_h, scale_v);

	inv = morph;
	done = cairo_matrix_invert (&inv);
	if (done != CAIRO_STATUS_SUCCESS) {
		g_warning ("Failed to invert matrix. This should never happen. Never!");
		return;
	}

	// rotate all items in the canvas group
	for (index = 0; index < group->items->len; index++) {
		canvas_item = GOO_CANVAS_ITEM (group->items->pdata[index]);
		goo_canvas_item_set_transform (GOO_CANVAS_ITEM (canvas_item), &morph);
	}

	// revert the rotation of all labels and change their anchor to not overlap too badly
	// this assures that the text is always horizontal and properly aligned
	anchor = angle_to_anchor (rotation);

	for (iter = priv->label_items; iter; iter = iter->next) {
		g_object_set (iter->data,
		              "anchor", anchor,
		              NULL);

		goo_canvas_item_set_transform (iter->data, &inv);

	}
	// same for label nodes
	for (iter = priv->label_nodes; iter; iter = iter->next) {
		g_object_set (iter->data,
		              "anchor", anchor, 
		              NULL);

		goo_canvas_item_set_transform (iter->data, &inv);
	}


	// Invalidate the bounding box cache.
	priv->cache_valid = FALSE;
}
Esempio n. 7
0
/* =====================================================================
 * Periodically recalculate some submarine parameters, with a larger delay
 * =====================================================================*/
static gboolean update_timeout_slow() {
  gdouble delta_assiette;

  if(!boardRootItem)
    return FALSE;

  if(board_paused)
    return TRUE;

  /* speed : don't reach instantly the ordered speed */
  if (speed_ordered != submarine_horizontal_speed) {
    submarine_horizontal_speed += (speed_ordered-submarine_horizontal_speed)/10.0;
    if (fabs(speed_ordered - submarine_horizontal_speed) < 0.1)
      submarine_horizontal_speed = speed_ordered;
  }

  /* assiette */
  delta_assiette = (ballast_ar_air - ballast_av_air)/200.0 +
    (barre_av_angle - barre_ar_angle)/5.0*submarine_horizontal_speed;
  assiette -= delta_assiette*UPDATE_DELAY/10000.0;
  if (assiette < -30.0)
    assiette = -30.0;
  if (assiette > 30.0)
    assiette = 30.0;

  /* If surfacing, diminish the 'assiette' */
  if ( depth <= 5.0 + SURFACE_DEPTH) {
    assiette *= depth/(depth+1.0);
  }

  /* update some dynamic parameters */
  /* resulting_weight > 0 ==> the sub goes deeper
     regleur : this is the qty of water */
  resulting_weight = weight - ballast_av_air - ballast_ar_air + regleur;
  submarine_vertical_speed = resulting_weight/300.0
    + submarine_horizontal_speed*sin(DEG_TO_RAD(-assiette));

  /* if depth rudders are in the same direction */
  if (barre_ar_angle != 0.0 && barre_av_angle != 0.0) {
    if (fabs(barre_ar_angle)/barre_ar_angle == fabs(barre_av_angle)/barre_av_angle) {
      gdouble a = (fabs(barre_ar_angle) > fabs(barre_av_angle)) ? barre_av_angle : barre_ar_angle;
      submarine_vertical_speed += a * submarine_horizontal_speed/30.0;
    }
  }

  /* position & depth */
  submarine_x += submarine_horizontal_speed
    * cos(DEG_TO_RAD(assiette))
    * UPDATE_DELAY_SLOW/1000.0;

  depth += submarine_vertical_speed * UPDATE_DELAY_SLOW/1000.0;

  if (depth < SURFACE_DEPTH)
    depth = SURFACE_DEPTH;
  if (depth > MAX_DEPTH)
    depth = MAX_DEPTH;

  // show an alert if some parameters reach the limit
  if (depth >= MAX_DEPTH-20.0 || assiette == -30.0
      || assiette == 30.0 || air == 0.0 || battery == 0.0)
    g_object_set (alert_submarine,
		  "visibility", GOO_CANVAS_ITEM_VISIBLE,
		  NULL);
  else
    g_object_set (alert_submarine,
		  "visibility", GOO_CANVAS_ITEM_INVISIBLE,
		  NULL);

  /* if the submarine dives, stop charging air tanks and batteries */
  if ( depth >= SURFACE_DEPTH+10.0 ) {
    if (air_charging) {
      air_charging = FALSE;
      gc_item_rotate_with_center(air_compressor_item, 0,
				 TRIGGER_CENTER_X, TRIGGER_CENTER_Y );
    }
    if (battery_charging) {
      battery_charging = FALSE;
      gc_item_rotate_with_center(battery_charger_item, 0,
				 TRIGGER_CENTER_X, TRIGGER_CENTER_Y );
    }
  }

  /* Check the submarine passed the right door */
  if ( submarine_x > WRAP_X && !gamewon )
    {
      /* Check its within the gate range */
      GooCanvasBounds bounds;

      goo_canvas_item_get_bounds (submarine_item, &bounds);

      guint antena_height = 30;
      if(bounds.y1 + antena_height < gate_top_current_y ||
	 bounds.y2 > gate_bottom_y)
	{
	  /* It's a crash */
	  submarine_explosion();
	}
      else
	{
	  gamewon = TRUE;
	  ok();
	}
    }

  /* Open the door */
  if(treasure_captured && gate_top_current_y > gate_top_y)
    open_door();

  /* display the submarine */
  goo_canvas_item_set_simple_transform(submarine_item,
				       submarine_x - submarine_width/2.0,
				       depth + SURFACE_DEPTH - submarine_height/2.0,
				       1, -assiette);

  /* the frigate */
  if ( frigate_item ) {
    /* detects a collision between the frigate and the submarine */
    if (depth <= 30.0 && !submarine_destroyed) {
      GooCanvasBounds bounds;
      goo_canvas_item_get_bounds(frigate_item, &bounds);
      gdouble frigate_x = bounds.x1 + (bounds.x2 - bounds.x1) / 2;
      if ( abs(submarine_x - frigate_x) < 100 ) {
        submarine_explosion();
	return TRUE;
      }
    }
  }

  /* whale detection */
  {
    gdouble dist1 = hypot( submarine_x - whale_x,  depth - whale_y);
    if ( ( dist1 < WHALE_DETECTION_RADIUS ) && !submarine_destroyed ) {
      g_object_set (whale, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
      g_object_set (big_explosion, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
      submarine_explosion();
      return TRUE;
    }
  }

  /* treasure detection */
  {
    gdouble dist1 = hypot( submarine_x - treasure_x, depth - treasure_y);
    if ( (dist1 < TREASURE_DETECTION_RADIUS)
	 && !treasure_captured ) {
      gc_sound_play_ogg("sounds/tuxok.wav", NULL);
      g_object_set (treasure, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
      treasure_captured = TRUE;
      open_door();
    }
  }

  return TRUE;
}
Esempio n. 8
0
/* =====================================================================
 * Periodically recalculate some submarine parameters, with a larger delay
 * =====================================================================*/
static gboolean update_timeout_slow() {
  gdouble delta_assiette;

  if(!boardRootItem)
    return FALSE;

  if(board_paused)
    return TRUE;

  /* speed : don't reach instantly the ordered speed */
  if (speed_ordered != submarine_horizontal_speed) {
    submarine_horizontal_speed += (speed_ordered-submarine_horizontal_speed)/10.0;
    if (fabs(speed_ordered - submarine_horizontal_speed) < 0.1)
      submarine_horizontal_speed = speed_ordered;
  }

  /* assiette */
  delta_assiette = (ballast_ar_air - ballast_av_air)/200.0 +
    (barre_av_angle - barre_ar_angle)/5.0*submarine_horizontal_speed;
  assiette -= delta_assiette*UPDATE_DELAY/10000.0;
  if (assiette < -30.0)
    assiette = -30.0;
  if (assiette > 30.0)
    assiette = 30.0;

  /* If surfacing, diminish the 'assiette' */
  if ( depth <= 5.0 + SURFACE_DEPTH) {
    assiette *= depth/(depth+1.0);
  }

  /* update some dynamic parameters */
  /* resulting_weight > 0 ==> the sub goes deeper
     regleur : this is the qty of water */
  resulting_weight = weight - ballast_av_air - ballast_ar_air + regleur;
  submarine_vertical_speed = resulting_weight/300.0
    + submarine_horizontal_speed*sin(DEG_TO_RAD(-assiette));

  /* if depth rudders are in the same direction */
  if (barre_ar_angle != 0.0 && barre_av_angle != 0.0) {
    if (fabs(barre_ar_angle)/barre_ar_angle == fabs(barre_av_angle)/barre_av_angle) {
      gdouble a = (fabs(barre_ar_angle) > fabs(barre_av_angle)) ? barre_av_angle : barre_ar_angle;
      submarine_vertical_speed += a * submarine_horizontal_speed/30.0;
    }
  }

  /* position & depth */
  submarine_x += submarine_horizontal_speed
    * cos(DEG_TO_RAD(assiette))
    * UPDATE_DELAY_SLOW/1000.0;

  depth += submarine_vertical_speed * UPDATE_DELAY_SLOW/1000.0;

  if (depth < SURFACE_DEPTH)
    depth = SURFACE_DEPTH;
  if (depth > MAX_DEPTH)
    depth = MAX_DEPTH;

  // show an alert if some parameters reach the limit
  if (depth >= MAX_DEPTH-20.0 || assiette == -30.0
      || assiette == 30.0 || air == 0.0 || battery == 0.0)
    g_object_set (alert_submarine,
		  "visibility", GOO_CANVAS_ITEM_VISIBLE,
		  NULL);
  else
    g_object_set (alert_submarine,
		  "visibility", GOO_CANVAS_ITEM_INVISIBLE,
		  NULL);

  /* if the submarine dives, stop charging air tanks and batteries */
  if ( depth >= SURFACE_DEPTH+10.0 ) {
    if (air_charging) {
      air_charging = FALSE;
      gc_item_rotate_with_center(air_compressor_item, 0,
				 TRIGGER_CENTER_X, TRIGGER_CENTER_Y );
    }
    if (battery_charging) {
      battery_charging = FALSE;
      gc_item_rotate_with_center(battery_charger_item, 0,
				 TRIGGER_CENTER_X, TRIGGER_CENTER_Y );
    }
  }

  /* if the submarine is too close from right, put it on the left */
  if ( submarine_x > WRAP_X )
    {
      /* Check its within the gate range */
      GooCanvasBounds bounds;

      goo_canvas_item_get_bounds (submarine_item, &bounds);

      if(bounds.y1 < gate_top_current_y ||
	 bounds.y2 > gate_bottom_y)
	{
	  /* It's a crash */
	  submarine_explosion();
	}
      else
	{
	  gamewon = TRUE;
	  /* Let the user play indefinitly at level 3 */
	  if(gcomprisBoard->level<3)
	    gc_bonus_display(gamewon, GC_BONUS_SMILEY);
	  else
	    {
	      submarine_x = SUBMARINE_INITIAL_X;
	      depth = SUBMARINE_INITIAL_DEPTH;
	    }
	}
    }

  /* Open the door */
  if(treasure_captured && gate_top_current_y > gate_top_y)
    open_door();

  /* display the submarine */
  goo_canvas_item_set_simple_transform(submarine_item,
				       submarine_x - submarine_width/2.0,
				       depth + SURFACE_DEPTH - submarine_height/2.0,
				       1, -assiette);

  /* the frigate */
  {
    GooCanvasBounds bounds;
    goo_canvas_item_get_bounds(frigate_item, &bounds);
    //goo_canvas_item_translate(frigate_item, - FRIGATE_SPEED * UPDATE_DELAY_SLOW/1000.0, 0.0);
    /* detects a collision between the frigate and the submarine */
    if (depth <= 30.0 && !submarine_destroyed)
      if ( (submarine_x - submarine_width <= bounds.x1 && submarine_x >= bounds.x2) ||
	   (submarine_x - submarine_width >= bounds.x1 && submarine_x - submarine_width <= bounds.x2) ||
	   (submarine_x >= bounds.x1 && submarine_x <= bounds.x2) ) {
        submarine_explosion();
      }
    /* wraps the destroyer if it reached the left side (and disappeared for a long time)*/
    //if (bounds.x2 < -300.0)
    //gc_item_absolute_move( frigate_item, BOARDWIDTH, bounds.y1 );
  }

  /* whale detection */
  {
    gdouble dist1, dist2, dist3;
    dist1 = hypot( submarine_x -submarine_width/2 -whale_x,
		   depth+SURFACE_IN_BACKGROUND-whale_y);
    dist2 = hypot(submarine_x - submarine_width - whale_x,
		  depth+SURFACE_IN_BACKGROUND-whale_y);
    dist3 = hypot(submarine_x - whale_x,
		  depth+SURFACE_IN_BACKGROUND-whale_y);
    /* magnetic detection (dist1) or collision with the whale (dist2 & dist3) */
    if ( (dist1 < WHALE_DETECTION_RADIUS
	  || dist2 < WHALE_DETECTION_RADIUS
	  || dist3 < WHALE_DETECTION_RADIUS)
	 && !submarine_destroyed ) {
      g_object_set (whale, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
      g_object_set (big_explosion, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
      submarine_explosion();
    }
  }

  /* treasure detection */
  {
    gdouble dist1, dist2, dist3;
    dist1 = hypot( submarine_x -submarine_width/2 -treasure_x,
		   depth+SURFACE_IN_BACKGROUND-treasure_y);
    dist2 = hypot(submarine_x - submarine_width - treasure_x,
		  depth+SURFACE_IN_BACKGROUND-treasure_y);
    dist3 = hypot(submarine_x - treasure_x,
		  depth+SURFACE_IN_BACKGROUND-treasure_y);
    /* magnetic detection (dist1) or collision with the treasure (dist2 & dist3) */
    if ( (dist1 < TREASURE_DETECTION_RADIUS
	  || dist2 < TREASURE_DETECTION_RADIUS
	  || dist3 < TREASURE_DETECTION_RADIUS)
	 && !treasure_captured ) {
      gc_sound_play_ogg("sounds/tuxok.wav", NULL);
      g_object_set (treasure, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
      treasure_captured = TRUE;
      open_door();
    }
  }

  return TRUE;
}