/********************************************************************** * * 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 "trickpile.h" #include "table.h" #include "hand.h" #include "ui.h" #include "cards.h" #include "../../player/player.h" #include "../../game/game.h" #include "../../game/game.h" #include "../../party/rule.h" #include "../../card/trick.h" #include "../../misc/setting.h" #include "../../utils/string.h" namespace UI_GTKMM_NS { #define TRICKPILE_TRICKS_STEP_BIG_PART \ static_cast(this->ui->cards->height() / 15.0) #define TRICKPILE_TRICKS_STEP_SMALL_PART \ static_cast(this->ui->cards->width() / 30.0) #define TRICKPILE_CARDS_STEP_BIG_PART \ static_cast(this->ui->cards->height() * 0) #define TRICKPILE_CARDS_STEP_SMALL_PART \ static_cast(this->ui->cards->width() / 20.0) /** ** ** Constructor ** ** @param table the table ** @param player the player ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.1 ** **/ TrickPile::TrickPile(Table* const table, Player const* const player) : HTIN(table, player) { return ; } // TrickPile::TrickPile(Table* const table, Player const* const player) /** ** ** Destruktor ** ** @param - ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.1 ** **/ TrickPile::~TrickPile() { return ; } // TrickPile::~TrickPile() /** ** ** draws the trickpile ** ** @param update whether to update the area ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.1 ** **/ void TrickPile::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(); // for the specialpoints update the values // I hope, there cannot be more specialpoints than cards, since that // is not tested here. switch(this->player->no()) { case 0: pos_y += this->ui->cards->back().get_width(); pos_y -= this->ui->cards->back().get_height(); height -= this->ui->cards->back().get_width(); height += this->ui->cards->back().get_height(); break; case 1: width -= this->ui->cards->back().get_width(); width += this->ui->cards->back().get_height(); break; case 2: height -= this->ui->cards->back().get_width(); height += this->ui->cards->back().get_height(); break; case 3: pos_x += this->ui->cards->back().get_width(); pos_x -= this->ui->cards->back().get_height(); width -= this->ui->cards->back().get_width(); width += this->ui->cards->back().get_height(); break; default: DEBUG_ASSERTION(false, "TrickPile::draw_tricks():\n" " player->no not valid: " << this->player->no()); break; } // switch(this->player->no()) if (update) this->table().clear(Gdk::Rectangle(pos_x, pos_y, width, height)); // draw the cards this->draw_tricks(); if (this->player->game().rule()(Rule::SHOW_TRICKPILES_POINTS) && (::setting(Setting::SHOW_TRICKPILES_POINTS) || (::game_status == GAMESTATUS::GAME_FINISHED))) this->draw_points(); if (update) this->table().update(Gdk::Rectangle(pos_x, pos_y, width, height)); } // if (GAME_RESERVATION <= game_status < GAME_FINISHED) return ; } // void TrickPile::draw(bool const update = true) /** ** ** draws the tricks in the trickpile ** ** @param - ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.1 ** ** @todo skip the cards, the human player(s) do know not to make a special points (because of further team informations) ** **/ void TrickPile::draw_tricks() { if (::game_status & GAMESTATUS::GAME) { unsigned trickno = this->player->number_of_tricks(); if (this->table().in_game_review()) { trickno = 0; for (::TrickPile::const_iterator t = this->player->trickpile().begin(); t != this->player->trickpile().end(); ++t) if ((*t)->no() < this->table().game_review_trickno()) trickno += 1; else break; } // if (this->table().in_game_review()) for (unsigned t = 0; t < trickno; t++) { HandCards cards = this->player->trickpile()[t]->specialpoints_cards(); unsigned const specialpoints_no = cards.size(); // ToDo: skip the cards, the human player(s) do know not to make a special points (because of further team informations) while (cards.size() < this->player->game().playerno()) cards.push_back(HandCard()); for (unsigned c = 0; c < cards.size(); ++c) { HandCard const& card = cards[c]; Rotation rotation = this->pile_rotation(); int x = (this->start_x() + this->tricks_step_x() * t + this->cards_step_x() * c); int y = (this->start_y() + this->tricks_step_y() * t + this->cards_step_y() * c); if (card) { switch (this->position()) { case SOUTH: y += this->ui->cards->back(rotation).get_height(); rotation = ROTATION::counterclockwise(rotation); y -= this->ui->cards->card(card, rotation).get_height(); x -= this->cards_step_y() * c; break; case WEST: rotation = ROTATION::clockwise(rotation); y += this->cards_step_x() * c; break; case EAST: x += this->ui->cards->back(rotation).get_width(); rotation = ROTATION::counterclockwise(rotation); x -= this->ui->cards->card(card, rotation).get_width(); x -= this->cards_step_y() * c; break; case NORTH: x += this->ui->cards->back(rotation).get_width(); rotation = ROTATION::clockwise(rotation); x -= this->ui->cards->card(card, rotation).get_width(); y -= this->cards_step_x() * c; break; default: DEBUG_ASSERTION(false, "TrickPile::draw_tricks():\n" " player->no not valid: " << this->player->no()); break; } // switch (this->player->no()) } else { // if !(card) x -= (specialpoints_no * this->cards_step_x()); y -= (specialpoints_no * this->cards_step_y()); } // if !(card) this->table().pixmap->draw_pixbuf(this->table().gc, this->ui->cards->card(card, rotation), 0, 0, x, y, -1, -1, Gdk::RGB_DITHER_NONE, 0, 0); } // for (c < cards.size()) } // for (t < this->player->number_of_tricks()) } // if (::game_status & GAMESTATUS::GAME) return ; } // void TrickPile::draw_tricks() /** ** ** draws the points in the trickpile ** ** @param update whether to update the area (default: false) ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.1 ** **/ void TrickPile::draw_points(bool const update) { unsigned number_of_tricks = this->player->number_of_tricks(); this->table().trickpile_points_layout->set_text(DK::Utils::String::to_string(this->player->points_in_trickpile())); if (this->table().in_game_review()) { unsigned points = 0; number_of_tricks = 0; for (::TrickPile::const_iterator t = this->player->trickpile().begin(); t != this->player->trickpile().end(); ++t) if ((*t)->no() < this->table().game_review_trickno()) points += (*t)->points(), number_of_tricks += 1; else break; this->table().trickpile_points_layout->set_text(DK::Utils::String::to_string(points)); } // if (this->table().in_game_review()) if (number_of_tricks == 0) return ; int number_of_cards = (this->player->game().playerno() - this->player->trickpile().back()->specialpoints_cards().size()); if (number_of_cards < 1) number_of_cards = 1; int layout_width, layout_height; this->table().trickpile_points_layout->get_pixel_size(layout_width, layout_height); int const x = (this->start_x() + (this->tricks_step_x() * (number_of_tricks - 1)) + (this->cards_step_x() * (number_of_cards - 1)) + this->ui->cards->width(this->pile_rotation()) / 2 - (layout_width / 2) ); int const y = (this->start_y() + (this->tricks_step_y() * (number_of_tricks - 1)) + (this->cards_step_y() * (number_of_cards - 1)) + this->ui->cards->height(this->pile_rotation()) / 2 - (layout_height / 2) ); this->table().pixmap->draw_layout(this->table().trickpile_points_gc, x, y, this->table().trickpile_points_layout); if (update) this->table().update(Gdk::Rectangle(x, y, layout_width, layout_height)); return ; } // void TrickPile::draw_points(bool const update = false) /** ** -> result ** ** @param - ** ** @return rotation of the cards in the pile ** ** @author Diether Knof ** ** @version 0.7.2 **/ Rotation TrickPile::pile_rotation() const { switch(this->position()) { case NORTH: return LEFT; case SOUTH: return RIGHT; case WEST: return UP; case EAST: return DOWN; } // switch(this->position()) return UP; } // Rotation TrickPile::pile_rotation() const /** ** ** -> result ** ** @param - ** ** @return starting x position of the trickpile ** ** @version 0.6.1 ** ** @author Diether Knof ** **/ int TrickPile::pos_x() const { int value = this->start_x(); switch(this->position()) { case NORTH: case EAST: value -= (this->width() - this->ui->cards->width(this->pile_rotation())); break; case SOUTH: case WEST: break; } // switch(position) return value; } // int TrickPile::pos_x() /** ** ** -> result ** ** @param - ** ** @return starting y position of the trickpile ** ** @version 0.6.1 ** ** @author Diether Knof ** **/ int TrickPile::pos_y() const { int value = this->start_y(); switch(this->position()) { case NORTH: case WEST: break; case SOUTH: case EAST: value -= (this->height() - this->ui->cards->height(this->pile_rotation())); break; } // switch(position) return value; } // int TrickPile::pos_y() /** ** ** -> result ** ** @param - ** ** @return width of the trickpile ** ** @version 0.6.1 ** ** @author Diether Knof ** **/ int TrickPile::width() const { int const value = (this->ui->cards->width(this->pile_rotation()) + ((this->player->number_of_tricks() - 1) * std::abs(this->tricks_step_x())) + ((this->player->game().playerno() - 1) * std::abs(this->cards_step_x())) ); return value; } // int TrickPile::width() /** ** ** -> result ** ** @param - ** ** @return height of the trickpile ** ** @version 0.6.1 ** ** @author Diether Knof ** **/ int TrickPile::height() const { int const value = (this->ui->cards->height(this->pile_rotation()) + ((this->player->number_of_tricks() - 1) * std::abs(this->tricks_step_y())) + ((this->player->game().playerno() - 1) * std::abs(this->cards_step_y())) ); return value; } // int TrickPile::height() /** ** ** -> result ** ** @param - ** ** @return starting x position of the trickpile ** ** @version 0.6.1 ** ** @author Diether Knof ** **/ int TrickPile::start_x() const { int value = 0; // return value switch(this->position()) { case NORTH: value = (this->hand().start_x() - this->ui->cards->width(this->pile_rotation()) - this->hand().margin_x()); break; case SOUTH: value = (this->hand().start_x() + this->hand().width() + this->hand().margin_x()); break; case WEST: value = this->hand().start_x(); break; case EAST: value = (this->hand().start_x() + this->hand().width() - this->ui->cards->width(this->pile_rotation())); break; } // switch(this->position()) return value; } // int TrickPile::start_x() /** ** ** -> result ** ** @param - ** ** @return starting y position of the trickpile ** ** @version 0.6.1 ** ** @author Diether Knof ** **/ int TrickPile::start_y() const { int value = 0; // return value switch(this->position()) { case NORTH: value = this->hand().start_y(); break; case SOUTH: value = (this->hand().start_y() + this->hand().height() - this->ui->cards->height(this->pile_rotation())); break; case WEST: value = (this->hand().start_y() + this->hand().height() + this->hand().margin_y()); break; case EAST: value = (this->hand().start_y() - this->hand().margin_y() - this->ui->cards->height(this->pile_rotation())); break; } // switch(this->position()) return value; } // int TrickPile::start_y() /** ** ** -> result ** ** @param - ** ** @return x step of the tricks ** ** @version 0.6.1 ** ** @author Diether Knof ** **/ int TrickPile::tricks_step_x() const { int value = 0; if (!this->player->game().rule()(Rule::SHOW_TRICKS_IN_TRICKPILES)) { value = 0; } else { // if !(!this->player->game().rule()(Rule::SHOW_TRICKS_IN_TRICKPILES)) switch(this->position()) { case NORTH: value = -TRICKPILE_TRICKS_STEP_BIG_PART; break; case SOUTH: value = TRICKPILE_TRICKS_STEP_BIG_PART; break; case WEST: value = TRICKPILE_TRICKS_STEP_SMALL_PART; break; case EAST: value = -TRICKPILE_TRICKS_STEP_SMALL_PART; break; } // switch(this->position()) } // if !(!this->player->game().rule()(Rule::SHOW_TRICKS_IN_TRICKPILES)) return value; } // int TrickPile::tricks_step_x() /** ** ** -> result ** ** @param - ** ** @return y step of the tricks ** ** @version 0.6.1 ** ** @author Diether Knof ** **/ int TrickPile::tricks_step_y() const { int value = 0; if (!this->player->game().rule()(Rule::SHOW_TRICKS_IN_TRICKPILES)) { value = 0; } else { // if !(!this->player->game().rule()(Rule::SHOW_TRICKS_IN_TRICKPILES)) switch(this->position()) { case NORTH: value = TRICKPILE_TRICKS_STEP_SMALL_PART; break; case SOUTH: value = -TRICKPILE_TRICKS_STEP_SMALL_PART; break; case WEST: value = TRICKPILE_TRICKS_STEP_BIG_PART; break; case EAST: value = -TRICKPILE_TRICKS_STEP_BIG_PART; break; } // switch(this->position()) } // if !(!this->player->game().rule()(Rule::SHOW_TRICKS_IN_TRICKPILES)) return value; } // int TrickPile::tricks_step_y() /** ** ** -> result ** ** @param - ** ** @return x step of the cards ** ** @version 0.6.1 ** ** @author Diether Knof ** **/ int TrickPile::cards_step_x() const { int value = 0; switch(this->position()) { case NORTH: value = -TRICKPILE_CARDS_STEP_BIG_PART; break; case SOUTH: value = TRICKPILE_CARDS_STEP_BIG_PART; break; case WEST: value = TRICKPILE_CARDS_STEP_SMALL_PART; break; case EAST: value = -TRICKPILE_CARDS_STEP_SMALL_PART; break; } // switch(this->position()) return value; } // int TrickPile::cards_step_x() /** ** ** -> result ** ** @param - ** ** @return y step of the cards ** ** @version 0.6.1 ** ** @author Diether Knof ** **/ int TrickPile::cards_step_y() const { int value = 0; switch(this->position()) { case NORTH: value = TRICKPILE_CARDS_STEP_SMALL_PART; break; case SOUTH: value = -TRICKPILE_CARDS_STEP_SMALL_PART; break; case WEST: value = TRICKPILE_CARDS_STEP_BIG_PART; break; case EAST: value = -TRICKPILE_CARDS_STEP_BIG_PART; break; } // switch(this->position()) return value; } // int TrickPile::cards_step_y() /** ** ** -> result ** ** @param x x position ** @param y y position ** ** @return the pointer to the trick under the mouse curser ** NULL if the pointer is over no trick ** or the trick cannot be shown (-> rules) ** ** @version 0.6.6 ** ** @author Diether Knof ** ** @todo transparency ** **/ ::Trick const* TrickPile::over_trick(int const x, int const y) const { if (::in_running_game()) { ::TrickPile const& trickpile = this->player->trickpile(); for (int t = trickpile.size() - 1; t >= 0; --t) { if (trickpile[t]->no() + this->player->game().rule()(Rule::SHOW_TRICKS_NUMBER) < this->player->game().real_trick_current_no()) break; int const c = this->player->game().playerno() - 1; int const step_x = ((this->cards_step_x() > 0) ? this->cards_step_x() : -this->cards_step_x()); int const step_y = ((this->cards_step_y() > 0) ? this->cards_step_y() : -this->cards_step_y()); int const pos_x = (this->start_x() + t * this->tricks_step_x() + c * ((this->cards_step_x() > 0) ? 0 : -step_x)); int const pos_y = (this->start_y() + t * this->tricks_step_y() + c * ((this->cards_step_y() > 0) ? 0 : -step_y)); if ( (x >= pos_x) && (x < (pos_x + step_x * c + this->ui->cards->back(this->pile_rotation() ).get_width())) && (y >= pos_y) && (y < (pos_y + step_y * c + this->ui->cards->back(this->pile_rotation() ).get_height())) ) { return trickpile[t]; } } // if (this->player has made the last trick) } // if (::in_running_game()) return NULL; } // ::Trick const* TrickPile::over_trick(int const x, int const y) } // namespace UI_GTKMM_NS #endif // #ifdef USE_UI_GTKMM