3
* Copyright (C) 2001 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 GcomprisBoard *gcomprisBoard = NULL;
24
static gboolean board_paused = TRUE;
26
static void start_board (GcomprisBoard *agcomprisBoard);
27
static void pause_board (gboolean pause);
28
static void end_board (void);
29
static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
30
static void set_level (guint level);
32
static void game_won(void);
34
#define VERTICAL_SEPARATION 30
35
#define HORIZONTAL_SEPARATION 30
36
#define TEXT_COLOR "white"
38
static GnomeCanvasGroup *boardRootItem = NULL;
39
static GnomeCanvasGroup *speedRootItem = NULL;
41
static double wind_speed;
44
static GnomeCanvasItem *answer_item = NULL;
45
static gchar answer_string[10];
46
static guint answer_string_index = 0;
48
static GnomeCanvasItem *animate_item = NULL;
49
static gint animate_id = 0;
50
static gint animate_item_distance = 0;
51
static gint animate_item_size = 0;
52
static double animate_item_x = 0;
53
static double animate_item_y = 0;
54
#define MAX_DART_SIZE 20
55
#define MIN_DART_SIZE 3
57
static guint user_points = 0;
60
* Functions Definition
62
static void process_ok(void);
63
static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str);
64
static GnomeCanvasItem *target_create_item(GnomeCanvasGroup *parent);
65
static void target_destroy_all_items(void);
66
static void target_next_level(void);
67
static gint item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data);
68
static void animate_items(void);
69
static void launch_dart(double item_x, double item_y);
72
* distance to target, min wind speed, max wind speed, target1 width(center),
73
* value1 (for target1), ... to target10, value10
75
* a target width of 0 means no such target
77
#define MAX_NUMBER_OF_TARGET 10
80
guint number_of_arrow;
81
guint target_distance;
82
guint target_min_wind_speed;
83
guint target_max_wind_speed;
84
gint target_width_value[MAX_NUMBER_OF_TARGET*2];
89
* Definition of targets one line by level based on TargetDefinition
91
static TargetDefinition targetDefinition[] =
93
{ 3, 100, 2, 5, { 40, 5 , 80, 3, 150, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
94
{ 5, 150, 2, 7, { 30, 10, 50, 5, 150, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
95
{ 7, 200, 4, 9, { 20, 10, 40, 5, 60, 3, 150, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
96
{ 7, 200, 5, 10, { 15, 100, 35, 50, 55, 10, 75, 5, 150, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }
98
#define NUMBER_OF_TARGET 4
100
#define TARGET_CENTER_X 235
101
#define TARGET_CENTER_Y 260
103
#define SPEED_CENTER_X 660
104
#define SPEED_CENTER_Y 125
106
static guint target_colors[] = {
107
0xAA0000FF, 0x00AA00FF, 0x0000AAFF, 0xAAAA00FF, 0x00AAAAFF, 0xAA00AAFF, 0xAA0000FF, 0x00AA00FF, 0x0000AAFF, 0xAA0000FF
110
static guint number_of_arrow = 0;
112
/* Description of this plugin */
113
static BoardPlugin menu_bp =
117
"Practice addition with a target game",
118
"Hit the target and count your points",
119
"Bruno Coudoin <bruno.coudoin@free.fr>",
138
* Main entry point mandatory for each Gcompris's game
139
* ---------------------------------------------------
143
GET_BPLUGIN_INFO(target)
146
* in : boolean TRUE = PAUSE : FALSE = CONTINUE
149
static void pause_board (gboolean pause)
151
if(gcomprisBoard==NULL)
154
if(gamewon == TRUE && pause == FALSE) /* the game is won */
162
gtk_timeout_remove (animate_id);
169
animate_id = gtk_timeout_add (200, (GtkFunction) animate_items, NULL);
173
board_paused = pause;
178
static void start_board (GcomprisBoard *agcomprisBoard)
181
if(agcomprisBoard!=NULL)
183
gcomprisBoard=agcomprisBoard;
185
/* disable im_context */
186
gcomprisBoard->disable_im_context = TRUE;
188
gcomprisBoard->level=1;
189
gcomprisBoard->maxlevel=NUMBER_OF_TARGET;
190
gcomprisBoard->sublevel=1;
191
gcomprisBoard->number_of_sublevel=1; /* Go to next level after this number of 'play' */
193
gc_set_background(gnome_canvas_root(gcomprisBoard->canvas), "opt/target_background.jpg");
201
/* ======================================= */
202
static void end_board ()
204
if(gcomprisBoard!=NULL)
207
target_destroy_all_items();
209
gcomprisBoard = NULL;
212
/* ======================================= */
213
static void set_level (guint level)
216
if(gcomprisBoard!=NULL)
218
gcomprisBoard->level=level;
219
gcomprisBoard->sublevel=1;
225
/* ======================================= */
226
static gint key_press(guint keyval, gchar *commit_str, gchar *preedit_str)
230
if(board_paused || !gcomprisBoard)
233
/* Add some filter for control and shift key */
236
/* Avoid all this keys to be interpreted by this game */
261
if(answer_string_index>0)
263
answer_string_index--;
264
answer_string[answer_string_index] = 0;
271
/* Limit the user entry to 5 digits */
272
if(c>='0' && c<='9' && answer_string_index<5)
274
answer_string[answer_string_index++] = c;
275
answer_string[answer_string_index] = 0;
280
gchar *tmpstr = g_strdup_printf(_("Points = %s"), answer_string);
281
gnome_canvas_item_set(answer_item,
291
/* ======================================= */
292
static gboolean is_our_board (GcomprisBoard *gcomprisBoard)
296
if(g_strcasecmp(gcomprisBoard->type, "target")==0)
298
/* Set the plugin entry */
299
gcomprisBoard->plugin=&menu_bp;
307
/*-------------------------------------------------------------------------------*/
308
/*-------------------------------------------------------------------------------*/
309
/* set initial values for the next level */
310
static void target_next_level()
313
gc_bar_set(GC_BAR_LEVEL);
314
gc_bar_set_level(gcomprisBoard);
316
target_destroy_all_items();
319
/* Try the next level */
320
target_create_item(gnome_canvas_root(gcomprisBoard->canvas));
322
/* ==================================== */
323
/* Destroy all the items */
324
static void target_destroy_all_items()
326
if(boardRootItem!=NULL)
327
gtk_object_destroy (GTK_OBJECT(boardRootItem));
329
boardRootItem = NULL;
331
if(speedRootItem!=NULL)
332
gtk_object_destroy (GTK_OBJECT(speedRootItem));
336
answer_string_index = 0;
339
speedRootItem = NULL;
343
* Display a random wind speed
345
static void display_windspeed()
348
guint needle_zoom = 15;
350
GnomeCanvasPoints *canvasPoints;
351
canvasPoints = gnome_canvas_points_new (2);
353
if(speedRootItem!=NULL)
354
gtk_object_destroy (GTK_OBJECT(speedRootItem));
356
speedRootItem = GNOME_CANVAS_GROUP(
357
gnome_canvas_item_new (gnome_canvas_root(gcomprisBoard->canvas),
358
gnome_canvas_group_get_type (),
363
/* Speed orientation */
364
second = g_random_int()%60;
365
ang = second * M_PI / 30;
368
wind_speed = targetDefinition[gcomprisBoard->level-1].target_min_wind_speed \
369
+ g_random_int()%(targetDefinition[gcomprisBoard->level-1].target_max_wind_speed \
370
- targetDefinition[gcomprisBoard->level-1].target_min_wind_speed);
372
canvasPoints->coords[0]=SPEED_CENTER_X;
373
canvasPoints->coords[1]=SPEED_CENTER_Y;
374
canvasPoints->coords[2]=SPEED_CENTER_X + wind_speed * sin(ang) * needle_zoom;
375
canvasPoints->coords[3]=SPEED_CENTER_Y - wind_speed * cos(ang) * needle_zoom;
376
gnome_canvas_item_new (speedRootItem,
377
gnome_canvas_line_get_type (),
378
"points", canvasPoints,
380
"width_units", (double)1,
381
"width_pixels", (guint) 4,
382
"last_arrowhead", TRUE,
383
"arrow_shape_a", (double) wind_speed,
384
"arrow_shape_b", (double) wind_speed-15,
385
"arrow_shape_c", (double) 5.0,
388
gnome_canvas_points_free(canvasPoints);
390
/* Draw the center of the speedometer */
391
gnome_canvas_item_new (speedRootItem,
392
gnome_canvas_ellipse_get_type(),
393
"x1", (double)SPEED_CENTER_X-5,
394
"y1", (double)SPEED_CENTER_Y-5,
395
"x2", (double)SPEED_CENTER_X+5,
396
"y2", (double)SPEED_CENTER_Y+5,
398
"outline_color", "red",
399
"width_units", (double)1,
402
tmpstr = g_strdup_printf(_("Wind speed = %d\nkilometers/hour"), (guint)wind_speed);
403
gnome_canvas_item_new (speedRootItem,
404
gnome_canvas_text_get_type (),
406
"font", gc_skin_font_board_medium,
407
"x", (double) SPEED_CENTER_X,
408
"y", (double) SPEED_CENTER_Y + 110,
409
"anchor", GTK_ANCHOR_CENTER,
410
"fill_color", "white",
418
/* ==================================== */
419
static GnomeCanvasItem *target_create_item(GnomeCanvasGroup *parent)
423
GnomeCanvasItem *item = NULL;
425
boardRootItem = GNOME_CANVAS_GROUP(
426
gnome_canvas_item_new (parent,
427
gnome_canvas_group_get_type (),
428
"x", (double) TARGET_CENTER_X,
429
"y", (double) TARGET_CENTER_Y,
431
for(i=0; i<MAX_NUMBER_OF_TARGET; i++)
433
if(targetDefinition[gcomprisBoard->level-1].target_width_value[i*2]>0)
435
item = gnome_canvas_item_new (boardRootItem,
436
gnome_canvas_ellipse_get_type(),
437
"x1", (double)-targetDefinition[gcomprisBoard->level-1].target_width_value[i*2],
438
"y1", (double)-targetDefinition[gcomprisBoard->level-1].target_width_value[i*2],
439
"x2", (double)targetDefinition[gcomprisBoard->level-1].target_width_value[i*2],
440
"y2", (double)targetDefinition[gcomprisBoard->level-1].target_width_value[i*2],
441
"fill_color_rgba", target_colors[i],
442
"outline_color", "black",
443
"width_units", (double)1,
446
gnome_canvas_item_lower_to_bottom(item);
447
gtk_signal_connect(GTK_OBJECT(item), "event", (GtkSignalFunc) item_event, NULL);
449
/* Display the value for this target */
450
tmpstr = g_strdup_printf("%d",
451
targetDefinition[gcomprisBoard->level-1].target_width_value[i*2+1]);
452
item = gnome_canvas_item_new (boardRootItem,
453
gnome_canvas_text_get_type (),
455
"font", gc_skin_font_board_medium,
457
"y", (double) targetDefinition[gcomprisBoard->level-1].target_width_value[i*2] - 10,
458
"anchor", GTK_ANCHOR_CENTER,
459
"fill_color", "white",
463
gtk_signal_connect(GTK_OBJECT(item), "event", (GtkSignalFunc) item_event, NULL);
467
number_of_arrow = targetDefinition[gcomprisBoard->level-1].number_of_arrow;
469
tmpstr = g_strdup_printf(_("Distance to target = %d meters"),
470
targetDefinition[gcomprisBoard->level-1].target_distance);
471
gnome_canvas_item_new (boardRootItem,
472
gnome_canvas_text_get_type (),
474
"font", gc_skin_font_board_medium,
476
"y", (double) BOARDHEIGHT-TARGET_CENTER_Y -45,
477
"anchor", GTK_ANCHOR_CENTER,
478
"fill_color", "black",
486
/* ==================================== */
487
static void game_won()
489
gcomprisBoard->sublevel++;
491
if(gcomprisBoard->sublevel>gcomprisBoard->number_of_sublevel) {
492
/* Try the next level */
493
gcomprisBoard->sublevel=1;
494
gcomprisBoard->level++;
495
if(gcomprisBoard->level>gcomprisBoard->maxlevel) { // the current board is finished : bail out
496
gc_bonus_end_display(GC_BOARD_FINISHED_RANDOM);
499
gc_sound_play_ogg ("sounds/bonus.wav", NULL);
504
static void process_ok()
506
guint answer_points = atoi(answer_string);
510
if(answer_points == user_points)
513
target_destroy_all_items();
514
gc_bonus_display(gamewon, GC_BONUS_SMILEY);
519
gc_bonus_display(gamewon, GC_BONUS_SMILEY);
529
static void request_score()
531
GdkPixbuf *button_pixmap = NULL;
532
double y_offset = 160;
533
double x_offset = 245;
536
gc_bar_set(GC_BAR_LEVEL|GC_BAR_OK);
537
button_pixmap = gc_skin_pixmap_load("button_large2.png");
538
gnome_canvas_item_new (boardRootItem,
539
gnome_canvas_pixbuf_get_type (),
540
"pixbuf", button_pixmap,
545
tmpstr = g_strdup_printf(_("Points = %s"), "");
546
answer_item = gnome_canvas_item_new (boardRootItem,
547
gnome_canvas_text_get_type (),
549
"font", gc_skin_font_board_title_bold,
550
"x", (double) x_offset + gdk_pixbuf_get_width(button_pixmap)/2,
551
"y", (double) y_offset + gdk_pixbuf_get_height(button_pixmap)/2,
552
"anchor", GTK_ANCHOR_CENTER,
553
"fill_color", "black",
557
gdk_pixbuf_unref(button_pixmap);
560
static void add_points(double x, double y)
565
// Calculate the distance
566
diametre = sqrt(x*x+y*y);
568
for(i=0; i<MAX_NUMBER_OF_TARGET; i++)
570
if(diametre < targetDefinition[gcomprisBoard->level-1].target_width_value[i*2])
572
user_points += targetDefinition[gcomprisBoard->level-1].target_width_value[i*2+1];
584
static void animate_items()
592
// Apply the wind move
593
animate_item_x = animate_item_x + wind_speed * sin(ang);
594
animate_item_y = animate_item_y - wind_speed * cos(ang);
596
gnome_canvas_item_set (animate_item,
597
"x1", (double)animate_item_x - animate_item_size,
598
"y1", (double)animate_item_y - animate_item_size,
599
"x2", (double)animate_item_x + animate_item_size,
600
"y2", (double)animate_item_y + animate_item_size,
603
if(animate_item_size>MIN_DART_SIZE)
606
if(--animate_item_distance == 0)
608
gc_sound_play_ogg ("sounds/brick.wav", NULL);
610
gtk_timeout_remove (animate_id);
614
// Calc the point for this dart
615
add_points(animate_item_x, animate_item_y);
617
// Change the wind for the next target
625
static void launch_dart(double item_x, double item_y)
628
animate_item_x = item_x;
629
animate_item_y = item_y;
630
animate_item_size = MAX_DART_SIZE;
631
animate_item_distance = targetDefinition[gcomprisBoard->level-1].target_distance/10;
633
gc_sound_play_ogg ("sounds/line_end.wav", NULL);
635
animate_item = gnome_canvas_item_new (boardRootItem,
636
gnome_canvas_ellipse_get_type(),
637
"x1", (double)item_x-MAX_DART_SIZE,
638
"y1", (double)item_y-MAX_DART_SIZE,
639
"x2", (double)item_x+MAX_DART_SIZE,
640
"y2", (double)item_y+MAX_DART_SIZE,
641
"fill_color_rgba", 0xFF80FFFF,
642
"outline_color", "white",
643
"width_units", (double)1,
646
animate_id = gtk_timeout_add (200, (GtkFunction) animate_items, NULL);
648
if(--number_of_arrow == 0)
655
/* ==================================== */
657
item_event(GnomeCanvasItem *item, GdkEvent *event, gpointer data)
659
double item_x, item_y;
664
/* Is there already a dart on air */
665
if(number_of_arrow == 0 || animate_item)
670
case GDK_BUTTON_PRESS:
671
switch(event->button.button)
676
item_x = event->button.x;
677
item_y = event->button.y;
678
gnome_canvas_item_w2i(item->parent, &item_x, &item_y);
680
launch_dart(item_x, item_y);