1
/* gcompris - paratrooper.c
3
* Copyright (C) 2000, 2008 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
25
static GcomprisBoard *gcomprisBoard = NULL;
27
static gint drop_tux_id = 0;
29
static GooCanvasItem *boardRootItem = NULL;
30
static gint boat_x, boat_y, boat_landarea_y, boat_width;
32
static gint plane_x, plane_y;
33
static gint planespeed_x;
34
static gdouble windspeed;
36
static GooCanvasItem *planeitem;
41
TUX_DROPPING = 1 << 1,
52
gboolean speed_override;
53
GooCanvasItem *rootitem;
54
GooCanvasItem *paratrooper;
55
GooCanvasItem *instruct;
58
static ParatrooperItem paratrooperItem;
61
static void start_board (GcomprisBoard *agcomprisBoard);
62
static void pause_board (gboolean pause);
63
static void end_board (void);
64
static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
65
static void set_level (guint level);
66
static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str);
68
static void paratrooper_create_cloud(GooCanvasItem *parent);
69
static gint paratrooper_drop_clouds (GtkWidget *widget, gpointer data);
70
static gint paratrooper_move_tux (GtkWidget *widget, gpointer data);
71
static void paratrooper_destroy_all_items(void);
72
static void paratrooper_next_level(void);
73
static gboolean item_event (GooCanvasItem *item,
74
GooCanvasItem *target,
75
GdkEventButton *event,
77
static void next_state(void);
80
static double speed = 0.0;
81
static double imageZoom = 0.0;
83
/* Description of this plugin */
84
static BoardPlugin menu_bp =
89
"Direct the parachutist to help him or her land safely",
90
"Bruno Coudoin <bruno.coudoin@free.fr>",
109
* Main entry point mandatory for each Gcompris's game
110
* ---------------------------------------------------
114
GET_BPLUGIN_INFO(paratrooper)
117
* in : boolean TRUE = PAUSE : FALSE = CONTINUE
120
static void pause_board (gboolean pause)
122
if(gcomprisBoard==NULL)
128
gtk_timeout_remove (drop_tux_id);
134
if(gamewon == TRUE) /* the game is won */
136
gcomprisBoard->level++;
137
if(gcomprisBoard->level>gcomprisBoard->maxlevel)
138
gcomprisBoard->level = gcomprisBoard->maxlevel;
142
if(paratrooperItem.status!=TUX_INPLANE && paratrooperItem.status!=TUX_LANDED) {
143
drop_tux_id = gtk_timeout_add (1000, (GtkFunction) paratrooper_move_tux, NULL);
146
if(gamewon == TRUE) /* the game is won */
147
paratrooper_next_level();
153
static void start_board (GcomprisBoard *agcomprisBoard)
156
if(agcomprisBoard!=NULL)
158
gcomprisBoard=agcomprisBoard;
160
/* disable im_context */
161
gcomprisBoard->disable_im_context = TRUE;
163
gc_set_background(goo_canvas_get_root_item(gcomprisBoard->canvas),
164
"paratrooper/scenery3_background.png");
167
/* set initial values for this level */
168
gcomprisBoard->level = 1;
169
gcomprisBoard->maxlevel = 6;
170
gc_bar_set(GC_BAR_LEVEL);
171
gc_bar_location(BOARDWIDTH-200, -1, 0.9);
173
/* Init of paratrooper struct */
174
paratrooperItem.rootitem = NULL;
176
paratrooper_next_level();
188
if(gcomprisBoard!=NULL)
191
paratrooper_destroy_all_items();
192
gcomprisBoard->level = 1; // Restart this game to zero
194
gcomprisBoard = NULL;
198
set_level (guint level)
201
if(gcomprisBoard!=NULL)
203
gcomprisBoard->level=level;
204
paratrooper_next_level();
208
static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str)
215
/* Add some filter for control and shift key */
218
/* Avoid all this keys to be interpreted by this game */
244
paratrooperItem.speed_override = 1;
245
if(paratrooperItem.status == TUX_FLYING && paratrooperItem.speed >= 3)
246
paratrooperItem.speed--;
249
paratrooperItem.speed_override = 1;
250
if(paratrooperItem.status == TUX_FLYING && paratrooperItem.speed <= 6)
251
paratrooperItem.speed++;
261
is_our_board (GcomprisBoard *gcomprisBoard)
265
if(g_strcasecmp(gcomprisBoard->type, "paratrooper")==0)
267
/* Set the plugin entry */
268
gcomprisBoard->plugin=&menu_bp;
276
/*-------------------------------------------------------------------------------*/
277
/*-------------------------------------------------------------------------------*/
278
/*-------------------------------------------------------------------------------*/
279
/*-------------------------------------------------------------------------------*/
281
/* set initial values for the next level */
282
static void paratrooper_next_level()
284
RsvgHandle *svg_handle;
285
RsvgDimensionData rsvg_dimension;
287
GooCanvasItem *planeroot;
288
GooCanvasBounds bounds;
292
gc_bar_set_level(gcomprisBoard);
294
paratrooper_destroy_all_items();
297
goo_canvas_group_new (goo_canvas_get_root_item(gcomprisBoard->canvas),
300
/* Try the next level */
301
speed=10+(30/(gcomprisBoard->level));
302
gcomprisBoard->number_of_sublevel=0;
303
/* Make the images tend to 0.5 ratio */
304
imageZoom=0.4+(0.2 * (2 - (gcomprisBoard->level-1) % 3));
306
/* Setup and Display the plane */
307
svg_handle = gc_rsvg_load("paratrooper/tuxplane.svgz");
308
rsvg_handle_get_dimensions (svg_handle, &rsvg_dimension);
311
goo_canvas_group_new (boardRootItem,
313
planespeed_x = 4 + gcomprisBoard->level;
315
plane_x = -rsvg_dimension.width;
317
planeitem = goo_canvas_svg_new (planeroot,
321
goo_canvas_item_set_simple_transform(planeitem,
326
goo_canvas_item_animate(planeroot,
327
BOARDWIDTH + rsvg_dimension.width,
334
GOO_CANVAS_ANIMATE_RESTART);
336
g_signal_connect(planeitem, "button-press-event",
337
(GtkSignalFunc) item_event,
339
gc_item_focus_init(planeitem, NULL);
340
g_object_unref(svg_handle);
342
windspeed = (3 + rand() % (100 * gcomprisBoard->level) / 100);
345
if (gcomprisBoard->level >= 4)
349
gtk_timeout_add (200,
350
(GtkFunction) paratrooper_drop_clouds, NULL);
352
/* Display the target */
353
svg_handle = gc_rsvg_load("paratrooper/fishingboat.svgz");
354
rsvg_handle_get_dimensions (svg_handle, &rsvg_dimension);
355
boat_x = (BOARDWIDTH - rsvg_dimension.width) / 2;
356
boat_y = BOARDHEIGHT - 100;
357
boat_landarea_y = boat_y + 20;
359
goo_canvas_svg_new (boardRootItem,
362
goo_canvas_item_translate(item,
363
-rsvg_dimension.width/2,
366
goo_canvas_item_get_bounds(item, &bounds);
367
boat_width = bounds.x2 - bounds.x1;
369
goo_canvas_item_animate(item,
377
GOO_CANVAS_ANIMATE_FREEZE);
379
g_object_unref(svg_handle);
381
/* Prepare the parachute */
383
gtk_timeout_remove (drop_tux_id);
387
paratrooperItem.status = TUX_INPLANE;
388
paratrooperItem.speed = 3;
390
paratrooperItem.rootitem = \
391
goo_canvas_group_new (boardRootItem,
394
paratrooperItem.paratrooper = \
395
goo_canvas_svg_new (paratrooperItem.rootitem,
399
g_object_set (paratrooperItem.paratrooper, "visibility",
400
GOO_CANVAS_ITEM_INVISIBLE, NULL);
402
g_signal_connect(paratrooperItem.paratrooper, "button-press-event",
403
(GtkSignalFunc) item_event,
406
paratrooperItem.instruct = \
407
goo_canvas_text_new (boardRootItem,
408
_("Control fall speed with up and down arrow keys."),
409
(double) BOARDWIDTH / 2.0,
413
"font", gc_skin_font_board_medium,
414
"fill_color_rgba", gc_skin_color_title,
416
g_object_set (paratrooperItem.instruct, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
420
/* Destroy all the items */
421
static void paratrooper_destroy_all_items()
424
goo_canvas_item_remove(boardRootItem);
425
boardRootItem = NULL;
429
* This does the moves of the game's paratropper
433
paratrooper_move_tux (GtkWidget *widget, gpointer data)
436
GooCanvasBounds bounds;
439
goo_canvas_item_get_bounds(paratrooperItem.paratrooper, &bounds);
441
center = bounds.x1 + (bounds.x2 - bounds.x1) / 2;
443
/* Manage the wrapping */
445
goo_canvas_item_translate(paratrooperItem.rootitem,
449
if(center > BOARDWIDTH) {
450
goo_canvas_item_translate(paratrooperItem.rootitem,
455
offset = (windspeed / 2 + 15 * paratrooperItem.drift) / 16;
456
paratrooperItem.drift = offset;
458
if (paratrooperItem.status == TUX_DROPPING && gcomprisBoard->level >= 4)
459
paratrooperItem.speed *= 1.05;
461
if (paratrooperItem.status == TUX_FLYING && paratrooperItem.speed > 3 &&
462
!paratrooperItem.speed_override)
463
paratrooperItem.speed /= 1.2;
465
goo_canvas_item_translate(paratrooperItem.rootitem,
466
offset, paratrooperItem.speed);
468
/* Check we reached the target */
469
if(bounds.y2 > boat_landarea_y)
471
if( center > boat_x &&
472
center < boat_x + boat_width &&
473
paratrooperItem.status == TUX_FLYING)
475
paratrooperItem.status = TUX_LANDED;
480
if(bounds.y2 < BOARDHEIGHT - 20)
481
drop_tux_id = gtk_timeout_add (150,
482
(GtkFunction) paratrooper_move_tux,
486
paratrooperItem.status = TUX_CRASHED;
493
drop_tux_id = gtk_timeout_add (150,
494
(GtkFunction) paratrooper_move_tux, NULL);
501
paratrooper_create_cloud(GooCanvasItem *parent)
503
RsvgHandle *svg_handle = NULL;
508
RsvgDimensionData rsvg_dimension;
510
svg_handle = gc_rsvg_load("paratrooper/cloud.svgz");
511
rsvg_handle_get_dimensions (svg_handle, &rsvg_dimension);
520
x = BOARDWIDTH - rsvg_dimension.width * imageZoom;
527
goo_canvas_group_new (parent,
530
item = goo_canvas_svg_new (root,
534
goo_canvas_item_scale(item,
535
imageZoom, imageZoom);
537
goo_canvas_item_translate(root, x, y);
539
goo_canvas_item_animate(root,
545
BOARDWIDTH * (80 / ABS(windspeed)),
547
GOO_CANVAS_ANIMATE_RESTART);
548
g_object_unref(svg_handle);
550
/* The plane is always on top */
551
goo_canvas_item_raise(planeitem, NULL);
555
* This is called on a low frequency and is used to drop new items
558
static gint paratrooper_drop_clouds (GtkWidget *widget, gpointer data)
560
paratrooper_create_cloud(boardRootItem);
568
* This is the state machine of the paratrooper
572
GooCanvasBounds bounds;
574
switch(paratrooperItem.status)
578
RsvgHandle *svg_handle;
580
gc_sound_play_ogg ("sounds/tuxok.wav", NULL);
582
svg_handle = gc_rsvg_load("paratrooper/minitux.svgz");
583
g_object_set (paratrooperItem.paratrooper,
584
"svg-handle", svg_handle,
586
g_object_unref(svg_handle);
587
gc_item_focus_init(paratrooperItem.paratrooper, NULL);
589
goo_canvas_item_get_bounds(planeitem, &bounds);
591
g_object_set (paratrooperItem.paratrooper, "visibility",
592
GOO_CANVAS_ITEM_VISIBLE, NULL);
593
paratrooperItem.status = TUX_DROPPING;
594
paratrooperItem.drift = planespeed_x;
596
goo_canvas_item_translate(paratrooperItem.rootitem,
597
(bounds.x1 > 0 ? bounds.x1 : 0),
600
gtk_timeout_add (10, (GtkFunction) paratrooper_move_tux, NULL);
602
gc_item_focus_remove(planeitem, NULL);
608
RsvgHandle *svg_handle;
610
gc_sound_play_ogg ("sounds/eraser2.wav", NULL);
612
svg_handle = gc_rsvg_load("paratrooper/parachute.svgz");
614
g_object_set (paratrooperItem.paratrooper,
615
"svg-handle", svg_handle,
618
gc_item_focus_remove(paratrooperItem.paratrooper, NULL);
619
g_object_unref(svg_handle);
621
paratrooperItem.status = TUX_FLYING;
622
paratrooperItem.speed_override = 0;
623
if (gcomprisBoard->level >= 2) {
624
goo_canvas_item_raise (paratrooperItem.instruct, NULL);
625
g_object_set (paratrooperItem.instruct, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
631
gc_sound_play_ogg ("sounds/tuxok.wav", NULL);
632
g_object_set (paratrooperItem.instruct, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
634
gc_bonus_display(gamewon, GC_BONUS_TUX);
639
gc_sound_play_ogg ("sounds/bubble.wav", NULL);
640
g_object_set (paratrooperItem.instruct, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
641
goo_canvas_item_set_transform(paratrooperItem.rootitem, NULL);
642
paratrooperItem.status = TUX_INPLANE;
643
paratrooperItem.speed = 3;
644
g_object_set (paratrooperItem.paratrooper, "visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
645
g_object_set (planeitem, "visibility", GOO_CANVAS_ITEM_VISIBLE, NULL);
646
gc_item_focus_init(planeitem, NULL);
655
item_event (GooCanvasItem *item,
656
GooCanvasItem *target,
657
GdkEventButton *event,