/********************************************************************** * * FreeDoko a Doppelkopf-Game * * Copyright (C) 2001-2007 by Diether Knof and Borg Enders * * 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 can find this license in the file 'gpl.txt'. * * 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 * * Contact: * Diether Knof dknof@gmx.de * Borg Enders borg@borgsoft.de * *********************************************************************/ #include "constants.h" #ifdef USE_UI_GTKMM #include "hand.h" #include "table.h" #include "card_suggestion.h" #include "ui.h" #include "cards.h" #include "icongroup.h" #include "../../game/game.h" #include "../../party/rule.h" #include "../../player/player.h" #include "../../player/human/human.h" #include "../../player/ai/cards_information.of_player.h" #include "../../card/trick.h" #include "../../misc/setting.h" namespace UI_GTKMM_NS { /** ** Constructor ** ** @param table the table ** @param player the player ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.1 **/ Hand::Hand(Table* const table, Player const* const player) : HTIN(table, player) { return ; } // Hand::Hand(Table* const table, Player const* const player) /** ** Destruktor ** ** @param - ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.1 **/ Hand::~Hand() { return ; } // Hand::~Hand() /** ** draws the hand ** ** @param update whether to update the area ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.1 **/ void Hand::draw(bool const update) { if ((::game_status >= GAMESTATUS::GAME_INIT) && (::game_status <= GAMESTATUS::GAME_FINISHED)) { int pos_x = this->pos_x(); int pos_y = this->pos_y(); int width = this->width(); int height = this->height(); Game const& game = this->player->game(); // emphasize suggested card if ( this->table().card_suggestion_ && (this->player->type() == Player::HUMAN)) { switch (this->position()) { case SOUTH: pos_y -= (this->margin_y() * 2 / 3); height += (this->margin_y() * 2 / 3); break; case NORTH: height += (this->margin_y() * 2 / 3); break; case WEST: width += (this->margin_x() * 2 / 3); break; case EAST: pos_x -= (this->margin_x() * 2 / 3); width += (this->margin_x() * 2 / 3); break; default: DEBUG_ASSERTION(false, "Hand::cardno_at_position():\n" " player->no not valid: " << this->player->no()); break; } // switch (this->position()) } // if (this->table().card_suggestion_) if (update) this->table().clear(Gdk::Rectangle(pos_x, pos_y, width, height)); bool const show = ((this->player->type() == Player::HUMAN) || ::setting(Setting::SHOW_ALL_HANDS) || (::game_status == GAMESTATUS::GAME_FINISHED) || ( (::game_status == GAMESTATUS::GAME_REDISTRIBUTE) && (*(this->player) == game.soloplayer()) ) ); bool const show_ai_information_hand = ( !show && (::game_status >= GAMESTATUS::GAME_PLAY) && ::setting(Setting::SHOW_AI_INFORMATION_HANDS)); // the ai to show the cards information of Ai const& ai = ( (game.humanno() == 1) ? *static_cast(game.human_player()) : *static_cast(this->hand(SOUTH).player)); // the hand to draw ::Hand* const hand(!show_ai_information_hand ? NULL : new ::Hand(ai.handofplayer(*this->player))); SortedHand const sorted_hand(!show_ai_information_hand ? this->player->sorted_hand() : SortedHand(*hand) ); // for showing the 'must have' cards Card last_card; unsigned last_card_no = 0; // draw the cards for (unsigned c = 0; c < sorted_hand.cardsnumber_all(); c++) { if (this->table().in_game_review()) if (sorted_hand.played_trick(c) <= this->table().game_review_trickno()) continue; if ( (show || show_ai_information_hand ? !sorted_hand.played(c) : !sorted_hand.hand().played(c) ) || (::game_status == GAMESTATUS::GAME_FINISHED) ) { Glib::RefPtr card = (show || show_ai_information_hand ? this->ui->cards->card(sorted_hand.card_all(c), this->rotation()) : this->ui->cards->back(this->rotation()) ); int pos_x = (this->start_x() + static_cast(this->cards_step_x(sorted_hand.cardsnumber_all()) * c)); int pos_y = (this->start_y() + static_cast(this->cards_step_y(sorted_hand.cardsnumber_all()) * c)); if (last_card != sorted_hand.card_all(c)) { last_card_no = 0; last_card = sorted_hand.card_all(c); } if (show_ai_information_hand && !(last_card_no < ai.cards_information().of_player(*this->player).must_have(sorted_hand.card_all(c))) ) { Glib::RefPtr copy = card->copy(); card->saturate_and_pixelate(copy, 5, true); card = copy; } else { last_card_no += 1; } // emphasize the valid cards if ( ::setting(Setting::EMPHASIZE_VALID_CARDS) && game.rule()(Rule::SHOW_IF_VALID) && (::game_status == GAMESTATUS::GAME_PLAY) && (game.player_current() == *this->player) && (this->player->type() == Player::HUMAN)) { if (!game.trick_current().isvalid(sorted_hand.card_all(c), sorted_hand.hand())) { Glib::RefPtr copy = card->copy(); card->saturate_and_pixelate(copy, 0, true); card = copy; } // if (!card valid) } // if (emphasize valid cards) if ( this->table().card_suggestion_ && (this->player == &game.player_current()) && (c == sorted_hand.requested_position_all()) ) { switch (this->position()) { case NORTH: pos_y += (this->margin_y() * 2 / 3); break; case SOUTH: pos_y -= (this->margin_y() * 2 / 3); break; case WEST: pos_x += (this->margin_x() * 2 / 3); break; case EAST: pos_x -= (this->margin_x() * 2 / 3); break; default: DEBUG_ASSERTION(false, "Hand::draw():\n" " player->no not valid: " << this->player->no()); break; } // switch (this->position()) } // if (suggested card) this->table().pixmap->draw_pixbuf(this->table().gc, card, 0, 0, pos_x, pos_y, -1, -1, Gdk::RGB_DITHER_NONE, 0, 0); } // if (!sorted_hand.played(c)) } // for (c < sorted_hand.cardsnumber_all() if (show_ai_information_hand) delete hand; if (update) this->table().update(Gdk::Rectangle(pos_x, pos_y, width, height)); } // if (GAME_RESERVATION <= game_status < GAME_FINISHED) return ; } // void Hand::draw(bool const update = true) /** ** -> result ** ** @param position Position of the hand ** ** @return upper left x position of the hand at 'position' ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::pos_x(Position const position) const { int value = 0; // return value switch(position) { case NORTH: case SOUTH: value = (this->table().border_x() + this->width(WEST) + this->margin_x(WEST) + this->icongroup().width(WEST) + this->icongroup().margin_x(WEST)); break; case WEST: value = this->table().border_x(); break; case EAST: value = (this->table().width() - this->table().border_x() - this->width()); break; } // switch(position) return value; } // int Hand::pos_x(Position const position) /** ** -> result ** ** @param position Position of the hand ** ** @return upper left y position of the hand at 'position' ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::pos_y(Position const position) const { int value = 0; // return value switch(position) { case NORTH: value = this->table().border_y(); break; case SOUTH: value = (this->table().height() - this->table().border_y() - this->height()); break; case WEST: case EAST: value = (this->table().border_y() + this->height(NORTH) + this->margin_y(NORTH) + this->icongroup().height(NORTH) + this->icongroup().margin_y(NORTH)); break; } // switch(position) return value; } // int Hand::pos_y(Position const position) /** ** -> result ** ** @param position Position of the hand ** ** @return width of the hand at 'position' ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::width(Position const position) const { int value = 0; // return value switch(position) { case NORTH: case SOUTH: value = (this->table().width() - this->table().border_x() - this->width(WEST) - this->margin_x(WEST) - this->icongroup().width(WEST) - this->icongroup().margin_x(WEST) - this->table().border_x() - this->width(EAST) - this->margin_x(EAST) - this->icongroup().width(EAST) - this->icongroup().margin_x(EAST)); if (value < static_cast(this->ui->cards->width(this->rotation(position)))) value = this->ui->cards->width(this->rotation(position)); break; case WEST: case EAST: value = this->ui->cards->width(this->rotation(position)); break; } // switch(position) return value; } // int Hand::width(Position const position) /** ** -> result ** ** @param position Position of the hand ** ** @return height of the hand at 'position' ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::height(Position const position) const { int value = 0; // return value switch(position) { case NORTH: case SOUTH: value = this->ui->cards->height(this->rotation(position)); break; case WEST: case EAST: value = (this->table().height() - this->table().border_y() - this->height(NORTH) - this->margin_y(NORTH) - this->icongroup().height(NORTH) - this->icongroup().margin_y(NORTH) - this->table().border_y() - this->height(SOUTH) - this->margin_y(SOUTH) - this->icongroup().height(SOUTH) - this->icongroup().margin_y(SOUTH)); if (value < static_cast(this->ui->cards->height(this->rotation(position)))) value = this->ui->cards->height(this->rotation(position)); break; } // switch(position) return value; } // int Hand::height(Position const position) /** ** -> result ** ** @param position Position of the hand ** ** @return starting x position of the hand at 'position' ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::start_x(Position const position) const { return this->pos_x(position); } // int Hand::start_x(Position const position) /** ** -> result ** ** @param position Position of the hand ** ** @return starting y position of the hand at 'position' ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::start_y(Position const position) const { return this->pos_y(position); } // int Hand::start_y(Position const position) /** ** -> result ** ** @param position Position of the hand ** ** @return the x margin at 'position ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::margin_x(Position const position) const { int value = 0; switch(position) { case NORTH: case SOUTH: value = (this->ui->cards->height() / 10); break; case WEST: case EAST: value = (this->ui->cards->height() / 10); break; } // switch(position) return value; } // int Hand::margin_x(Position const position) /** ** -> result ** ** @param position Position of the hand ** ** @return the y margin at 'position ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::margin_y(Position const position) const { int value = 0; switch(position) { case NORTH: case SOUTH: value = (this->ui->cards->height() / 10); break; case WEST: case EAST: value = (this->ui->cards->height() / 10); break; } // switch(position) return value; } // int Hand::margin_y(Position const position) /** ** -> result ** ** @param - ** ** @return upper left x position of the hand ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::pos_x() const { return this->pos_x(this->position()); } // int Hand::pos_x() /** ** -> result ** ** @param - ** ** @return upper left y position of the hand ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::pos_y() const { return this->pos_y(this->position()); } // int Hand::pos_y() /** ** -> result ** ** @param - ** ** @return width of the hand ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::width() const { return this->width(this->position()); } // int Hand::width() /** ** -> result ** ** @param - ** ** @return height of the hand ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::height() const { return this->height(this->position()); } // int Hand::height() /** ** -> result ** ** @param - ** ** @return starting x position of the hand ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::start_x() const { return this->start_x(this->position()); } // int Hand::start_x() /** ** -> result ** ** @param - ** ** @return starting y position of the hand ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::start_y() const { return this->start_y(this->position()); } // int Hand::start_y() /** ** -> result ** ** @param cards_no number of cards (all cards) ** ** @return x step of the cards ** ** @author Diether Knof ** ** @version 0.6.1 **/ double Hand::cards_step_x(unsigned const cards_no) const { if (cards_no == 0) return 0; double value = 0; switch(this->position()) { case NORTH: case SOUTH: value = ((this->width(this->position()) - this->ui->cards->width(this->rotation(this->position()))) / static_cast(cards_no - 1)); break; case WEST: case EAST: value = 0; break; } // switch(this->position()) return value; } // double Hand::cards_step_x(unsigned cards_no) /** ** -> result ** ** @param cards_no number of cards (all cards) ** ** @return y step of the cards ** ** @author Diether Knof ** ** @version 0.6.1 **/ double Hand::cards_step_y(unsigned const cards_no) const { if (cards_no <= 1) return 0; double value = 0; switch(this->position()) { case NORTH: case SOUTH: value = 0; break; case WEST: case EAST: value = ((this->height(this->position()) - this->ui->cards->height(this->rotation(this->position()))) / static_cast(cards_no - 1)); break; } // switch(this->position()) return value; } // double Hand::cards_step_y(unsigned cards_no) /** ** -> result ** ** @param - ** ** @return the horizontal margin of the hand (to the center of the table) ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::margin_x() const { return this->margin_x(this->position()); } // int Hand::margin_x() /** ** -> result ** ** @param - ** ** @return the vertical margin of the hand (to the center of the table) ** ** @author Diether Knof ** ** @version 0.6.1 **/ int Hand::margin_y() const { return this->margin_y(this->position()); } // int Hand::margin_y() /** ** -> result ** ** @param x x position ** @param y y position ** ** @return the number of the card at the given position, ** UINT_MAX, if there is no card ** ** @author Diether Knof ** ** @version 0.6.1 ** ** @todo check for transparency **/ unsigned Hand::cardno_at_position(int const x, int const y) const { // note: the position of the hand is complex to calculate // (see Hand::draw()), so since it does not take much time to get // through all cards I just check all cards. for (unsigned cb = this->player->sorted_hand().cardsnumber_all(); cb > 0; cb--) { unsigned const c = cb - 1; if (!this->player->sorted_hand().played(c)) { int pos_x = (this->start_x() + static_cast(this->cards_step_x(this->player->sorted_hand().cardsnumber_all()) * c)); int pos_y = (this->start_y() + static_cast(this->cards_step_y(this->player->sorted_hand().cardsnumber_all()) * c)); // emphasize suggested card if ( this->table().card_suggestion_ && (this->player == &this->player->game().player_current()) && (c == this->player->sorted_hand().requested_position()) ) { switch (this->position()) { case NORTH: pos_y += (this->margin_y() * 2 / 3); break; case SOUTH: pos_y -= (this->margin_y() * 2 / 3); break; case WEST: pos_x += (this->margin_x() * 2 / 3); break; case EAST: pos_x -= (this->margin_x() * 2 / 3); break; default: DEBUG_ASSERTION(false, "Hand::cardno_at_position():\n" " player->no not valid: " << this->player->no()); break; } // switch (this->position()) } // if (suggested card if ((x >= pos_x) && (x < (pos_x + static_cast(this->ui->cards->width(this->rotation())))) && (y >= pos_y) && (y < (pos_y + static_cast(this->ui->cards->height(this->rotation())))) ) // the position is over the card // ToDo: check for transparency return c; } } return UINT_MAX; } // unsigned Hand::cardno_at_position(int const x, int const y) const /** ** -> result ** ** @param x x position ** @param y y position ** ** @return the card at the given position ** Card(), if there is no card ** ** @author Diether Knof ** ** @version 0.6.5 **/ Card Hand::card_at_position(int const x, int const y) const { unsigned const cardno = this->cardno_at_position(x, y); if (cardno == UINT_MAX) return Card(); return this->player->sorted_hand().card_all(cardno); } // Card Hand::card_at_position(int const x, int const y) const } // namespace UI_GTKMM_NS #endif // #ifdef USE_UI_GTKMM