Commit 9a99a80f authored by Yves Combe's avatar Yves Combe

new board crane by Marc BRUN.

parent 08ddffc9
2006-01-01 Yves Combe <yves@ycombe.net>
new board crane by Marc BRUN.
NOT added in potfile yet.
* boards/Makefile.am:
* boards/boardicons/crane.png:
* boards/crane.xml.in:
* boards/crane/arrow_b.png:
* boards/crane/arrow_l.png:
* boards/crane/arrow_r.png:
* boards/crane/arrow_u.png:
* boards/crane/bulb.png:
* boards/crane/crane-bg.png:
* boards/crane/letter-a.png:
* boards/crane/letter-b.png:
* boards/crane/letter-c.png:
* boards/crane/rectangle1.png:
* boards/crane/rectangle2.png:
* boards/crane/selected.png:
* boards/crane/square1.png:
* boards/crane/square2.png:
* boards/crane/triangle1.png:
* boards/crane/triangle2.png:
* boards/crane/tux.png:
* boards/crane/water_drop1.png:
* boards/crane/water_drop2.png:
* boards/crane/water_spot1.png:
* boards/crane/water_spot2.png:
* po/Makefile.in.in:
* src/boards/Makefile.am:
* src/boards/crane.c: (pause_board), (start_board), (end_board),
(set_level), (is_our_board), (crane_next_level),
(crane_destroy_all_items), (crane_create_item), (bonus),
(finished), (game_won), (item_event), (arrow_event), (draw_arrow),
(draw_redhands), (draw_frame), (place_item), (smooth_move),
(is_allowed_move), (get_item_index), (shuffle_list), (select_item):
2005-12-19 Bruno coudoin <bruno.coudoin@free.fr>
- Patch by Patrick GOLDBRONN pgoldbronn on free.fr
......
......@@ -30,6 +30,7 @@ xml_in_files = \
clickgame.xml.in \
clockgame.xml.in \
colors.xml.in \
crane.xml.in \
colors_group.xml.in \
computer.xml.in \
connect4.xml.in \
......
<?xml version="1.0" encoding="UTF-8"?>
<GCompris>
<Board
name="crane"
type="crane"
section="/boards"
icon="boardicons/crane.png"
difficulty="0"
mode="normal"
author="Marc BRUN"
boarddir="">
<_title>Build the same</_title>
<_description>Copy the model</_description>
<_prerequisite>Mouse manipulation</_prerequisite>
<_goal>Motor-coordination</_goal>
<_manual>
Move the item from the bottom left frame to have them positioned the same as in the top right model.
</_manual>
<_credit></_credit>
</Board>
</GCompris>
......@@ -11,6 +11,11 @@
#
# - Modified by jacob berkman <jacob@ximian.com> to install
# Makefile.in.in and po2tbl.sed.in for use with glib-gettextize
#
# - Modified by Rodney Dawes <dobey@novell.com> for use with intltool
#
# We have the following line for use by intltoolize:
# INTLTOOL_MAKEFILE
GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
PACKAGE = @PACKAGE@
......@@ -27,13 +32,13 @@ VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
datadir = @datadir@
datarootdir = @datarootdir@
libdir = @libdir@
localedir = $(libdir)/locale
gnulocaledir = $(datadir)/locale
gettextsrcdir = $(datadir)/glib-2.0/gettext/po
subdir = po
install_sh = @install_sh@
mkdir_p = @mkdir_p@
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
INSTALL = @INSTALL@
......@@ -61,7 +66,8 @@ SOURCES =
POFILES = @POFILES@
GMOFILES = @GMOFILES@
DISTFILES = ChangeLog Makefile.in.in POTFILES.in \
$(POFILES) $(GMOFILES) $(SOURCES)
$(POFILES) $(SOURCES)
EXTRA_DISTFILES = POTFILES.skip Makevars LINGUAS
POTFILES = \
......@@ -77,7 +83,7 @@ INSTOBJEXT = @INSTOBJEXT@
.po.pox:
$(MAKE) $(GETTEXT_PACKAGE).pot
$(MSGMERGE) $< $(top_builddir)/po/$(GETTEXT_PACKAGE).pot -o $*pox
$(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox
.po.mo:
$(MSGFMT) -o $@ $<
......@@ -174,7 +180,7 @@ uninstall:
rm -f $(DESTDIR)$(gettextsrcdir)/Makefile.in.in; \
fi
check: all
check: all $(GETTEXT_PACKAGE).pot
dvi info tags TAGS ID:
......@@ -186,16 +192,21 @@ mostlyclean:
clean: mostlyclean
distclean: clean
rm -f Makefile Makefile.in POTFILES *.mo *.msg *.cat *.cat.m
rm -f Makefile Makefile.in POTFILES
rm -f *.mo *.msg *.cat *.cat.m $(GMOFILES)
maintainer-clean: distclean
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
rm -f $(GMOFILES)
rm -f Makefile.in.in
distdir = ../$(GETTEXT_PACKAGE)-$(VERSION)/$(subdir)
dist distdir: $(DISTFILES) $(GETTEXT_PACKAGE).pot
dist distdir: $(DISTFILES)
dists="$(DISTFILES)"; \
extra_dists="$(EXTRA_DISTFILES)"; \
for file in $$extra_dists; do \
test -f $$file && dists="$$dists $$file"; \
done; \
for file in $$dists; do \
ln $(srcdir)/$$file $(distdir) 2> /dev/null \
|| cp -p $(srcdir)/$$file $(distdir); \
......@@ -232,17 +243,13 @@ update-po: Makefile
# and Intltool tags (enclosed in square brackets), and appending a full
# relative path to them
POTFILES: POTFILES.in
( if test 'x$(srcdir)' != 'x.'; then \
posrcprefix='$(top_srcdir)/'; \
else \
posrcprefix="../"; \
fi; \
( posrcprefix='$(top_srcdir)/'; \
rm -f $@-t $@ \
&& (sed -e '/^#/d' \
-e "s/^\[.*\] +//" \
-e '/^[ ]*$$/d' \
-e "s@.*@ $$posrcprefix& \\\\@" < $(srcdir)/$@.in \
| sed -e '$$s/\\$$//') > $@-t \
&& (sed -e '/^#/d' \
-e 's/^[[].*] *//' \
-e '/^[ ]*$$/d' \
-e "s@^@ $$posrcprefix@" $(srcdir)/$@.in \
| sed -e '$$!s/$$/ \\/') > $@-t \
&& chmod a-w $@-t \
&& mv $@-t $@ )
......
......@@ -36,6 +36,7 @@ lib_LTLIBRARIES = \
libclickgame.la \
libclockgame.la \
libcolors.la \
libcrane.la \
liberase.la \
libenumerate.la \
libfifteen.la \
......@@ -87,6 +88,10 @@ libawele_la_LDFLAGS = -module -avoid-version
libawele_la_LIBADD = $(top_builddir)/src/gcompris/libgcompris-1.la
libawele_la_SOURCES = awele.c awele_alphaBeta.c awele_utils.c
libcrane_la_LDFLAGS = -module -avoid-version
libcrane_la_LIBADD = $(top_builddir)/src/gcompris/libgcompris-1.la
libcrane_la_SOURCES = crane.c
libmenu_la_LDFLAGS = -module -avoid-version
libmenu_la_LIBADD = $(top_builddir)/src/gcompris/libgcompris-1.la
libmenu_la_SOURCES = menu.c
......
/* gcompris - crane.c
*
* Copyright (C) 2005 Marc BRUN
*
* 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 <string.h>
#include <unistd.h>
#include "gcompris/gcompris.h"
// Define
#define SOUNDLISTFILE PACKAGE
#define CRANE_BUTTON_WIDTH 20
#define CRANE_BUTTON_HEIGHT 50
#define CRANE_BUTTON_SPACE 20 // Space between a pair (left/right or up/down)
#define CRANE_BUTTON_LEFT_X 200
#define CRANE_BUTTON_LEFT_Y 72
#define CRANE_BUTTON_RIGHT_X (CRANE_BUTTON_LEFT_X + CRANE_BUTTON_HEIGHT + CRANE_BUTTON_SPACE)
#define CRANE_BUTTON_RIGHT_Y CRANE_BUTTON_LEFT_Y
#define CRANE_BUTTON_UP_X 408
#define CRANE_BUTTON_UP_Y 200
#define CRANE_BUTTON_DOWN_X CRANE_BUTTON_UP_X
#define CRANE_BUTTON_DOWN_Y (CRANE_BUTTON_UP_Y + CRANE_BUTTON_HEIGHT + CRANE_BUTTON_SPACE)
#define CRANE_FRAME_X 38
#define CRANE_FRAME_Y 168
#define CRANE_FRAME_COLUMN 6
#define CRANE_FRAME_LINE 5
#define CRANE_FRAME_CELL 52
#define CRANE_FRAME_BORDER 6
#define CRANE_FRAME_IMAGE_SIZE 40
#define CRANE_FRAME_MODEL_X 460
#define CRANE_FRAME_MODEL_Y 107
#define RIGHT 0
#define LEFT 1
#define UP 2
#define DOWN 3
#define MAX_LEVEL 6 // Don't raise this number except if putting more values in pixmap[] array, in place_item function
#define NB_ELEMENT (2 * MAX_LEVEL) + 2
// Types
// Structure describes the objects of the frames
typedef struct {
GdkPixbuf *pixmap;
double x;
double y;
double h;
double w;
} crane_object;
// Structure decribes a movement
typedef struct {
int x; // x movement
int y; // y movement
int nb; // how much of x/y movement (to give a smooth effect) ?
} move_object;
// Global variables
static GcomprisBoard *gcomprisBoard = NULL;
static gboolean board_paused = TRUE;
static GnomeCanvasGroup *boardRootItem = NULL;
static GnomeCanvasItem *selected_item = NULL;
static GnomeCanvasItem *red_hands = NULL;
static gint timer_id = 0;
static gint nb_move = 0;
static gboolean moving = FALSE;
static move_object my_move;
static int list_answer[CRANE_FRAME_LINE * CRANE_FRAME_COLUMN];
static int list_game[CRANE_FRAME_LINE * CRANE_FRAME_COLUMN];
// gcompris functions
static void start_board (GcomprisBoard *agcomprisBoard);
static void pause_board (gboolean pause);
static void end_board (void);
static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
static void set_level (guint level);
static int gamewon;
static void game_won(void);
static GnomeCanvasItem *crane_create_item();
static void crane_destroy_all_items(void);
static void crane_next_level(void);
// crane functions
static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static gint arrow_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
static guint smooth_move(move_object *);
static int is_allowed_move (double, double, int);
static void shuffle_list(int list[], int);
static void select_item(GnomeCanvasItem *, int);
static int get_item_index (double, double);
static void draw_arrow(void);
static void draw_frame(int, int);
static void draw_redhands(void);
static void place_item(int, int, int);
/* Description of this plugin */
static BoardPlugin menu_bp =
{
NULL,
NULL,
"Duplicate the top right model.",
"Select item in the bottom left frame and move them with the crane's arrows.",
"Marc BRUN",
NULL,
NULL,
NULL,
NULL,
start_board,
pause_board,
end_board,
is_our_board,
NULL,
NULL,
set_level,
NULL,
NULL,
NULL,
NULL
};
/*
* Main entry point mandatory for each Gcompris's game
* ---------------------------------------------------
*
*/
GET_BPLUGIN_INFO(crane)
static void pause_board (gboolean pause)
{
if (gcomprisBoard == NULL)
return;
if (timer_id) {
gtk_timeout_remove (timer_id);
timer_id = 0;
}
/* the game is won */
if (gamewon == TRUE && pause == FALSE)
game_won();
board_paused = pause;
}
static void start_board (GcomprisBoard *agcomprisBoard)
{
if (agcomprisBoard != NULL) {
gcomprisBoard = agcomprisBoard;
gcomprisBoard->level = 1;
gcomprisBoard->maxlevel = MAX_LEVEL;
gcomprisBoard->sublevel = 1;
gcomprisBoard->number_of_sublevel = 1; /* Go to next level after this number of 'play' */
gcompris_bar_set(GCOMPRIS_BAR_LEVEL);
crane_next_level();
gamewon = FALSE;
pause_board(FALSE);
}
}
static void end_board () {
if (timer_id) {
gtk_timeout_remove (timer_id);
timer_id = 0;
}
if (gcomprisBoard != NULL) {
pause_board(TRUE);
crane_destroy_all_items();
}
gcomprisBoard = NULL;
}
/* ======================================= */
static void set_level (guint level) {
if (gcomprisBoard != NULL) {
gcomprisBoard->level = level;
gcomprisBoard->sublevel = 1;
crane_next_level();
}
}
/* ======================================= */
static gboolean is_our_board (GcomprisBoard *gcomprisBoard) {
if (gcomprisBoard) {
if (g_strcasecmp(gcomprisBoard->type, "crane") == 0) {
/* Set the plugin entry */
gcomprisBoard->plugin = &menu_bp;
return TRUE;
}
}
return FALSE;
}
/*-------------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------------*/
/* set initial values for the next level */
static void crane_next_level() {
gcompris_set_background(gnome_canvas_root(gcomprisBoard->canvas), "crane/crane-bg.png");
gcompris_bar_set_level(gcomprisBoard);
crane_destroy_all_items();
gamewon = FALSE;
/* Try the next level */
crane_create_item();
}
/* ==================================== */
/* Destroy all the items */
static void crane_destroy_all_items()
{
if (timer_id) {
gtk_timeout_remove (timer_id);
timer_id = 0;
}
if(boardRootItem != NULL)
gtk_object_destroy (GTK_OBJECT(boardRootItem));
boardRootItem = NULL;
}
/* ==================================== */
static GnomeCanvasItem *crane_create_item()
{
int i;
int nb_element;
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));
// The four arrows on the crane
draw_arrow();
// The leading frames on both model (answer) and boardgame, only for first levels
if (gcomprisBoard->level < 5) {
draw_frame(CRANE_FRAME_X, CRANE_FRAME_Y); // Boardgame
draw_frame(CRANE_FRAME_MODEL_X, CRANE_FRAME_MODEL_Y); // Model
}
// The red corners (hands) that show the selected item
draw_redhands();
nb_element = gcomprisBoard->level * 2 + 2;
// Answer frame => the unmovable items of the model
for (i = 0 ; i < nb_element ; i++) list_answer[i] = i;
for ( ; i < CRANE_FRAME_LINE * CRANE_FRAME_COLUMN ; i ++) list_answer[i] = -1;
shuffle_list(list_answer, CRANE_FRAME_LINE * CRANE_FRAME_COLUMN);
place_item(CRANE_FRAME_MODEL_X, CRANE_FRAME_MODEL_Y, 0);
// Game frame => the playable items
for (i = 0 ; i < nb_element ; i++) list_game[i] = i;
for ( ; i < CRANE_FRAME_LINE * CRANE_FRAME_COLUMN ; i ++) list_game[i] = -1;
shuffle_list(list_game, CRANE_FRAME_LINE * CRANE_FRAME_COLUMN);
place_item(CRANE_FRAME_X, CRANE_FRAME_Y, 1);
return NULL;
}
// Display an happy face for end of level
static void bonus() {
gcompris_display_bonus(gamewon, BONUS_SMILEY);
gcompris_play_ogg ("bonus", NULL);
timer_id = 0;
}
// Display a 'end of game' animation
static void finished() {
board_finished(BOARD_FINISHED_RANDOM);
timer_id = 0;
}
// One more level completed
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) { // all levels completed : the current board is finished
timer_id = g_timeout_add (2000, (GtkFunction) finished, NULL);
return;
}
}
crane_next_level();
}
// Event on item
static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
if(board_paused)
return FALSE;
if (event->type == GDK_MOTION_NOTIFY) // Mouse moved
return FALSE;
// Select item if left click on it
if (event->type == GDK_BUTTON_PRESS && event->button.button == 1)
select_item(item, TRUE);
return FALSE;
}
// Event on arrow
static gint arrow_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data) {
int success;
double x,y;
double dx1, dy1, dx2, dy2;
int direction;
int i;
int index, new_index;
if (board_paused)
return FALSE;
if (moving) // An object is already moving
return FALSE;
if (gamewon)
return FALSE;
if (event->type == GDK_MOTION_NOTIFY) // Mouse moved
return FALSE;
if (selected_item == NULL)
return FALSE;
// Left click on an arrow move the selected item
if (event->type == GDK_BUTTON_PRESS && event->button.button == 1) {
x = event->button.x;
y = event->button.y;
gnome_canvas_item_get_bounds(selected_item, &dx1, &dy1, &dx2, &dy2);
if (x < CRANE_BUTTON_RIGHT_X) {
direction = LEFT;
my_move.x = -1;
my_move.y = 0;
} else if (x < (CRANE_BUTTON_RIGHT_X + CRANE_BUTTON_HEIGHT)) {
direction = RIGHT;
my_move.x = 1;
my_move.y = 0;
} else if (y < CRANE_BUTTON_DOWN_Y) {
direction = UP;
my_move.x = 0;
my_move.y = -1;
} else if (y < (CRANE_BUTTON_DOWN_Y + CRANE_BUTTON_HEIGHT)) {
direction= DOWN;
my_move.x = 0;
my_move.y = 1;
} else {
printf("Clic location error : %g %g\n", x, y);
return FALSE;
}
// Check if the move doesn't go out of the frame
if (is_allowed_move(dx1, dy1, direction)) {
index = get_item_index(dx1, dy1);
new_index = index + my_move.x + (my_move.y * CRANE_FRAME_COLUMN);
// Check if no object is already here
if (list_game[new_index] == -1) {
// Do a smooth move
my_move.nb = 52;
timer_id = g_timeout_add(10, (GtkFunction) smooth_move, &my_move);
list_game[new_index] = list_game[index];
list_game[index] = -1;
}
}
}
// Check if the level is won
success = 1;
for (i = 0 ; i < CRANE_FRAME_LINE * CRANE_FRAME_COLUMN ; i++) {
if (list_answer[i] != list_game[i]) success = 0;
}
if (success) {
gamewon = TRUE;
timer_id = g_timeout_add (1200, (GtkFunction) bonus, NULL);
}
return FALSE;
}
// Draw the four arrows on the crane
static void draw_arrow() {
GnomeCanvasItem *item_arrow = NULL;
int i;
crane_object arrow[4];
arrow[0].pixmap = gcompris_load_pixmap("crane/arrow_b.png");
arrow[0].x = CRANE_BUTTON_DOWN_X; arrow[0].y = CRANE_BUTTON_DOWN_Y; arrow[0].w = CRANE_BUTTON_WIDTH; arrow[0].h = CRANE_BUTTON_HEIGHT;
arrow[1].pixmap = gcompris_load_pixmap("crane/arrow_u.png");
arrow[1].x = CRANE_BUTTON_UP_X; arrow[1].y = CRANE_BUTTON_UP_Y; arrow[1].w = CRANE_BUTTON_WIDTH; arrow[1].h = CRANE_BUTTON_HEIGHT;
arrow[2].pixmap = gcompris_load_pixmap("crane/arrow_l.png");
arrow[2].x = CRANE_BUTTON_LEFT_X; arrow[2].y = CRANE_BUTTON_LEFT_Y; arrow[2].w = CRANE_BUTTON_HEIGHT; arrow[2].h = CRANE_BUTTON_WIDTH;
arrow[3].pixmap = gcompris_load_pixmap("crane/arrow_r.png");
arrow[3].x = CRANE_BUTTON_RIGHT_X; arrow[3].y = CRANE_BUTTON_RIGHT_Y; arrow[3].w = CRANE_BUTTON_HEIGHT; arrow[3].h = CRANE_BUTTON_WIDTH;
for (i = 0 ; i < 4 ; i++) {
item_arrow = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type(),
"pixbuf", arrow[i].pixmap,
"x", arrow[i].x,
"y", arrow[i].y,
"width", arrow[i].w,
"height", arrow[i].h,
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_NW,
NULL);
gtk_signal_connect(GTK_OBJECT(item_arrow), "event", (GtkSignalFunc) arrow_event, NULL);
}
}
// Draw the red hands object which highlight the selected object
static void draw_redhands() {
GnomeCanvasItem *item_redhands = NULL;
GdkPixbuf *pixmap;
pixmap = gcompris_load_pixmap("crane/selected.png");
item_redhands = gnome_canvas_item_new (boardRootItem,
gnome_canvas_pixbuf_get_type(),
"pixbuf", pixmap,
"x", (double) 5,
"y", (double) 5,
"width", (double) (CRANE_FRAME_IMAGE_SIZE + 5),
"height", (double) (CRANE_FRAME_IMAGE_SIZE + 5),
"width_set", TRUE,
"height_set", TRUE,
"anchor", GTK_ANCHOR_NW,
NULL);
gnome_canvas_item_hide(item_redhands);
red_hands = item_redhands;
}
// Draw the drak frame (horizontal and vertical lines) that helps positionning elements
static void draw_frame(int x, int y) {
GnomeCanvasItem *item_frame = NULL;
int i;
GnomeCanvasPoints *track;
track = gnome_canvas_points_new(2);
for (i = 1 ; i < CRANE_FRAME_COLUMN ; i++) {
track->coords[0] = x + (i * CRANE_FRAME_CELL);
track->coords[1] = y + CRANE_FRAME_BORDER;
track->coords[2] = x + i * CRANE_FRAME_CELL;
track->coords[3] = y + (CRANE_FRAME_LINE * CRANE_FRAME_CELL) - CRANE_FRAME_BORDER;