/********************************************************************** * * 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" #include "game.h" #include "gameplay_actions/swines.h" #include "../player/player.h" #include "../party/party.h" #include "../party/rule.h" #include "../ui/ui.h" #ifdef NETWORK #include "../network/server.h" #endif /** ** -> result ** ** @param - ** ** @return whether the second dolle goes over the first in the current trick ** ** @author Diether Knof ** ** @version 0.7.4 **/ bool Game::second_dolle_over_first() const { return ( this->rule()(Rule::DOLLEN) && !( this->rule()(Rule::DOLLEN_FIRST_OVER_SECOND_WITH_SWINES) && this->swines_owner()) && ( !this->is_last_trick() ? this->rule()(Rule::DOLLEN_SECOND_OVER_FIRST) : (this->rule()(Rule::DOLLEN_SECOND_OVER_FIRST) != this->rule()(Rule::DOLLEN_CONTRARY_IN_LAST_TRICK)) ) ); } // bool Game::second_dolle_over_first() const /** ** -> result ** ** @param card card to check ** ** @return whether the card is a special card ** (according to the rules and the hand) ** ** @author Diether Knof ** ** @version 0.7.4 **/ bool Game::is_special(HandCard const& card) const { // dolle if ( this->rule()(Rule::DOLLEN) && (card == Card::DOLLE)) return true; // swines if ( this->rule()(Rule::SWINES) && ( GAMETYPE::is_solo(this->type()) ? this->rule()(Rule::SWINES_IN_SOLO) : true) && (card.value() == Card::ACE) && card.istrump() && ( this->swines_owner() || this->swines_announcement_valid(card.player())) ) return true; // hyperswines if ( this->rule()(Rule::HYPERSWINES) && ( GAMETYPE::is_solo(this->type()) ? this->rule()(Rule::HYPERSWINES_IN_SOLO) : true) && (card.value() == Card::NINE) && card.istrump() && ( this->swines_owner() || this->swines_announcement_valid(card.player())) ) return true; return false; } // bool Game::is_special(HandCard card) const /** ** -> result ** ** @param - ** ** @return a dolle card ** ** @author Diether Knof ** ** @version 0.7.4 **/ Card Game::dolle() const { if ( this->rule()(Rule::DOLLEN) && ( GAMETYPE::is_normal(this->type()) || GAMETYPE::is_poverty(this->type()) || GAMETYPE::is_marriage(this->type()) || GAMETYPE::is_color_solo(this->type())) ) return Card::DOLLE; else return Card(); } // Card Game::dolle() /** ** -> result ** ** @param - ** ** @return a swine card ** ** @author Diether Knof ** ** @version 0.7.4 **/ Card Game::swine() const { if ( this->rule()(Rule::SWINES) && ( GAMETYPE::is_normal(this->type()) || GAMETYPE::is_poverty(this->type()) || GAMETYPE::is_marriage(this->type()) || ( this->rule()(Rule::SWINES_IN_SOLO) && GAMETYPE::is_color_solo(this->type())) ) ) return Card(this->trumpcolor(), Card::ACE); else return Card(); } // Card Game::swine() /** ** -> result ** ** @param - ** ** @return a hyperswine card ** ** @author Diether Knof ** ** @version 0.7.4 **/ Card Game::hyperswine() const { if ( this->rule()(Rule::HYPERSWINES) && ( GAMETYPE::is_normal(this->type()) || GAMETYPE::is_poverty(this->type()) || GAMETYPE::is_marriage(this->type()) || ( this->rule()(Rule::HYPERSWINES_IN_SOLO) && GAMETYPE::is_color_solo(this->type())) ) ) return Card(this->trumpcolor(), this->rule()(Rule::WITH_NINES) ? Card::NINE : Card::KING); else return Card(); } // Card Game::hyperswine() /** ** -> result ** ** @param - ** ** @return the player who has swines ** NULL, if no player has swines ** ** @author Borg Enders ** @author Diether Knof ** ** @version 0.4.5 **/ Player const* Game::swines_owner() const { if (!this->swines_announced()) return NULL; return this->swines_owner_; } // Player const* Game::swines_owner() const /** ** -> result ** for the rules look into the code ** In a reservation 'true' can be returned although the announcement cannot ** be made (see Game::swines_announce). ** This is needed for the sorting in solo games. ** ** @param player the player who wants to announce swines ** ** @return whether 'player' can announce swines ** ** @author Diether Knof ** ** @version 0.7.4 **/ bool Game::swines_announcement_valid(Player const& player) const { // rule must allow swines if (!this->rule()(Rule::SWINES)) return false; // the swines must not be announced if (this->swines_announced()) return false; // check cards number if ( (this->rule()(Rule::SWINE_ONLY_SECOND) ? (player.hand().numberoftrumpaces() != 1) : (player.hand().numberoftrumpaces() != this->rule()(Rule::NUMBER_OF_SAME_CARDS))) ) return false; // 'swines announcement begin': must be in the reservation // (in a poverty before the shifting) if ( this->rule()(Rule::SWINES_ANNOUNCEMENT_BEGIN) && ( (::game_status == GAMESTATUS::GAME_INIT) || (::game_status == GAMESTATUS::GAME_RESERVATION) || (::game_status == GAMESTATUS::GAME_POVERTY_SHIFT) || (::game_status == GAMESTATUS::GAME_START) ) && !this->poverty_shifted()) return true; // normal case, announcement in the game: can announce if ( !this->rule()(Rule::SWINES_ANNOUNCEMENT_BEGIN) && !this->rule()(Rule::SWINE_ONLY_SECOND)) return true; // 'swine only second': first fox must be caught by the same team if ( this->rule()(Rule::SWINE_ONLY_SECOND) && (player.hand().numberofalltrumpaces() == this->rule()(Rule::NUMBER_OF_SAME_CARDS)) && (this->first_fox_catcher()) && ( (this->teaminfo(*this->first_fox_catcher()) == this->teaminfo(player)) && ( ::is_real(this->teaminfo(player)) || (this->first_fox_catcher()->no() == player.no()) ) ) ) return true; return false; } // bool Game::swines_announcement_valid(Player const& player) const /** ** announce swines if they can be announced and they have not yet been ** announced ** ** @param player player who wants to announce swines ** ** @return whether the swines are announced ** ** @author Diether Knof ** ** @version 0.7.4 **/ bool Game::swines_announce(Player& player) { if (this->swines_announced()) return false; if (!this->swines_announcement_valid(player)) return false; // in a reservation no announcement is allowed, // but 'valid' returns 'true', because of the cards ordering. // This is needed when solo games are selected if (::game_status == GAMESTATUS::GAME_RESERVATION) return false; this->swines_owner_ = &player; this->swines_announced_ = true; this->swines_owner_->hand_sort(); // sort the hand of all players because of possible hyperswines if (this->rule()(Rule::SWINE_ONLY_SECOND)) // the swines owner has to say his team this->teaminfo_update(); for (vector::iterator p = this->players().begin(); p != this->players().end(); p++) { (*p)->swines_announced(player); if ((*p)->hand().has_hyperswines()) (*p)->hand_sort(); } if (!this->isvirtual()) { ::ui->swines_announced(*this->swines_owner()); ::ui->gameplay_action(GameplayAction::Swines(this->swines_owner()->no())); } { // update 'this->trumps_' for (list::iterator t = this->trumps_.begin(); t != this->trumps_.end(); ++t) { if (*t == this->swine()) { this->trumps_.erase(t); break; } } // for (t \in this->trump_) this->trumps_.push_back(this->swine()); } // update 'this->trumps_' return true; } // bool Game::swines_announce(Player& player) /** ** -> result ** ** @param - ** ** @return the player who has hyperswines ** NULL, if no player has hyperswines ** ** @author Borg Enders ** @author Diether Knof ** ** @version 0.4.5 **/ Player const* Game::hyperswines_owner() const { if (!this->hyperswines_announced()) return NULL; return this->hyperswines_owner_; } // Player const* Game::hyperswines_owner() const /** ** -> result ** for the rules look into the code ** ** @param player the player who wants to announce hyperswines ** ** @return whether 'player' can announce hyperswines ** ** @author Diether Knof ** ** @version 0.6.6 **/ bool Game::hyperswines_announcement_valid(Player const& player) const { if (!this->rule()(Rule::HYPERSWINES)) return false; if (this->hyperswines_announced()) return false; if ( !this->swines_announced() && !this->swines_announcement_valid(player)) return false; #ifdef WORKAROUND // in the following case we have a problem // * virtual games // * cards informations // - the player can have diamond ace and diamond nine // - the player cannot have all four cards (2 diamond ace, 2 diamond nines) if ( this->isvirtual() && !this->swines_announced()) return false; #endif if ( !this->rule()(Rule::SWINES_AND_HYPERSWINES_JOINT) && (this->swines_owner() == &player)) return false; if ( (this->rule()(Rule::WITH_NINES) ? player.hand().numberoftrumpnines() : player.hand().numberoftrumpkings()) != this->rule()(Rule::NUMBER_OF_SAME_CARDS)) return false; if ( this->rule()(Rule::HYPERSWINES_ANNOUNCEMENT_BEGIN) && (::game_status == GAMESTATUS::GAME_RESERVATION) && !this->poverty_shifted()) return true; // normal case, announcement in the game: can announce if (!this->rule()(Rule::HYPERSWINES_ANNOUNCEMENT_BEGIN)) return true; return false; } // bool Game::hyperswines_announcement_valid(Player const& player) const /** ** announce hyperswines if they can be announced ** If the player has not annouced 'swines', they are announced automatically ** ** @param player player who wants to announce hyperswines ** ** @return whether the hyperswines are announced ** ** @author Diether Knof ** ** @version 0.6.6 **/ bool Game::hyperswines_announce(Player& player) { DEBUG_ASSERTION(!this->hyperswines_announced(), "Game::hyperswines_announce():\n" " hyperswines have already been announced.\n" " virtual = " << (this->isvirtual() ? "true" : "false")); if (this->hyperswines_announced()) return false; if (!this->hyperswines_announcement_valid(player)) return false; if (!this->swines_announced()) this->swines_announce(player); this->hyperswines_owner_ = &player; this->hyperswines_announced_ = true; this->hyperswines_owner_->hand_sort(); if (!this->isvirtual()) { ::ui->hyperswines_announced(*this->hyperswines_owner()); ::ui->gameplay_action(GameplayAction::Hyperswines(this->hyperswines_owner()->no())); } for (vector::iterator p = this->players().begin(); p != this->players().end(); p++) (*p)->hyperswines_announced(player); { // update 'this->trumps_' for (list::iterator t = this->trumps_.begin(); t != this->trumps_.end(); ++t) { if (*t == this->hyperswine()) { this->trumps_.erase(t); break; } } // for (t \in this->trump_) this->trumps_.push_back(this->hyperswine()); } // update 'this->trumps_' return true; } // bool Game::hyperswines_announce(Player& player) // bool Game::hyperswines_announced() const /** ** test the reservations for swines ** ** @param - ** ** @return - ** ** @author Diether Knof ** ** @version 0.6.6 **/ void Game::test_swines_from_reservations() { #ifdef NETWORK // the parent calls directly 'announce_swines()' if (::server->has_parent_connection()) return ; #endif if (this->rule()(Rule::SWINES)) { for (unsigned i = 0; i < this->playerno(); i++, this->player_current_ = &(this->player_following(this->player_current()))) { if ( this->reservation(this->player_current()).swines && this->swines_announcement_valid(this->player_current()) ) { this->swines_announce(this->player_current()); } // if (reservation) } // for (p < playerno()) } // if (rule()(Rule::SWINES)) // testing hyperswines if (this->rule()(Rule::HYPERSWINES)) { if (this->swines_announced()) { for (unsigned i = 0; i < this->playerno(); i++, this->player_current_ = &(this->player_following(this->player_current()))) { if ( (this->reservation(this->player_current()).hyperswines) && this->hyperswines_announcement_valid(this->player_current()) ) { this->hyperswines_announce(this->player_current()); } // if (reservation) } // for (p < playerno()) } // if (this->swines_announced()) } // if (rule()(Rule::HYPERSWINES)) return ; } // void Game::test_swines_from_reservations()