/* * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include "load.h" #include "free.h" #include "alloc.h" #include "draw.h" #include "throw.h" #include "game.h" #include "position.h" #include "select.h" #include "set.h" #include "get.h" #include "callback.h" #include "find.h" #include "clear.h" #include "list.h" #include "def.h" #include "config.h" gboolean event_blink(gpointer data) { struct _prog *prog_data = (struct _prog*) data; struct _card *tmp; GList *lst; struct _card *card = NULL; for(lst = prog_data->waiting; lst; lst = lst->next) { tmp = lst->data; if(tmp->blink == TRUE) { tmp->draw = !tmp->draw; card = tmp; } } if(card && prog_data->copy) { GdkGC *gc = prog_data->area->style->fg_gc[GTK_WIDGET_STATE(prog_data->area)]; if(card->draw == TRUE) { gdk_gc_set_clip_mask(gc, prog_data->cardmask); gdk_gc_set_clip_origin(gc, card->dim.x, card->dim.y); gdk_draw_drawable( prog_data->target, gc, card->img, 0, 0, card->dim.x, card->dim.y, card->dim.w, card->dim.h); gdk_gc_set_clip_mask(gc, NULL); } else gdk_draw_drawable(prog_data->target, gc, prog_data->copy, card->dim.x, card->dim.y, card->dim.x, card->dim.y, card->dim.w, card->dim.h); gdk_draw_drawable( prog_data->area->window, gc, prog_data->target, card->dim.x, card->dim.y, card->dim.x, card->dim.y, card->dim.w, card->dim.h); } return(TRUE); } gboolean key_down(GtkWidget *widget, GdkEventKey *event, gpointer user_data) { struct _prog *prog_data = user_data; if(event->type == GDK_KEY_PRESS && event->keyval == GDK_Escape) { if(prog_data->movecard) { if(prog_data->copy) g_object_unref(prog_data->copy); prog_data->copy = NULL; prog_data->movecard->card->draw = TRUE; g_free(prog_data->movecard); prog_data->movecard = NULL; draw_container(prog_data); } } } /* click_givecard : takes care of distributing * the first batch of cards to the players * (5 cards each) and show one more card. This * final card will be proposed to each player * one at a time. If anyone decide to take it, * then the family of this card will become the * master family of the round (trump). * * struct _prog *prog_data: see file def.h * * What is needed in struct _prog : * * prog_data->state : the status of the game * right now. Are we playing yet ? * This is an enum egstate (see file def.h * for more details about it) * * prog_data->allwidgets[4] : allwidgets is * an array composed by many GtkWidget* each. * The Fifth ([4]) is a spinbutton; which will * be suppressed in the future. */ void click_givecard(struct _prog *prog_data) { gtk_label_set_text(GTK_LABEL(prog_data->allwidgets[6]), NULL); gtk_button_set_label(GTK_BUTTON(prog_data->allwidgets[2]), _("Pass") ); prog_data->state = DISTRIBUTING; game_distribute_phase1(prog_data); game_finish_phase1(prog_data); prog_data->player = prog_data->distributer; select_player_next(&prog_data->player); prog_data->menext = prog_data->player; prog_data->state = READY_DISTRIB1; if(prog_data->output != NULL) { fprintf(prog_data->output, _("Ready, distribution phase 1 done.\n") ); } game_choose_trump(prog_data); } gboolean play_next_turn(struct _prog* prog_data) { return ( prog_data->player != 2 && prog_data->player == prog_data->menext && prog_data->players[prog_data->player] ); } /* click_selectmaster : Start the first turn of this round. * This means many things has to be done. First of all * when calling this function it means a player decided * which master family is the trump of this round. * We need to set this, to send the remaining cards * to each player (3 each, except the so called master * of the game, he will get 2 from the pile and one * which was the card proposed to the players as the * trump). Then we needs to set new points for all * cards from the trump family. They are now more * powerful then they were initialised. * Then the computer will play he has to. * * struct _prog *prog_data: see file def.h * * What is needed in struct _prog: * * prog_data->state : an enum egstate, see * file def.h for more details * * prog_data->master : who takes the proposed * card. * * prog_data->player : who has to drop a card * right now. It's not exactly always this. * When each players has dropped one card, * the player is not the player who needs to * drop a card next. * * prog_data->hashand : who is in charge * of deciding the first of each four cards * to be dropped on the table at each turn. * This is the player who has the hand * before anyone drops a more powerful card. * Note: it's not chaning when someone do * this (dropping a more powerful card). * That is why it's called "hashand" and not * "havehand". See menext for the player who * have the hand right now. * * prog_data->menext : the player which * win this turn at the moment. It can * be changed at any card drop except the * first. When you win a turn, you are * the first to drop the first card next. * This is exactly when menext should * not be changed. You can't change menext * at this time because you are the one * to drop the card. You are then already * the menext player. * * prog_data->distributer : which player * takes care of distributing the cards. * Note: you don't have to do it with * the mouse or something like this. This * is all virtual dude. Anyway it's needed * to know who is the first to play on the * first turn. * Note: each round it's incremented by * turning round the clock. * * prog_data->family : the trump color. * * prog_data->allwidgets[4] : allwidgets is an * array composed by many GtkWidget*. * The fifth is the spinbutton, which will * be suppressed in the future. * * prog_data->waiting : a GList representing * the table. This is where you drop your cards. * Each element of this list is a struct _card, * defined in the def.h file. * * prog_data->allwidgets[5] : a GtkImage * containing nothing at first. This is where * we put the icon of the trump family * (diamond, spade, heart or club) * * prog_data->icons : an array of 4 GtkImage, * each of the family icons. * * prog_data->output : the stream to print * messages to. Default is stdout. */ void click_selectmaster(struct _prog *prog_data, int master, int trump) { char str[10]; prog_data->state = DISTRIBUTING; prog_data->master = master; switch(master) { case 0: g_stpcpy(str, _("Top") ); break; case 1: g_stpcpy(str, _("Right") ); break; case 2: g_stpcpy(str, _("You") ); break; case 3: g_stpcpy(str, _("Left") ); break; } gtk_label_set_text(GTK_LABEL(prog_data->allwidgets[7]), str); prog_data->family = trump; prog_data->player = prog_data->menext; prog_data->hashand = prog_data->menext; gtk_image_set_from_pixbuf(GTK_IMAGE(prog_data->allwidgets[5]), prog_data->icons[prog_data->family]); if(prog_data->output != NULL) { fprintf(prog_data->output, _("Trump: ") ); game_print_family(prog_data->output, prog_data->family); fprintf(prog_data->output, "\n"); } game_distribute_phase2(prog_data); set_points(prog_data); prog_data->players[2] = g_list_sort(prog_data->players[2], list_sort); game_hand_position(prog_data, 2); if(prog_data->withdeclaration == TRUE) { game_check_declarations(prog_data); } gtk_label_set_text(GTK_LABEL(prog_data->allwidgets[8]), "1/8" ); gtk_button_set_label(GTK_BUTTON(prog_data->allwidgets[2]), _("Next") ); gtk_widget_set_sensitive(prog_data->allwidgets[2], FALSE); if(prog_data->player == 2) { set_moveable(prog_data->players[2], TRUE); } else { set_moveable(prog_data->players[2], FALSE); } prog_data->state = READY_DISTRIB2; draw_container(prog_data); if( play_next_turn(prog_data) ) { game_turn(prog_data, NULL); } game_play_ia(prog_data); } /* click_play : a mouse click on the * game area means something should be * done. The action here can be a card * drop, a distributing process, or * an end of a round. * In all case it should be related to * the computer doing something. */ void click_play(struct _prog *prog_data) { game_turn(prog_data, NULL); game_play_ia(prog_data); } /* action_click : the user clicked * on something. And we need to know * what he means. This is depending * on the game state. * * struct _prog *prog_data: see file def.h * * What is used in the struct _prog: * * prog_data->state : enum egstate, * see file def.h for more details. * * */ void action_click(struct _prog *prog_data) { if(prog_data->state == READY_PILE) { if(prog_data->output != NULL) { fprintf(prog_data->output, _("Distribute phase 1 please!\n") ); } if((prog_data->points[0] > 100 || prog_data->points[1] > 100 ) && (prog_data->points[0] != prog_data->points[1]) ) { free_cell_list(&prog_data->cells); prog_data->report = 0; prog_data->points[0] = 0; prog_data->points[1] = 0; prog_data->row = 0; gtk_table_resize(GTK_TABLE(prog_data->allwidgets[9]), 1, 2); } click_givecard(prog_data); } else if(prog_data->state == READY_DISTRIB2) { /*if(prog_data->output != NULL) fprintf(prog_data->output, _("Play !\n") );*/ click_play(prog_data); } draw_container(prog_data); } /* event_start : user clicked on the Start * labelled button. In the future this will * be replaced by something else. * * struct _prog *prog_data: see file def.h * */ void event_start(GtkButton *button, gpointer data) { struct _prog *prog_data = (struct _prog*)data; if(prog_data->output != NULL) { fprintf(prog_data->output, _("Click on Button\n") ); } if(prog_data->state == READY_DISTRIB1) { gtk_widget_set_sensitive(prog_data->allwidgets[10+ ((struct _card*)prog_data->waiting->data)->family], FALSE); if(prog_data->output != NULL) { fprintf(prog_data->output, _("You don't want this card. Ok!\n") ); } game_choose_trump_next(prog_data); } else if(prog_data->state == EGS_SECOND) { int i; for(i=0; i<4; i++) { if(i != ((struct _card*)prog_data->waiting->data)->family ) gtk_widget_set_sensitive(prog_data->allwidgets[10+i], FALSE); } if(prog_data->output) { fprintf(prog_data->output, _("Player decided to pass a second time.\n") ); } game_choose_trump_next(prog_data); } else action_click(prog_data); } /* motion_notify_event : the user drag the mouse. * This means a mouse button is pressed and the * cursor is moving. * * struct _prog *prog_data: see fil def.h * * What is needed in struct _prog: * * prog_data->movecard : this is a pointer * to a struct _movingcard defined in the * def.h file. It will be NULL if there are * no moving card at the moment. A moving * card is a card which the user is dragging * around on the game area. * The struct contains informations about * this card, like a pointer to the * struct _card of this particular card. * Also a separate struct _dim for the * position of the dragged card exists * because we need to recover the orginal * position of the card if it can't be * dropped. It's preferable to keep * the original data in the struct _card, * not in the newly allocated movecard _dim. * */ gint motion_notify_event (GtkWidget *widget, GdkEventMotion *event, gpointer data) { struct _prog *prog_data = (struct _prog*)data; struct _target *zone = NULL; GdkPixmap *source; int x, y, w, h, toph, leftw, ax, ay, aw, ah, bx, by, bw, bh; if(prog_data->movecard) { if(!prog_data->copy) { prog_data->movecard->card->draw = FALSE; draw_copy(prog_data); prog_data->movecard->card->draw = TRUE; } if(prog_data->copy) { x = prog_data->movecard->dim.x; y = prog_data->movecard->dim.y; w = prog_data->movecard->card->dim.w; h = prog_data->movecard->card->dim.h; gdk_draw_drawable(prog_data->target, prog_data->area->style->fg_gc[GTK_WIDGET_STATE(prog_data->area)], prog_data->copy, x-1, y-1, x-1, y-1, w+2, h+2); if(prog_data->dropping) { zone = draw_dropping_zone(prog_data, prog_data->target); } prog_data->movecard->dim.x = (gint)event->x -prog_data->movecard->dim.w; prog_data->movecard->dim.y = (gint)event->y -prog_data->movecard->dim.h; if(zone) { if(zone->active == FALSE) source = prog_data->copy; else source = prog_data->target; gdk_draw_drawable(prog_data->area->window, prog_data->area->style->fg_gc[GTK_WIDGET_STATE(prog_data->area)], source, zone->dim.x, zone->dim.y, zone->dim.x, zone->dim.y, zone->dim.w, 1); gdk_draw_drawable(prog_data->area->window, prog_data->area->style->fg_gc[GTK_WIDGET_STATE(prog_data->area)], source, zone->dim.x+zone->dim.w, zone->dim.y, zone->dim.x+zone->dim.w, zone->dim.y, 1, zone->dim.h); gdk_draw_drawable(prog_data->area->window, prog_data->area->style->fg_gc[GTK_WIDGET_STATE(prog_data->area)], source, zone->dim.x, zone->dim.y+zone->dim.h, zone->dim.x, zone->dim.y+zone->dim.h, zone->dim.w+1, 1); gdk_draw_drawable(prog_data->area->window, prog_data->area->style->fg_gc[GTK_WIDGET_STATE(prog_data->area)], source, zone->dim.x, zone->dim.y, zone->dim.x, zone->dim.y, 1, zone->dim.h); } draw_moving_card(prog_data, prog_data->target); gdk_draw_drawable(prog_data->area->window, prog_data->area->style->fg_gc[GTK_WIDGET_STATE(prog_data->area)], prog_data->target, prog_data->movecard->dim.x, prog_data->movecard->dim.y, prog_data->movecard->dim.x, prog_data->movecard->dim.y, w, h); /*----Refreshing area optimization---- * try this on an old XXX Mhz, and * see how fast it is when you drag * a card around. */ if(x <= prog_data->movecard->dim.x) { leftw = prog_data->movecard->dim.x -x; bx = x-1; bw = leftw+2; } else { leftw = w-x+prog_data->movecard->dim.x; bx = x+leftw-1; bw = w-leftw+2; } if(y <= prog_data->movecard->dim.y) { ax = x-1; ay = y-1; toph = prog_data->movecard->dim.y -y; ah = toph+1; aw = w+2; by = y+toph; bh = h - toph +1; } else { toph = h-(y-prog_data->movecard->dim.y); ax = x -1; ay = y+toph; ah = h - toph +1; aw = w +2; by = y-1; bh = toph+1; } gdk_draw_drawable( prog_data->area->window, prog_data->area->style->fg_gc[GTK_WIDGET_STATE(prog_data->area)], prog_data->target, ax, ay, ax, ay, aw, ah); gdk_draw_drawable( prog_data->area->window, prog_data->area->style->fg_gc[GTK_WIDGET_STATE(prog_data->area)], prog_data->target, bx, by, bx, by, bw, bh); } } return TRUE; } /* button_press_event : user did press a mouse button. * * prog_data->waiting: GList containing cards dropped * on the table. * * prog_data->players[2] : GList containing the user * hand. The player corresponding to the human * player is the third of the players array ([2]) * and is represented at the bottom of the screen. * */ void button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer data) { struct _prog *prog_data = (struct _prog*)data; gboolean found = FALSE; if(event->button == 1) { found = find_moveable_card(prog_data->waiting, event, prog_data); if(found == FALSE) found = find_moveable_card(prog_data->players[2], event, prog_data); if(found == TRUE) clear_blink(prog_data); } } gboolean is_player_next(struct _prog *prog_data, int n) { return ( ( (prog_data->player == n && prog_data->player != prog_data->hashand ) || ( prog_data->player == prog_data->hashand && prog_data->menext == n) ) && prog_data->players[n] != NULL ); } gboolean game_drop_enable(struct _prog *prog_data) { struct _target *zone = get_active_targetzone(prog_data->dropping); return ( prog_data->no_drag == TRUE || ( zone && zone->active == TRUE && (prog_data->state == READY_DISTRIB2 || prog_data->state == READY_DISTRIB1) ) ); } /* button_release_event : user released a pressed * mouse button. This means we need to check if * a card was selected. If true, then we want * to check if it can be dropped here. * * See file def.h for more details about * structs and their fields. */ void button_release_event (GtkWidget *widget, GdkEventButton *event, gpointer data) { struct _prog *prog_data = (struct _prog*)data; struct _card *drop = NULL; if(event->button == 1) { if(prog_data->movecard) { if(prog_data->copy) g_object_unref(prog_data->copy); prog_data->copy = NULL; prog_data->movecard->card->draw = TRUE; if( is_player_next(prog_data, 2) ) { if(prog_data->output != NULL) fprintf(prog_data->output, _("Click on a moveable card!\n") ); if( game_drop_enable(prog_data) ) drop = prog_data->movecard->card; } g_free(prog_data->movecard); prog_data->movecard = NULL; if(drop != NULL) { if(prog_data->state == READY_DISTRIB1) { if(prog_data->output != NULL) { fprintf(prog_data->output, _("You selected the card!\n") ); } gtk_widget_set_sensitive( prog_data->allwidgets[10+((struct _card*) prog_data->waiting->data)->family], FALSE); click_selectmaster(prog_data, 2, ((struct _card*)prog_data->waiting->data)->family); } else if(prog_data->state != EGS_SECOND) { if(prog_data->hide == TRUE) { int i; prog_data->hide = FALSE; for(i = 0; i < 4; i++) { if(i != 2) set_draw_face(prog_data->players[i], FALSE); } } gtk_label_set_text( GTK_LABEL(prog_data->allwidgets[6]), NULL); game_turn(prog_data, drop); game_play_ia(prog_data); } } draw_container(prog_data); } else { /*if(prog_data->output != NULL) fprintf(prog_data->output, _("Click on game area occured\n") );*/ action_click(prog_data); } } } /* realisation : the game area has been * initilialised by Gtk, we now needs to * draw it. This means allocating a * GtkPixmap to draw to, then loading * cards (because we need to know the window * depth before loading any images). * * Then we can set the position of the * dropping zone area, because we need * to know the size of the area before * positioning it. At least it's true * for the middle area of the table. * At the moment it's the only dropping * area created. * * Then we can start the game, that means * preparing everything for the game to * be played. As an example there is the * prog_data->pile GList that needs to be * mixed. * * See game_start() function for more details * about what needs to be done. (file game.c) * * return gboolean: see Gtk documentation * about realize event of a gdk-drawing area. */ gboolean realisation( GtkWidget *aire_de_dessin, gpointer data ) { struct _prog *prog_data = (struct _prog*) data; alloc_prog(prog_data); if( load_cards(DATA_DIR, prog_data, aire_de_dessin) == FALSE) { int i; for(i =0; i< 4; i++) { if(prog_data->icons[i]) gtk_image_set_from_pixbuf( GTK_IMAGE(prog_data->allwidgets[14+i]), prog_data->icons[i]); } position_targetzone(prog_data); game_start(prog_data); } else { GtkWidget *dialog; dialog = gtk_message_dialog_new( GTK_WINDOW(prog_data->allwidgets[0]), GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("An error occured while loading cards pictures.\nPlease reinstall.") , NULL); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(error_event), prog_data); gtk_widget_show_all(dialog); } return TRUE; } /* rafraichissement : refresh the game area. * * return gboolean: see Gtk documentation * about expose-event */ gboolean rafraichissement( GtkWidget *aire_de_dessin, GdkEventExpose *event, gpointer data) { draw_container((struct _prog*)data ); return FALSE; } /* * return gboolean: see Gtk documentation * about destroy event */ gboolean quit(GtkWidget *window, gpointer data) { gtk_main_quit(); return TRUE; } /* resize: the window size has changed. * We need to draw and position everything * again. * * see Gtk documentation about check-resize * event for more informations. */ void resize(GtkContainer *container, gpointer data) { struct _prog *prog_data = (struct _prog*) data; gboolean animation; int w,h; if(prog_data->target && prog_data->area && prog_data->area->window ) { gdk_drawable_get_size(prog_data->target, &w, &h); if(prog_data->area->allocation.width != w || prog_data->area->allocation.height != h) { clear_blink(prog_data); alloc_pixmap(prog_data); animation = prog_data->animation; if(animation == TRUE) prog_data->animation = FALSE; game_middle_position(prog_data); game_hand_position(prog_data, -1); position_targetzone(prog_data); draw_container(prog_data); if(animation == TRUE) prog_data->animation = TRUE; } } } void error_event(GtkDialog *dialog, gint rid, gpointer data) { struct _prog *prog_data = (struct _prog *) data; gtk_widget_destroy(GTK_WIDGET(dialog)); gtk_widget_destroy(GTK_WIDGET(prog_data->allwidgets[0])); } void dialog_response_event(GtkDialog *dialog, gint rid, gpointer data) { /*if(rid == GTK_RESPONSE_CLOSE)*/ gtk_widget_destroy(GTK_WIDGET(dialog)); } void click_diamond(GtkButton *button, gpointer data) { struct _prog *prog_data = (struct _prog *) data; int i=0; for(i = 0; i<4; i++) gtk_widget_set_sensitive(prog_data->allwidgets[10+i], FALSE); click_selectmaster(prog_data, prog_data->player, 0); } void click_heart(GtkButton *button, gpointer data) { struct _prog *prog_data = (struct _prog *) data; int i=0; for(i = 0; i<4; i++) gtk_widget_set_sensitive(prog_data->allwidgets[10+i], FALSE); click_selectmaster(prog_data, prog_data->player, 2); } void click_club(GtkButton *button, gpointer data) { struct _prog *prog_data = (struct _prog *) data; int i=0; for(i = 0; i<4; i++) gtk_widget_set_sensitive(prog_data->allwidgets[10+i], FALSE); click_selectmaster(prog_data, prog_data->player, 3); } void click_spade(GtkButton *button, gpointer data) { struct _prog *prog_data = (struct _prog *) data; int i=0; for(i = 0; i<4; i++) gtk_widget_set_sensitive(prog_data->allwidgets[10+i], FALSE); click_selectmaster(prog_data, prog_data->player, 1); }