1
/* gcompris - planegame.c
3
* Copyright (C) 2000 Bruno Coudoin
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 3 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, see <http://www.gnu.org/licenses/>.
19
#include "gcompris/gcompris.h"
21
#define SOUNDLISTFILE PACKAGE
23
static GList *item_list = NULL;
24
static GList *item2del_list = NULL;
26
static gboolean board_paused = TRUE;
27
static GcomprisBoard *gcomprisBoard = NULL;
29
static gint dummy_id = 0;
30
static gint drop_items_id = 0;
32
static GnomeCanvasItem *planeitem = NULL;
33
static gint plane_x, plane_y;
34
static gint planespeed_x, planespeed_y;
38
/* These are the index for managing the game rule */
39
static gint plane_target, plane_last_target;
43
GnomeCanvasItem *rootitem;
47
static void start_board (GcomprisBoard *agcomprisBoard);
48
static void pause_board (gboolean pause);
49
static void end_board (void);
50
static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
51
static void set_level (guint level);
52
static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str);
54
static GnomeCanvasItem *planegame_create_item(GnomeCanvasGroup *parent);
55
static gint planegame_drop_items (GtkWidget *widget, gpointer data);
56
static gint planegame_move_items (GtkWidget *widget, gpointer data);
57
static void planegame_destroy_item(CloudItem *clouditem);
58
static void planegame_destroy_items(void);
59
static void planegame_destroy_all_items(void);
60
static void setup_item(GnomeCanvasItem *item);
61
static void planegame_next_level(void);
63
static guint32 fallSpeed = 0;
64
static double speed = 0.0;
65
static double imageZoom = 0.0;
67
/* Description of this plugin */
68
static BoardPlugin menu_bp =
72
N_("Numbers in Order"),
73
N_("Move the plane to catch the clouds in the correct order"),
74
"Bruno Coudoin <bruno.coudoin@free.fr>",
93
* Main entry point mandatory for each Gcompris's game
94
* ---------------------------------------------------
98
GET_BPLUGIN_INFO(planegame)
101
* in : boolean TRUE = PAUSE : FALSE = CONTINUE
104
static void pause_board (gboolean pause)
106
if(gcomprisBoard==NULL)
112
gtk_timeout_remove (dummy_id);
116
gtk_timeout_remove (drop_items_id);
123
drop_items_id = gtk_timeout_add (1000,
124
(GtkFunction) planegame_drop_items, NULL);
127
dummy_id = gtk_timeout_add (1000, (GtkFunction) planegame_move_items, NULL);
130
board_paused = pause;
135
static void start_board (GcomprisBoard *agcomprisBoard)
138
if(agcomprisBoard!=NULL)
140
gcomprisBoard=agcomprisBoard;
142
/* disable im_context */
143
gcomprisBoard->disable_im_context = TRUE;
145
gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), "opt/scenery3_background.png");
148
/* set initial values for this level */
149
gcomprisBoard->level = 1;
150
gcomprisBoard->maxlevel = 2;
151
gc_bar_set(GC_BAR_LEVEL);
153
planegame_next_level();
165
if(gcomprisBoard!=NULL)
169
planegame_destroy_all_items();
170
gcomprisBoard->level = 1; // Restart this game to zero
172
gcomprisBoard = NULL;
176
set_level (guint level)
179
if(gcomprisBoard!=NULL)
181
gcomprisBoard->level=level;
182
planegame_next_level();
186
static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str)
189
if(board_paused || !gcomprisBoard)
192
/* Add some filter for control and shift key */
195
/* Avoid all this keys to be interpreted by this game */
216
if(planespeed_x < MAXSPEED)
220
if(planespeed_x > -MAXSPEED)
224
if(planespeed_y > -MAXSPEED)
228
if(planespeed_y < MAXSPEED)
236
is_our_board (GcomprisBoard *gcomprisBoard)
240
if(g_strcasecmp(gcomprisBoard->type, "planegame")==0)
242
/* Set the plugin entry */
243
gcomprisBoard->plugin=&menu_bp;
252
/*-------------------------------------------------------------------------------*/
253
/*-------------------------------------------------------------------------------*/
254
/*-------------------------------------------------------------------------------*/
255
/*-------------------------------------------------------------------------------*/
257
/* set initial values for the next level */
258
static void planegame_next_level()
260
GdkPixbuf *pixmap = NULL;
262
gc_bar_set_level(gcomprisBoard);
264
planegame_destroy_all_items();
266
/* Try the next level */
267
speed=100+(40/(gcomprisBoard->level));
268
fallSpeed=10000-gcomprisBoard->level*200;
269
/* Make the images tend to 0.5 ratio */
270
imageZoom=0.3+(0.5/(gcomprisBoard->level));
272
/* Setup and Display the plane */
275
pixmap = gc_pixmap_load("gcompris/misc/tuxhelico.png");
278
planeitem = gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
279
gnome_canvas_pixbuf_get_type (),
281
"x", (double) plane_x,
282
"y", (double) plane_y,
283
"width", (double) gdk_pixbuf_get_width(pixmap)*imageZoom,
284
"height", (double) gdk_pixbuf_get_height(pixmap)*imageZoom,
288
gdk_pixbuf_unref(pixmap);
292
plane_last_target = 10;
294
gcomprisBoard->number_of_sublevel=plane_last_target;
296
gcomprisBoard->sublevel=plane_target;
298
if(gcomprisBoard->level>1)
300
/* No scoring after level 1 */
305
gc_score_start(SCORESTYLE_NOTE,
306
gcomprisBoard->width - 220,
307
gcomprisBoard->height - 50,
308
gcomprisBoard->number_of_sublevel);
309
gc_score_set(gcomprisBoard->sublevel);
313
#define ISIN(x1, y1, px1, py1, px2, py2) (x1>px1 && x1<px2 && y1>py1 && y2<py2 ? TRUE : FALSE)
315
static void planegame_cloud_colision(CloudItem *clouditem)
317
double px1, px2, py1, py2;
318
double x1, x2, y1, y2;
319
GnomeCanvasItem *item;
324
item = clouditem->rootitem;
326
gnome_canvas_item_get_bounds(planeitem, &px1, &py1, &px2, &py2);
327
gnome_canvas_item_get_bounds(item, &x1, &y1, &x2, &y2);
330
ISIN(x1, y1, px1, py1, px2, py2) ||
331
ISIN(x2, y1, px1, py1, px2, py2) ||
332
ISIN(x1, y2, px1, py1, px2, py2) ||
333
ISIN(x2, y2, px1, py1, px2, py2)
336
if(plane_target == clouditem->number)
338
gc_sound_play_ogg ("sounds/gobble.wav", NULL);
339
item2del_list = g_list_append (item2del_list, clouditem);
342
if(gcomprisBoard->level==1)
344
gc_score_set(plane_target);
347
if(plane_target==plane_last_target)
349
/* Try the next level */
350
gcomprisBoard->level++;
351
if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
352
gc_bonus_end_display(GC_BOARD_FINISHED_RANDOM);
355
planegame_next_level();
356
gc_sound_play_ogg ("sounds/bonus.wav", NULL);
363
static void planegame_move_plane(GnomeCanvasItem *item)
365
if(plane_x>gcomprisBoard->width-150 && planespeed_x>0)
368
if(plane_x<0 && planespeed_x<0)
371
if(plane_y>gcomprisBoard->height-50 && planespeed_y>0)
374
if(plane_y<10 && planespeed_y<0)
377
gnome_canvas_item_move(item, (double)planespeed_x, (double)planespeed_y);
378
plane_x+=planespeed_x;
379
plane_y+=planespeed_y;
382
static void planegame_move_item(CloudItem *clouditem)
384
double x1, y1, x2, y2;
385
GnomeCanvasItem *item = clouditem->rootitem;
387
gnome_canvas_item_move(item, -2.0, 0.0);
389
gnome_canvas_item_get_bounds (item,
396
item2del_list = g_list_append (item2del_list, clouditem);
401
static void planegame_destroy_item(CloudItem *clouditem)
403
GnomeCanvasItem *item = clouditem->rootitem;
405
item_list = g_list_remove (item_list, clouditem);
406
item2del_list = g_list_remove (item2del_list, clouditem);
407
gtk_object_destroy (GTK_OBJECT(item));
412
/* Destroy items that falls out of the canvas */
413
static void planegame_destroy_items()
415
CloudItem *clouditem;
417
while(g_list_length(item2del_list)>0)
419
clouditem = g_list_nth_data(item2del_list, 0);
420
planegame_destroy_item(clouditem);
424
/* Destroy all the items */
425
static void planegame_destroy_all_items()
427
CloudItem *clouditem;
429
while(g_list_length(item_list)>0)
431
clouditem = g_list_nth_data(item_list, 0);
432
planegame_destroy_item(clouditem);
437
gtk_object_destroy (GTK_OBJECT(planeitem));
443
* This does the moves of the game items on the play canvas
446
static gint planegame_move_items (GtkWidget *widget, gpointer data)
448
g_list_foreach (item_list, (GFunc) planegame_move_item, NULL);
449
g_list_foreach (item_list, (GFunc) planegame_cloud_colision, NULL);
451
/* Destroy items that falls out of the canvas */
452
planegame_destroy_items();
455
planegame_move_plane(planeitem);
456
dummy_id = gtk_timeout_add (speed,
457
(GtkFunction) planegame_move_items, NULL);
462
static GnomeCanvasItem *planegame_create_item(GnomeCanvasGroup *parent)
464
GdkPixbuf *pixmap = NULL;
465
GnomeCanvasItem *itemgroup;
468
CloudItem *clouditem;
470
/* Random cloud number */
471
if(g_random_int()%2==0)
478
min = MAX(1, plane_target - 1);
479
i = min + g_random_int()%(plane_target - min + 3);
481
number = g_strdup_printf("%d", i);
483
pixmap = gc_pixmap_load("gcompris/misc/cloud.png");
486
gnome_canvas_item_new (parent,
487
gnome_canvas_group_get_type (),
488
"x", (double) gcomprisBoard->width,
489
"y", (double)(g_random_int()%(gcomprisBoard->height-
490
(guint)(gdk_pixbuf_get_height(pixmap)*
495
gnome_canvas_item_new (GNOME_CANVAS_GROUP(itemgroup),
496
gnome_canvas_pixbuf_get_type (),
498
"x", (double) -gdk_pixbuf_get_width(pixmap)*imageZoom/2,
499
"y", (double) -gdk_pixbuf_get_height(pixmap)*imageZoom/2,
500
"width", (double) gdk_pixbuf_get_width(pixmap)*imageZoom,
501
"height", (double) gdk_pixbuf_get_height(pixmap)*imageZoom,
505
gdk_pixbuf_unref(pixmap);
508
gnome_canvas_item_new (GNOME_CANVAS_GROUP(itemgroup),
509
gnome_canvas_text_get_type (),
511
"font", gc_skin_font_board_big,
517
/* The plane is always on top */
518
gnome_canvas_item_raise_to_top(planeitem);
520
clouditem = g_malloc(sizeof(CloudItem));
521
clouditem->rootitem = itemgroup;
522
clouditem->number = i;
524
item_list = g_list_append (item_list, clouditem);
531
static void planegame_add_new_item()
533
setup_item (planegame_create_item(gnome_canvas_root(gcomprisBoard->canvas)));
537
* This is called on a low frequency and is used to drop new items
540
static gint planegame_drop_items (GtkWidget *widget, gpointer data)
542
planegame_add_new_item();
544
drop_items_id = gtk_timeout_add (fallSpeed,
545
(GtkFunction) planegame_drop_items, NULL);
550
item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
556
double item_x, item_y;
561
item_x = event->button.x;
562
item_y = event->button.y;
563
gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
567
case GDK_BUTTON_PRESS:
568
switch(event->button.button)
571
if (event->button.state & GDK_SHIFT_MASK)
576
fleur = gdk_cursor_new(GDK_FLEUR);
577
gc_canvas_item_grab(item,
578
GDK_POINTER_MOTION_MASK |
579
GDK_BUTTON_RELEASE_MASK,
582
gdk_cursor_destroy(fleur);
592
case GDK_MOTION_NOTIFY:
593
if (dragging && (event->motion.state & GDK_BUTTON1_MASK))
598
gnome_canvas_item_move(item, new_x - x, new_y - y);
604
case GDK_BUTTON_RELEASE:
607
gc_canvas_item_ungrab(item, event->button.time);
620
setup_item(GnomeCanvasItem *item)
622
gtk_signal_connect(GTK_OBJECT(item), "event",
623
(GtkSignalFunc) item_event,