Files
wagic/projects/mtg/src/MTGGameZones.cpp

1749 lines
57 KiB
C++

#include "PrecompiledHeader.h"
#include "CardSelector.h"
#include "MTGGameZones.h"
#include "Player.h"
#include "WEvent.h"
#include "MTGDeck.h"
#include "Subtypes.h"
#include "Rules.h"
#include "Token.h"
#if defined (WIN32) || defined (LINUX)
#include <time.h>
#endif
//------------------------------
//Players Game
//------------------------------
MTGPlayerCards::MTGPlayerCards()
: owner(0)
{
init();
}
MTGPlayerCards::MTGPlayerCards(Player* player, int * idList, int idListSize)
: owner(player)
{
init();
int i;
for (i = 0; i < idListSize; i++)
{
MTGCard * card = MTGCollection()->getCardById(idList[i]);
if (card)
{
MTGCardInstance * newCard = NEW MTGCardInstance(card, this);
library->addCard(newCard);
}
}
}
MTGPlayerCards::MTGPlayerCards(MTGDeck * deck)
: owner(0)
{
init();
initDeck(deck);
}
void MTGPlayerCards::initDeck(MTGDeck * deck)
{
resetLibrary();
//commander zone init
if(deck->CommandZone.size())
{
for(unsigned int j = 0; j < deck->CommandZone.size(); j++)
{
string cardID = deck->CommandZone[j];
MTGCard * card = MTGCollection()->getCardById(atoi(cardID.c_str()));
if(card)
{
MTGCardInstance * newCard = NEW MTGCardInstance(card, this);
//the card is marked as commander ad added to library.
newCard->basicAbilities[Constants::ISCOMMANDER] = 1;
library->addCard(newCard);
}
}
}
map<int, int>::iterator it;
for (it = deck->cards.begin(); it != deck->cards.end(); it++)
{
MTGCard * card = deck->getCardById(it->first);
if (card)
{
for (int j = 0; j < it->second; j++)
{
MTGCardInstance * newCard = NEW MTGCardInstance(card, this);
if(!deck->CommandZone.size()){ //If no commander format there are no limitations for cards.
library->addCard(newCard);
} else {
if(newCard->hasType("Land") && newCard->hasType("Basic")){ //There are no limitations for basic lands cards.
library->addCard(newCard);
} else{
bool colorFound = false; // All the cards have to share at least one color with commander identity color (any symbol in manacost or magic text).
bool colorless = false; // Colorless card can be always added to deck.
for(unsigned int i = 0; i < deck->CommandZone.size() && !colorFound; i++){
MTGCard * cmdcard = MTGCollection()->getCardById(atoi(deck->CommandZone[i].c_str()));
if(cmdcard){
MTGCardInstance * commander = NEW MTGCardInstance(cmdcard, this);
if((newCard->hasColor(Constants::MTG_COLOR_WHITE) && commander->hasColor(Constants::MTG_COLOR_WHITE)) ||
(newCard->hasColor(Constants::MTG_COLOR_BLACK) && commander->hasColor(Constants::MTG_COLOR_BLACK)) ||
(newCard->hasColor(Constants::MTG_COLOR_RED) && commander->hasColor(Constants::MTG_COLOR_RED)) ||
(newCard->hasColor(Constants::MTG_COLOR_BLUE) && commander->hasColor(Constants::MTG_COLOR_BLUE)) ||
(newCard->hasColor(Constants::MTG_COLOR_GREEN) && commander->hasColor(Constants::MTG_COLOR_GREEN)) ||
(newCard->hasColor(Constants::MTG_COLOR_WHITE) && commander->magicText.find("{w}") != std::string::npos) ||
(newCard->hasColor(Constants::MTG_COLOR_BLACK) && commander->magicText.find("{b}") != std::string::npos)||
(newCard->hasColor(Constants::MTG_COLOR_RED) && commander->magicText.find("{r}") != std::string::npos) ||
(newCard->hasColor(Constants::MTG_COLOR_BLUE) && commander->magicText.find("{u}") != std::string::npos) ||
(newCard->hasColor(Constants::MTG_COLOR_GREEN) && commander->magicText.find("{g}") != std::string::npos) ||
(newCard->magicText.find("{w}") != std::string::npos && commander->hasColor(Constants::MTG_COLOR_WHITE)) ||
(newCard->magicText.find("{b}") != std::string::npos && commander->hasColor(Constants::MTG_COLOR_BLACK)) ||
(newCard->magicText.find("{r}") != std::string::npos && commander->hasColor(Constants::MTG_COLOR_RED)) ||
(newCard->magicText.find("{u}") != std::string::npos && commander->hasColor(Constants::MTG_COLOR_BLUE)) ||
(newCard->magicText.find("{g}") != std::string::npos && commander->hasColor(Constants::MTG_COLOR_GREEN)) ||
(newCard->magicText.find("{w}") != std::string::npos && commander->magicText.find("{w}") != std::string::npos) ||
(newCard->magicText.find("{b}") != std::string::npos && commander->magicText.find("{b}") != std::string::npos)||
(newCard->magicText.find("{r}") != std::string::npos && commander->magicText.find("{r}") != std::string::npos) ||
(newCard->magicText.find("{u}") != std::string::npos && commander->magicText.find("{u}") != std::string::npos) ||
(newCard->magicText.find("{g}") != std::string::npos && commander->magicText.find("{g}") != std::string::npos)){
colorFound = true;
}
}
}
if(!colorFound)
colorless = (newCard->magicText.find("{g}") == std::string::npos && newCard->magicText.find("{w}") == std::string::npos && newCard->magicText.find("{b}") == std::string::npos &&
newCard->magicText.find("{r}") == std::string::npos && newCard->magicText.find("{u}") == std::string::npos && !newCard->hasColor(Constants::MTG_COLOR_BLUE) &&
!newCard->hasColor(Constants::MTG_COLOR_RED) && !newCard->hasColor(Constants::MTG_COLOR_WHITE) && !newCard->hasColor(Constants::MTG_COLOR_GREEN) &&
!newCard->hasColor(Constants::MTG_COLOR_BLACK));
if(colorFound || colorless){
bool onlyInstance = true; // In commander format only single cards are allowed if they are not basic lands.
for(unsigned int k = 0; k < library->cards.size() && onlyInstance; k++){
if(library->cards[k]->name == newCard->name)
onlyInstance = false;
}
if(onlyInstance)
library->addCard(newCard);
}
}
}
}
}
}
//sb init
if(deck->Sideboard.size())
{
for(unsigned int j = 0; j < deck->Sideboard.size(); j++)
{
string cardID = deck->Sideboard[j];
MTGCard * card = MTGCollection()->getCardById(atoi(cardID.c_str()));
if(card)
{
MTGCardInstance * newCard = NEW MTGCardInstance(card, this);
//sb zone
sideboard->addCard(newCard);
}
}
}
}
MTGPlayerCards::~MTGPlayerCards()
{
SAFE_DELETE(library);
SAFE_DELETE(graveyard);
SAFE_DELETE(hand);
SAFE_DELETE(inPlay);
SAFE_DELETE(stack);
SAFE_DELETE(removedFromGame);
SAFE_DELETE(garbage);
SAFE_DELETE(reveal);
SAFE_DELETE(sideboard);
SAFE_DELETE(commandzone);
SAFE_DELETE(temp);
SAFE_DELETE(playRestrictions);
}
void MTGPlayerCards::beforeBeginPhase()
{
SAFE_DELETE(garbageLastTurn);
garbageLastTurn = garbage = NEW MTGGameZone();
garbage->setOwner(this->owner);
library->beforeBeginPhase();
graveyard->beforeBeginPhase();
hand->beforeBeginPhase();
inPlay->beforeBeginPhase();
stack->beforeBeginPhase();
removedFromGame->beforeBeginPhase();
garbage->beforeBeginPhase();
reveal->beforeBeginPhase();
sideboard->beforeBeginPhase();
commandzone->beforeBeginPhase();
temp->beforeBeginPhase();
}
void MTGPlayerCards::setOwner(Player * player)
{
this->owner = player;
library->setOwner(player);
graveyard->setOwner(player);
hand->setOwner(player);
inPlay->setOwner(player);
removedFromGame->setOwner(player);
stack->setOwner(player);
garbage->setOwner(player);
garbageLastTurn->setOwner(player);
reveal->setOwner(player);
sideboard->setOwner(player);
commandzone->setOwner(player);
temp->setOwner(player);
}
void MTGPlayerCards::initGame(int shuffle, int draw)
{
if (shuffle)
library->shuffle();
if (draw)
{
for (int i = 0; i < 7; i++)
{
drawFromLibrary();
}
}
}
void MTGPlayerCards::OptimizedHand(Player * who,int amount, int lands, int creatures, int othercards)
{
//give the Ai hand adventage to insure a challanging match.
Player * p = dynamic_cast<Player*>(who);
MTGCardInstance * card = NULL;
MTGGameZone * z = p->game->library;
z->shuffle();
int optimizedland = 0;
int optimizedothercards = 0;
int optimizedcreatures = 0;
for (int j = 0; j < z->nb_cards; j++)
{
MTGCardInstance * _card = z->cards[j];
//-------------
if (_card->isLand() && optimizedland < lands)
{
card = _card;
if (card)
{
p->game->putInZone(card, p->game->library, p->game->hand);
optimizedland += 1;
}
}
//----------------first try to optimize a few cards that cost 2 or less.
if (_card->getManaCost()->getConvertedCost() <= 2 && optimizedothercards < othercards && !_card->isLand()
&& !_card->isCreature())
{
card = _card;
if (card)
{
p->game->putInZone(card, p->game->library, p->game->hand);
optimizedothercards += 1;
}
}
if (_card->getManaCost()->getConvertedCost() <= 2 && optimizedcreatures < creatures && _card->isCreature())
{
card = _card;
if (card)
{
p->game->putInZone(card, p->game->library, p->game->hand);
optimizedcreatures += 1;
}
}
}
//--------------incase none of them cost 2 or less(which makes for a really poorly crafted Ai deck), try for 3 or less at this point we're accepting anything but lands under 3 mana---
for (int k = 0; k < z->nb_cards; k++)
{
MTGCardInstance * _card = z->cards[k];
if (_card->getManaCost()->getConvertedCost() <= 3 && optimizedothercards < othercards && (!_card->isLand()
|| _card->isCreature()))
{
card = _card;
if (card)
{
p->game->putInZone(card, p->game->library, p->game->hand);
optimizedothercards += 1;
}
}
if (_card->getManaCost()->getConvertedCost() <= 3 && optimizedcreatures < creatures && (_card->isCreature()
|| !_card->isLand()))
{
card = _card;
if (card)
{
p->game->putInZone(card, p->game->library, p->game->hand);
optimizedcreatures += 1;
}
}
}
//--------------add up remaining. only 7 cards are optimized, the remaining cards (if rules change amount) are just drawn.
int leftover = 0;
leftover = amount;
leftover -= optimizedland;
leftover -= optimizedcreatures;
leftover -= optimizedothercards;
for (int i = leftover; i > 0; i--)
{
p->game->drawFromLibrary();
}
}
//----------------------------
void MTGPlayerCards::drawFromLibrary()
{
if (!library->nb_cards)
{
if (inPlay->hasAbility(Constants::CANTLOSE)
|| inPlay->hasAbility(Constants::CANTMILLLOSE)
|| owner->opponent()->game->inPlay->hasAbility(Constants::CANTWIN))
{
return;
}
library->owner->getObserver()->setLoser(library->owner);
return;
}
MTGCardInstance * toMove = library->cards[library->nb_cards - 1];
if (!library->miracle)
{
library->miracle = true;
toMove->miracle = true;
}
bool prefetch = options[Options::CARDPREFETCHING].number?true:false;
if (prefetch && WResourceManager::Instance()->IsThreaded())
{
// useability tweak - assume that the user is probably going to want to see the new card,
// so prefetch it.
// if we're not in text mode, always get the thumb
if (library->owner->getObserver()->getCardSelector()->GetDrawMode() != DrawMode::kText
&& library->owner->getObserver()->getResourceManager())
{
DebugTrace("Prefetching AI card going into play: " << toMove->getImageName());
library->owner->getObserver()->getResourceManager()->RetrieveCard(toMove, RETRIEVE_THUMB);
// also cache the large image if we're using kNormal mode
if (library->owner->getObserver()->getCardSelector()->GetDrawMode() == DrawMode::kNormal)
{
library->owner->getObserver()->getResourceManager()->RetrieveCard(toMove);
}
}
}
MTGCardInstance * ret = putInZone(toMove, library, hand);
if(ret)
{
toMove->currentZone = hand;
ret->currentZone = hand;
library->lastCardDrawn = ret;
}
}
void MTGPlayerCards::resetLibrary()
{
SAFE_DELETE(library);
library = NEW MTGLibrary();
library->miracle = false;
}
void MTGPlayerCards::init()
{
library = NEW MTGLibrary();
library->miracle = false;
graveyard = NEW MTGGraveyard();
hand = NEW MTGHand();
inPlay = NEW MTGInPlay();
battlefield = inPlay;
stack = NEW MTGStack();
removedFromGame = NEW MTGRemovedFromGame();
exile = removedFromGame;
garbage = NEW MTGGameZone();
garbageLastTurn = garbage;
reveal = NEW MTGGameZone();
sideboard = NEW MTGGameZone();
commandzone = NEW MTGGameZone();
temp = NEW MTGGameZone();
playRestrictions = NEW PlayRestrictions();
}
void MTGPlayerCards::showHand()
{
hand->debugPrint();
}
// Moves a card to its owner's graveyard
MTGCardInstance * MTGPlayerCards::putInGraveyard(MTGCardInstance * card)
{
if (card->getCurrentZone() != card->controller()->game->hand && card->basicAbilities[(int)Constants::EXILEDEATH])
{
return putInZone(card, card->getCurrentZone(), card->owner->game->exile);
}
else if (card->getCurrentZone() != card->controller()->game->hand && card->basicAbilities[(int)Constants::HANDDEATH])
{
return putInZone(card, card->getCurrentZone(), card->owner->game->hand);
}
else if (card->getCurrentZone() != card->controller()->game->hand && (card->basicAbilities[(int)Constants::INPLAYDEATH] || card->basicAbilities[(int)Constants::INPLAYTAPDEATH]))
{
MTGCardInstance* ret = putInZone(card, card->getCurrentZone(), card->owner->game->battlefield);
if(card->basicAbilities[(int)Constants::INPLAYTAPDEATH])
ret->tap(true);
return ret;
}
return putInZone(card, card->currentZone, card->owner->game->graveyard);
}
// Moves a card to its owner's exile
MTGCardInstance * MTGPlayerCards::putInExile(MTGCardInstance * card)
{
return putInZone(card, card->currentZone, card->owner->game->exile);
}
// Moves a card to its owner's library
MTGCardInstance * MTGPlayerCards::putInLibrary(MTGCardInstance * card)
{
return putInZone(card, card->currentZone, card->owner->game->library);
}
// Moves a card to its *owner's* (not controller!) hand
MTGCardInstance * MTGPlayerCards::putInHand(MTGCardInstance * card)
{
return putInZone(card, card->currentZone, card->owner->game->hand);
}
// Moves a card from one zone to another
// If the card is not actually in the expected "from" zone, does nothing and returns null
MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone * from, MTGGameZone * to,bool asCopy)
{
MTGCardInstance * copy = NULL;
Player * discarderOwner = NULL;
GameObserver *g = owner->getObserver();
if (!from || !to)
return card; //Error check
int doCopy = 1;
bool shufflelibrary = card->basicAbilities[(int)Constants::SHUFFLELIBRARYDEATH];
bool inplaytoinplay = false;
bool ripToken = false;
if (card->discarderOwner)
discarderOwner = card->discarderOwner;
if (g->players[0]->game->battlefield->hasName("Rest in Peace")||g->players[1]->game->battlefield->hasName("Rest in Peace"))
ripToken = true;
//Madness or Put in Play...
for(int i = 0; i < 2; ++i)
{
if (card->discarded && (to == g->players[i]->game->graveyard) && (from == g->players[i]->game->hand))
{
if(card->basicAbilities[(int)Constants::MADNESS])
to = g->players[i]->game->exile;
}
}
//Darksteel Colossus, Legacy Weapon ... top priority since we replace destination directly automatically...
for(int i = 0; i < 2; ++i)
{
if ((to == g->players[i]->game->graveyard) && (
card->basicAbilities[(int)Constants::LIBRARYDEATH]||
card->basicAbilities[(int)Constants::SHUFFLELIBRARYDEATH]))
{
to = g->players[i]->game->library;
}
}
//Leyline of the Void, Yawgmoth's Agenda... effect...
for(int i = 0; i < 2; ++i)
{
if ((to == g->players[i]->game->graveyard) && (
(g->players[i]->game->battlefield->hasAbility(Constants::MYGCREATUREEXILER) && card->isCreature()) ||
(g->players[i]->opponent()->game->battlefield->hasAbility(Constants::OPPGCREATUREEXILER) && card->isCreature())||
g->players[i]->game->battlefield->hasAbility(Constants::MYGRAVEEXILER) ||
g->players[i]->opponent()->game->battlefield->hasAbility(Constants::OPPGRAVEEXILER)))
{
if ((card->isToken && ripToken))
to = g->players[i]->game->exile;
if (!card->isToken)
to = g->players[i]->game->exile;
}
//close the currently open MAIN display.
if (from == g->players[i]->game->library || from == g->players[i]->game->graveyard || from == g->players[i]->game->exile || from == g->players[i]->game->commandzone || from == g->players[i]->game->sideboard)
{
if (g->guiOpenDisplay)
{
g->ButtonPressed(g->guiOpenDisplay);
}
}
}
//all cards that go from the hand to the graveyard is ALWAYS a discard.
if ((to == g->players[0]->game->graveyard || to == g->players[1]->game->graveyard) && (from == g->players[0]->game->hand || from
== g->players[1]->game->hand))
{
card->discarded = true;
}
//When a card is moved from inPlay to inPlay (controller change, for example), it is still the same object
if ((to == g->players[0]->game->inPlay || to == g->players[1]->game->inPlay) && (from == g->players[0]->game->inPlay || from
== g->players[1]->game->inPlay))
{
doCopy = 0;
asCopy = true;//don't send zone change event so it will not destroy the GUI when multiple switching of control...
inplaytoinplay = true;//try sending different event...
}
//Increase the number of time this card has been casted from commandzone to recalculate cost.
if(from != to && (from == g->players[0]->game->commandzone || from == g->players[1]->game->commandzone)){
card->numofcastfromcommandzone++;
card->controller()->numOfCommandCast++;
}
if (!(copy = from->removeCard(card, doCopy)))
return NULL; //ERROR
// Copy all the counters of the original card... (solving the bug on comparison cards with counter before zone changing events)
if(card->counters && doCopy && !asCopy && !inplaytoinplay){
for (unsigned int i = 0; i < card->counters->counters.size(); i++){
Counter * counter = card->counters->counters[i];
for(int j = 0; j < counter->nb; j++)
copy->counters->addCounter(counter->name.c_str(), counter->power, counter->toughness, true);
}
}
//Commander is going back to Command Zone, so we recalculate cost according to how many times it has been casted from there.
if(to == g->players[0]->game->commandzone || to == g->players[1]->game->commandzone){
for(int i = 0; i < copy->numofcastfromcommandzone; i++)
copy->getManaCost()->add(Constants::MTG_COLOR_ARTIFACT,2);
}
if (card->miracle)
{
copy->miracle = true;
}
//reset discarder Owner
if(to == g->players[0]->game->hand || to == g->players[0]->game->stack || to == g->players[0]->game->library ||
to == g->players[1]->game->hand || to == g->players[1]->game->stack || to == g->players[1]->game->library)
{
card->discarderOwner = NULL;
copy->discarderOwner = NULL;
}
//copy discarderowner
if (discarderOwner)
{
copy->discarderOwner = discarderOwner;
//change to
if(to == g->players[0]->game->graveyard)
{
if(card->has(Constants::DISCARDTOPLAYBYOPPONENT) && discarderOwner == card->controller()->opponent())
{
to = g->players[0]->game->battlefield;
}
}
else if(to == g->players[1]->game->graveyard)
{
if(card->has(Constants::DISCARDTOPLAYBYOPPONENT) && discarderOwner == card->controller()->opponent())
{
to = g->players[1]->game->battlefield;
}
}
}
if(from == g->players[0]->game->battlefield || from == g->players[1]->game->battlefield)
if(to != g->players[0]->game->battlefield || to != g->players[1]->game->battlefield)
{
card->kicked = 0;
copy->kicked = 0;//kicked reset everflowing chalice...
}
if (card->discarded)
{//set discarded for madness...
if(from == g->players[0]->game->hand || from == g->players[1]->game->hand)
copy->discarded = true;
else//turn off discarded if its previous zone is not in hand...
copy->discarded = false;
}
if (options[Options::SFXVOLUME].number > 0)
{
if (to == g->players[0]->game->graveyard || to == g->players[1]->game->graveyard)
{
if (card->isCreature() && g->getResourceManager())
{
g->getResourceManager()->PlaySample("graveyard.wav");
}
}
}
MTGCardInstance * ret = copy;
for(int i = 0; i < 2; ++i)
{
if(to == g->players[i]->game->library && from == g->players[i]->game->library)//if its going to the library from the library we intend to put it on top.
{
g->players[i]->game->temp->addCard(copy);
g->players[i]->game->library->placeOnTop.push_back(copy);
return ret;//don't send event
}
}
//before adding card to zone, if its Melded, we break it apart
if (from == g->players[0]->game->battlefield || from == g->players[1]->game->battlefield)
{
if(to != g->players[0]->game->battlefield || to != g->players[1]->game->battlefield)
if (copy->previous && copy->previous->MeldedFrom.size() && !copy->isACopier && !copy->isToken)//!copier & !token fix kiki-jiki clones crash
{
vector<string> names = split(copy->previous->MeldedFrom, '|');
MTGCard * cardone = MTGCollection()->getCardByName(names[0]);
MTGCardInstance * cardOne = NEW MTGCardInstance(cardone, copy->owner->game);
to->addCard(cardOne);
WEvent * e = NEW WEventZoneChange(cardOne, from, to);
g->receiveEvent(e);
MTGCard * cardtwo = MTGCollection()->getCardByName(names[1]);
MTGCardInstance * cardTwo = NEW MTGCardInstance(cardtwo, copy->owner->game);
to->addCard(cardTwo);
WEvent * e2 = NEW WEventZoneChange(cardTwo, from, to);
g->receiveEvent(e2);
if(from == g->players[0]->game->battlefield)
g->players[0]->game->temp->addCard(copy);
if (from == g->players[1]->game->battlefield)
g->players[1]->game->temp->addCard(copy);
WEvent * e3 = NEW WEventZoneChange(copy, from, to);
g->receiveEvent(e3);
return ret;
}
}
to->addCard(copy);
//The "Temp" zone are purely for code purposes, and we don't want the abilities engine to
//Trigger when cards move in this zone
// Additionally, when they move "from" this zone,
// we trick the engine into believing that they moved from the zone the card was previously in
// See http://code.google.com/p/wagic/issues/detail?id=335
{
if (to == g->players[0]->game->temp || to == g->players[1]->game->temp)
{
//don't send event when moving to temp
return ret;
}
if (from == g->players[0]->game->temp || from == g->players[1]->game->temp)
{
//remove temporary stuff
MTGCardInstance * previous = copy->previous;
MTGCardInstance * previous2 = previous->previous;
from = previous->previousZone;
copy->previous = previous2;
if (previous2)
previous2->next = copy;
previous->previous = NULL;
previous->next = NULL;
SAFE_DELETE(previous);
}
if(to == g->players[0]->game->battlefield || to == g->players[1]->game->battlefield)
{
if(ret->alias == 109736 && discarderOwner)
{
if(discarderOwner == ret->controller()->opponent())
{
AbilityFactory af(g);
MTGAbility * dodeCounter = af.parseMagicLine("counter(1/1,2)",-1,NULL,ret);
dodeCounter->oneShot = true;
dodeCounter->canBeInterrupted = false;
dodeCounter->resolve();
SAFE_DELETE(dodeCounter);
}
}
}
//remove exerted if changing controls
if((to == g->players[0]->game->battlefield && from == g->players[1]->game->battlefield)||
(to == g->players[1]->game->battlefield && from == g->players[0]->game->battlefield))
{
if(ret->exerted)
ret->exerted = false;
}
}
if(!asCopy)
{
if(shufflelibrary)
copy->owner->game->library->shuffle();//shouldnt we only ever do this if you clicked close on your library gui??????
WEvent * e = NEW WEventZoneChange(copy, from, to);
g->receiveEvent(e);
// Erasing counters from copy after the event has been triggered (no counter can survive to a zone changing)
if(doCopy && copy->counters && copy->counters->mCount > 0){
for (unsigned int i = 0; i < copy->counters->counters.size(); i++){
Counter * counter = copy->counters->counters[i];
for(int j = counter->nb; j > 0; j--)
copy->counters->removeCounter(counter->name.c_str(), counter->power, counter->toughness, true);
}
}
}
if(inplaytoinplay)
{
WEvent * ep = NEW WEventCardControllerChange(copy);
g->receiveEvent(ep);
}
return ret;
}
void MTGPlayerCards::discardRandom(MTGGameZone * from, MTGCardInstance * _stored)
{
if (!from->nb_cards)
return;
int r = owner->getObserver()->getRandomGenerator()->random() % (from->nb_cards);
WEvent * e = NEW WEventCardDiscard(from->cards[r]);
GameObserver * game = owner->getObserver();
game->receiveEvent(e);
if(_stored)
from->cards[r]->discarderOwner = _stored->controller();
putInZone(from->cards[r], from, graveyard);
}
int MTGPlayerCards::isInPlay(MTGCardInstance * card)
{
if (inPlay->hasCard(card))
{
return 1;
}
return 0;
}
int MTGPlayerCards::isInZone(MTGCardInstance * card,MTGGameZone * zone)
{
if (zone->hasCard(card))
{
return 1;
}
return 0;
}
//--------------------------------------
// Zones specific code
//--------------------------------------
MTGGameZone::MTGGameZone() :
nb_cards(0), lastCardDrawn(NULL), needShuffle(false)
{
}
MTGGameZone::~MTGGameZone()
{
for (size_t i = 0; i < cards.size(); i++)
{
cards[i]->stillNeeded = false;
//SAFE_DELETE(cards[i]->previous);
//SAFE_DELETE( cards[i] );
//cause crashes for generated cards using castcard named card...??? test fix for now
if(cards[i]->previous)
{
delete cards[i]->previous;
cards[i]->previous = NULL;
}
if(cards[i])
{
delete cards[i];
cards[i] = NULL;
}
}
cards.clear();
cardsMap.clear();
owner = NULL;
}
void MTGGameZone::beforeBeginPhase()
{
cardsSeenLastTurn.clear();
for(size_t k = 0; k < cardsSeenThisTurn.size(); k++)
{
cardsSeenLastTurn.push_back(cardsSeenThisTurn[k]);
}
cardsSeenThisTurn.clear();
};
void MTGGameZone::setOwner(Player * player)
{
for (int i = 0; i < nb_cards; i++)
{
cards[i]->owner = player;
cards[i]->lastController = player;
cards[i]->setObserver(player->getObserver());
}
owner = player;
}
MTGCardInstance * MTGGameZone::removeCard(MTGCardInstance * card, int createCopy)
{
assert(nb_cards < 10000);
int i;
cardsMap.erase(card);
for (i = 0; i < (nb_cards); i++)
{
if (cards[i] == card)
{
card->currentZone = NULL;
nb_cards--;
cards.erase(cards.begin() + i);
MTGCardInstance * copy = card;
//if (card->isToken) //TODO better than this ?
// return card;
//card->lastController = card->controller();
if(!card)
return NULL;
if (createCopy)
{
copy = card->clone();
copy->previous = card;
copy->view = card->view;
copy->isToken = card->isToken;
copy->X = card->X;
copy->castX = card->castX;
copy->kicked = card->kicked;
copy->storedCard = card->storedCard;
copy->storedSourceCard = card->storedSourceCard;
copy->lastController = card->controller();
copy->previousController = card->controller();
copy->basicAbilities[Constants::ISCOMMANDER] = card->basicAbilities[Constants::ISCOMMANDER];
copy->damageInflictedAsCommander = card->damageInflictedAsCommander;
copy->numofcastfromcommandzone = card->numofcastfromcommandzone;
for (int i = 0; i < ManaCost::MANA_PAID_WITH_BESTOW +1; i++)
copy->alternateCostPaid[i] = card->alternateCostPaid[i];
//stupid bug with tokens...
if (card->model == card)
copy->model = copy;
if (card->data == card)
copy->data = copy;
card->next = copy;
}
copy->previousZone = this;
return copy;
}
}
return NULL;
}
MTGCardInstance * MTGGameZone::hasCard(MTGCardInstance * card)
{
if (card->currentZone == this)
return card;
return NULL;
}
size_t MTGGameZone::getIndex(MTGCardInstance * card)
{
size_t i;
for(i = 0; i < cards.size(); i++)
{
if(cards[i] == card)
return i;
}
return -1;
}
unsigned int MTGGameZone::countByAlias(int number)
{
if(!number)
return 0;
int result = 0;
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->alias == number)
{
result++;
}
}
return result;
}
unsigned int MTGGameZone::countByType(const string &value)
{
int result = 0;
int subTypeId = MTGAllCards::findType(value);
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->hasType(subTypeId))
{
result++;
}
else if(value == "token" && cards[i]->isToken)
result++;
}
return result;
}
unsigned int MTGGameZone::countByCanTarget(TargetChooser * tc)
{
if(!tc)
return 0;
// we don't care if cards have protection.
bool withoutProtections = true;
int result = 0;
for (int i = 0; i < (nb_cards); i++)
{
if (tc->canTarget(cards[i], withoutProtections))
{
result++;
}
}
return result;
}
unsigned int MTGGameZone::countTotalManaSymbols(TargetChooser * tc, int color)
{
if (!tc) {
return 0;
}
// we don't care if cards have protection.
bool withoutProtections = true;
int result = 0;
for (int i = 0; i < nb_cards; i++)
{
if (tc->canTarget(cards[i], withoutProtections))
{
result += cards[i]->getManaCost()->getManaSymbols(color);
}
}
return result;
}
unsigned int MTGGameZone::countDevotion(TargetChooser * tc, int color1, int color2)
{
if (!tc) {
return 0;
}
// we don't care if cards have protection.
bool withoutProtections = true;
int result = 0;
for (int i = 0; i < nb_cards; i++)
{
if (tc->canTarget(cards[i], withoutProtections))
{
result += cards[i]->getManaCost()->getManaSymbolsHybridMerged(color1);
}
if (tc->canTarget(cards[i], withoutProtections))
{
result += cards[i]->getManaCost()->getManaSymbolsHybridMerged(color2);
}
result -= cards[i]->getManaCost()->countHybridsNoPhyrexian();
}
return result;
}
MTGCardInstance * MTGGameZone::findByName(string name)
{
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->name == name || cards[i]->getLCName()/*tokens*/ == name)
{
return cards[i];
}
}
return NULL;
}
bool MTGGameZone::hasType(const char * value)
{
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->hasType(value))
{
return true;
}
}
return false;
}
bool MTGGameZone::hasTypeSpecificInt(int value1,int value)
{
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->hasType(value1) && cards[i]->hasType(value))
{
return true;
}
}
return false;
}
bool MTGGameZone::hasPrimaryType(const char * value,const char * secondvalue)
{
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->hasType(value) && cards[i]->hasType(secondvalue))
{
return true;
}
}
return 0;
}
bool MTGGameZone::hasSpecificType(const char * value,const char * secondvalue)
{
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->hasType(value) && cards[i]->hasSubtype(secondvalue))
{
return true;
}
}
return false;
}
bool MTGGameZone::hasTypeButNotType(const char * value,const char * secondvalue)
{
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->hasType(value) && cards[i]->hasSubtype(value) && !cards[i]->hasType(secondvalue) && !cards[i]->hasSubtype(secondvalue))
{
return true;
}
}
return false;
}
bool MTGGameZone::hasName(string value)
{
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->name == value)
{
return true;
}
}
return false;
}
bool MTGGameZone::hasColor(int value)
{
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->getManaCost()->hasColor(value) && cards[i]->getManaCost()->getConvertedCost() > 0)
{
return true;
}
}
return false;
}
bool MTGGameZone::hasX()
{
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->getManaCost()->hasX())
{
return true;
}
}
return false;
}
bool MTGGameZone::hasAbility(int ability)
{
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->basicAbilities[ability])
{
return true;
}
}
return false;
}
bool MTGGameZone::hasAlias(int alias)
{
for (int i = 0; i < (nb_cards); i++)
{
if (cards[i]->alias == alias)
{
return true;
}
}
return false;
}
int MTGGameZone::seenThisTurn(TargetChooser * tc, int castMethod, bool lastTurn)
{
//The following 2 lines modify the passed TargetChooser. Call this function with care :/
tc->setAllZones(); // This is to allow targetting cards without caring about the actual zone
tc->targetter = NULL;
int count = 0;
if (lastTurn)
{
for (vector<MTGCardInstance *>::iterator iter = cardsSeenLastTurn.begin(); iter != cardsSeenLastTurn.end(); ++iter)
{
MTGCardInstance * c = (*iter);
if (c && c->matchesCastFilter(castMethod) && tc->canTarget(c))
count++;
}
}
else
{
for (vector<MTGCardInstance *>::iterator iter = cardsSeenThisTurn.begin(); iter != cardsSeenThisTurn.end(); ++iter)
{
MTGCardInstance * c = (*iter);
if (c->matchesCastFilter(castMethod) && tc->canTarget(c))
count++;
}
}
return count;
}
int MTGGameZone::seenThisTurn(string targetChooserDefinition, int castMethod)
{
TargetChooserFactory tcf(owner->getObserver());
TargetChooser *tc = tcf.createTargetChooser(targetChooserDefinition, NULL);
int result = seenThisTurn(tc, castMethod,false);
SAFE_DELETE(tc);
return result;
}
int MTGGameZone::seenLastTurn(string targetChooserDefinition, int castMethod)
{
TargetChooserFactory tcf(owner->getObserver());
TargetChooser *tc = tcf.createTargetChooser(targetChooserDefinition, NULL);
int result = seenThisTurn(tc, castMethod,true);
SAFE_DELETE(tc);
return result;
}
void MTGGameZone::cleanupPhase()
{
for (int i = 0; i < (nb_cards); i++)
(cards[i])->cleanup();
}
void MTGGameZone::shuffle()
{
owner->getObserver()->getRandomGenerator()->random_shuffle(cards.begin(), cards.end());
}
void MTGGameZone::addCard(MTGCardInstance * card)
{
if (!card)
return;
cards.push_back(card);
cardsSeenThisTurn.push_back(card);
nb_cards++;
cardsMap[card] = 1;
card->lastController = this->owner;
card->currentZone = this;
}
void MTGGameZone::debugPrint()
{
for (int i = 0; i < nb_cards; i++)
std::cerr << cards[i]->getName() << endl;
}
//------------------------------
MTGCardInstance * MTGInPlay::getNextAttacker(MTGCardInstance * previous)
{
int foundprevious = 0;
if (previous == NULL)
{
foundprevious = 1;
}
for (int i = 0; i < nb_cards; i++)
{
MTGCardInstance * current = cards[i];
if (current == previous)
{
foundprevious = 1;
}
else if (foundprevious && current->isAttacker())
{
return current;
}
}
return NULL;
}
MTGCardInstance * MTGInPlay::getNextLurer(MTGCardInstance * previous)
{
int foundprevious = 0;
if (previous == NULL)
{
foundprevious = 1;
}
for (int i = 0; i < nb_cards; i++)
{
MTGCardInstance * current = cards[i];
if (current == previous)
{
foundprevious = 1;
}
else if (foundprevious && current->isAttacker() && current->has(Constants::LURE))
{
return current;
}
}
return NULL;
}
MTGCardInstance * MTGInPlay::getNextProvoker(MTGCardInstance * previous, MTGCardInstance * thiscard)
{
int foundprevious = 0;
if (previous == NULL)
{
foundprevious = 1;
}
for (int i = 0; i < nb_cards; i++)
{
MTGCardInstance * current = cards[i];
if (current == previous)
{
foundprevious = 1;
}
else if (foundprevious && current->isAttacker() && thiscard->isProvoked && current->ProvokeTarget)
{
if(thiscard == current->ProvokeTarget)
return current;
}
}
return NULL;
}
MTGCardInstance * MTGInPlay::findAProvoker(MTGCardInstance * thiscard)
{
for (int i = 0; i < nb_cards; i++)
{
MTGCardInstance * current = cards[i];
if (current->isAttacker() && current->ProvokeTarget)
{
if(current->ProvokeTarget == thiscard)
return current;
}
}
return NULL;
}
MTGCardInstance * MTGInPlay::findALurer()
{
for (int i = 0; i < nb_cards; i++)
{
MTGCardInstance * current = cards[i];
if (current->isAttacker() && current->has(Constants::LURE))
{
return current;
}
}
return NULL;
}
void MTGInPlay::untapAll()
{
int i;
for (i = 0; i < nb_cards; i++)
{
MTGCardInstance * card = cards[i];
card->setUntapping();
if (!card->basicAbilities[(int)Constants::DOESNOTUNTAP] && !card->basicAbilities[(int)Constants::SHACKLER])
{
if(card->exerted)
{
card->exerted = false;
if (card->frozen >= 1)
{
card->frozen = 0;
}
}
else
{
card->exerted = false;
if (card->frozen < 1)
{
card->attemptUntap();
}
if (card->frozen >= 1)
{
card->frozen = 0;
}
}
}
}
}
MTGGameZone * MTGGameZone::intToZone(int zoneId, Player * p, Player * p2)
{
if (p2 != p && p2 && (p != p2->opponent()))
{
p = p2->opponent();
//these cases are generally handled this is a edge case fix.
}
switch (zoneId)
{
case MY_GRAVEYARD:
return p->game->graveyard;
case OPPONENT_GRAVEYARD:
return p->opponent()->game->graveyard;
case MY_BATTLEFIELD:
return p->game->inPlay;
case OPPONENT_BATTLEFIELD:
return p->opponent()->game->inPlay;
case BATTLEFIELD:
return p->game->inPlay;
case MY_HAND:
return p->game->hand;
case OPPONENT_HAND:
return p->opponent()->game->hand;
case MY_EXILE:
return p->game->removedFromGame;
case OPPONENT_EXILE:
return p->opponent()->game->removedFromGame;
case MY_LIBRARY:
return p->game->library;
case OPPONENT_LIBRARY:
return p->opponent()->game->library;
case LIBRARY:
return p->game->library;
case MY_STACK:
return p->game->stack;
case OPPONENT_STACK:
return p->opponent()->game->stack;
case STACK:
return p->game->stack;
case MY_REVEAL:
return p->game->reveal;
case OPPONENT_REVEAL:
return p->opponent()->game->reveal;
case REVEAL:
return p->game->reveal;
case MY_SIDEBOARD:
return p->game->sideboard;
case OPPONENT_SIDEBOARD:
return p->opponent()->game->sideboard;
case SIDEBOARD:
return p->game->sideboard;
case MY_COMMANDZONE:
return p->game->commandzone;
case OPPONENT_COMMANDZONE:
return p->opponent()->game->commandzone;
case COMMANDZONE:
return p->game->commandzone;
}
if (!p2) return NULL;
switch (zoneId)
{
case TARGET_CONTROLLER_GRAVEYARD:
return p2->game->graveyard;
case TARGET_CONTROLLER_BATTLEFIELD:
return p2->game->inPlay;
case TARGET_CONTROLLER_HAND:
return p2->game->hand;
case TARGET_CONTROLLER_EXILE:
return p2->game->removedFromGame;
case TARGET_CONTROLLER_LIBRARY:
return p2->game->library;
case TARGET_CONTROLLER_STACK:
return p2->game->stack;
case TARGET_CONTROLLER_REVEAL:
return p2->game->reveal;
case TARGET_CONTROLLER_SIDEBOARD:
return p2->game->sideboard;
case TARGET_CONTROLLER_COMMANDZONE:
return p2->game->commandzone;
default:
return NULL;
}
}
MTGGameZone * MTGGameZone::intToZone(GameObserver *g, int zoneId, MTGCardInstance * source, MTGCardInstance * target)
{
Player *p, *p2;
if (!source)
p = g->currentlyActing();
else
p = source->controller();
if (!target)
{
//TODO source may be NULL, need to handle the case when it is NULL. method declaration has NULL being default value of source and target.
if(source->target)
{
//bug case, this is a patchwork fix for now
//we need to find the root cause of why the 2nd variable is not returning the target.
p2 = source->target->controller();
target = source->target;
}
else
{
//bug or bug case default to
p2 = source->controller();
target = source;
}
}
else
p2 = target->controller();
MTGGameZone * result = intToZone(zoneId, p, p2);
if (result) return result;
switch (zoneId)
{
case TARGET_OWNER_GRAVEYARD:
return target->owner->game->graveyard;
case GRAVEYARD:
return target->owner->game->graveyard;
case OWNER_GRAVEYARD:
return target->owner->game->graveyard;
case TARGETED_PLAYER_GRAVEYARD:
if(source->playerTarget)
return source->playerTarget->game->graveyard;
else return source->controller()->game->graveyard;
case TARGET_OWNER_BATTLEFIELD:
return target->owner->game->inPlay;
case OWNER_BATTLEFIELD:
return target->owner->game->inPlay;
case TARGETED_PLAYER_BATTLEFIELD:
if(source->playerTarget)
return source->playerTarget->game->inPlay;
else return source->controller()->game->inPlay;
case TARGET_OWNER_HAND:
return target->owner->game->hand;
case HAND:
return target->owner->game->hand;
case OWNER_HAND:
return target->owner->game->hand;
case TARGETED_PLAYER_HAND:
if(source->playerTarget)
return source->playerTarget->game->hand;
else return source->controller()->game->hand;
case TARGET_OWNER_EXILE:
return target->owner->game->removedFromGame;
case EXILE:
return target->owner->game->removedFromGame;
case OWNER_EXILE:
return target->owner->game->removedFromGame;
case TARGETED_PLAYER_EXILE:
if(source->playerTarget)
return source->playerTarget->game->removedFromGame;
else return source->controller()->game->removedFromGame;
case TARGET_OWNER_LIBRARY:
return target->owner->game->library;
case OWNER_LIBRARY:
return target->owner->game->library;
case TARGETED_PLAYER_LIBRARY:
if(source->playerTarget)
return source->playerTarget->game->library;
else return source->controller()->game->library;
case TARGET_OWNER_STACK:
return target->owner->game->stack;
case OWNER_STACK:
return target->owner->game->stack;
case TARGETED_PLAYER_STACK:
if(source->playerTarget)
return source->playerTarget->game->stack;
else return source->controller()->game->stack;
case TARGET_OWNER_REVEAL:
return target->owner->game->reveal;
case REVEAL:
return target->owner->game->reveal;
case OWNER_REVEAL:
return target->owner->game->reveal;
case TARGETED_PLAYER_REVEAL:
if (source->playerTarget)
return source->playerTarget->game->reveal;
else return source->controller()->game->reveal;
case TARGET_OWNER_SIDEBOARD:
return target->owner->game->sideboard;
case SIDEBOARD:
return target->owner->game->sideboard;
case OWNER_SIDEBOARD:
return target->owner->game->sideboard;
case TARGETED_PLAYER_SIDEBOARD:
if (source->playerTarget)
return source->playerTarget->game->sideboard;
else return source->controller()->game->sideboard;
case TARGET_OWNER_COMMANDZONE:
return target->owner->game->commandzone;
case COMMANDZONE:
return target->owner->game->commandzone;
case OWNER_COMMANDZONE:
return target->owner->game->commandzone;
case TARGETED_PLAYER_COMMANDZONE:
if (source->playerTarget)
return source->playerTarget->game->commandzone;
else return source->controller()->game->commandzone;
default:
return NULL;
}
}
int MTGGameZone::zoneStringToId(string zoneName)
{
const char * strings[] = { "mygraveyard", "opponentgraveyard", "targetownergraveyard", "targetcontrollergraveyard",
"ownergraveyard", "graveyard","targetedpersonsgraveyard",
"myinplay", "opponentinplay", "targetownerinplay", "targetcontrollerinplay", "ownerinplay", "inplay","targetedpersonsinplay",
"mybattlefield", "opponentbattlefield", "targetownerbattlefield", "targetcontrollerbattlefield",
"ownerbattlefield", "battlefield","targetedpersonsbattlefield",
"myhand", "opponenthand", "targetownerhand", "targetcontrollerhand", "ownerhand", "hand","targetedpersonshand",
"mylibrary", "opponentlibrary", "targetownerlibrary", "targetcontrollerlibrary", "ownerlibrary", "library","targetedpersonslibrary",
"myremovedfromgame", "opponentremovedfromgame", "targetownerremovedfromgame",
"targetcontrollerremovedfromgame", "ownerremovedfromgame", "removedfromgame","targetedpersonsremovefromgame",
"myexile", "opponentexile", "targetownerexile", "targetcontrollerexile", "ownerexile", "exile","targetedpersonsexile",
"mystack", "opponentstack", "targetownerstack", "targetcontrollerstack", "ownerstack", "stack","targetedpersonsstack",
"myreveal", "opponentreveal", "targetownerreveal", "targetcontrollerreveal", "ownerreveal", "reveal","targetedpersonsreveal",
"mysideboard", "opponentsideboard", "targetownersideboard", "targetcontrollersideboard", "ownersideboard", "sideboard","targetedpersonssideboard",
"mycommandzone", "opponentcommandzone", "targetownercommandzone", "targetcontrollercommandzone", "ownercommandzone", "commandzone","targetedpersonscommandzone",
};
int values[] = { MY_GRAVEYARD, OPPONENT_GRAVEYARD, TARGET_OWNER_GRAVEYARD, TARGET_CONTROLLER_GRAVEYARD, OWNER_GRAVEYARD,
GRAVEYARD,TARGETED_PLAYER_GRAVEYARD,
MY_BATTLEFIELD, OPPONENT_BATTLEFIELD, TARGET_OWNER_BATTLEFIELD, TARGET_CONTROLLER_BATTLEFIELD,
OWNER_BATTLEFIELD, BATTLEFIELD,TARGETED_PLAYER_BATTLEFIELD,
MY_BATTLEFIELD, OPPONENT_BATTLEFIELD, TARGET_OWNER_BATTLEFIELD, TARGET_CONTROLLER_BATTLEFIELD,
OWNER_BATTLEFIELD, BATTLEFIELD,TARGETED_PLAYER_BATTLEFIELD,
MY_HAND, OPPONENT_HAND, TARGET_OWNER_HAND, TARGET_CONTROLLER_HAND, OWNER_HAND, HAND,TARGETED_PLAYER_HAND,
MY_LIBRARY, OPPONENT_LIBRARY, TARGET_OWNER_LIBRARY, TARGET_CONTROLLER_LIBRARY, OWNER_LIBRARY, LIBRARY,TARGETED_PLAYER_LIBRARY,
MY_EXILE, OPPONENT_EXILE, TARGET_OWNER_EXILE, TARGET_CONTROLLER_EXILE, OWNER_EXILE, EXILE,TARGETED_PLAYER_EXILE,
MY_EXILE, OPPONENT_EXILE, TARGET_OWNER_EXILE, TARGET_CONTROLLER_EXILE, OWNER_EXILE, EXILE,TARGETED_PLAYER_EXILE,
MY_STACK, OPPONENT_STACK, TARGET_OWNER_STACK, TARGET_CONTROLLER_STACK, OWNER_STACK, STACK,TARGETED_PLAYER_STACK,
MY_REVEAL, OPPONENT_REVEAL, TARGET_OWNER_REVEAL, TARGET_CONTROLLER_REVEAL, OWNER_REVEAL, REVEAL,TARGETED_PLAYER_REVEAL,
MY_SIDEBOARD, OPPONENT_SIDEBOARD, TARGET_OWNER_SIDEBOARD, TARGET_CONTROLLER_SIDEBOARD, OWNER_SIDEBOARD, SIDEBOARD,TARGETED_PLAYER_SIDEBOARD,
MY_COMMANDZONE, OPPONENT_COMMANDZONE, TARGET_OWNER_COMMANDZONE, TARGET_CONTROLLER_COMMANDZONE, OWNER_COMMANDZONE, COMMANDZONE,TARGETED_PLAYER_COMMANDZONE };
int max = sizeof(values) / sizeof *(values);
for (int i = 0; i < max; ++i)
{
if (zoneName.compare(strings[i]) == 0)
{
return values[i];
}
}
return 0;
}
MTGGameZone * MTGGameZone::stringToZone(GameObserver *g, string zoneName, MTGCardInstance * source, MTGCardInstance * target)
{
return intToZone(g, zoneStringToId(zoneName), source, target);
}
ostream& MTGGameZone::toString(ostream& out) const
{
return out << "Unknown zone";
}
ostream& MTGLibrary::toString(ostream& out) const
{
return out << "Library " << owner->getDisplayName();
}
ostream& MTGGraveyard::toString(ostream& out) const
{
return out << "Graveyard " << owner->getDisplayName();
}
ostream& MTGHand::toString(ostream& out) const
{
return out << "Hand " << owner->getDisplayName();
}
ostream& MTGRemovedFromGame::toString(ostream& out) const
{
return out << "RemovedFromGame " << owner->getDisplayName();
}
ostream& MTGStack::toString(ostream& out) const
{
return out << "Stack " << owner->getDisplayName();
}
ostream& MTGInPlay::toString(ostream& out) const
{
return out << "InPlay " << owner->getDisplayName();
}
ostream& operator<<(ostream& out, const MTGGameZone& z)
{
for (int i = 0; i < z.nb_cards; i++)
{
out << z.cards[i]->getMTGId();
if(i < z.nb_cards - 1)
out << ",";
}
return out;
// return z.toString(out);
}
bool MTGGameZone::parseLine(const string& ss)
{
bool result = false;
string s = ss;
for (int i = 0; i < nb_cards; i++)
{
SAFE_DELETE( cards[i] );
}
cards.clear();
cardsMap.clear();
nb_cards = 0;
while(s.size())
{
size_t limiter = s.find(",");
MTGCard * card = 0;
string toFind;
if (limiter != string::npos)
{
toFind = trim(s.substr(0, limiter));
s = s.substr(limiter + 1);
}
else
{
toFind = trim(s);
s = "";
}
card = MTGCollection()->getCardByName(toFind);
int id = Rules::getMTGId(toFind);
if (card)
{
/* For the moment we add the card directly in the final zone.
This is not the normal way and this prevents to resolve spells.
We'll need a fusion operation afterward to cast relevant spells */
MTGCardInstance * newCard = NEW MTGCardInstance(card, owner->game);
addCard(newCard);
result = true;
}
else
{
if(toFind == "*")
nb_cards++;
else if ( id < 0 )
{
// For the moment, we create a dummy Token to please the testsuite
Token* myToken = new Token(id);
addCard(myToken);
result = true;
}
else
{
DebugTrace("Card unfound " << toFind << " " << id);
}
}
}
return result;
}
ostream& operator<<(ostream& out, const MTGPlayerCards& z)
{
if(z.library->cards.size()) {
out << "library=";
out << *(z.library) << endl;
}
if(z.battlefield->cards.size()) {
out << "inplay=";
out << *(z.battlefield) << endl;
}
if(z.graveyard->cards.size()) {
out << "graveyard=";
out << *(z.graveyard) << endl;
}
if(z.hand->cards.size()) {
out << "hand=";
out << *(z.hand) << endl;
}
if(z.removedFromGame->cards.size()) {
out << "exile=";
out << *(z.hand) << endl;
}
return out;
}
bool MTGPlayerCards::parseLine(const string& s)
{
size_t limiter = s.find("=");
if (limiter == string::npos) limiter = s.find(":");
string areaS;
if (limiter != string::npos)
{
areaS = s.substr(0, limiter);
if (areaS.compare("graveyard") == 0)
{
graveyard->parseLine(s.substr(limiter+1));
return true;
}
else if (areaS.compare("library") == 0)
{
library->parseLine(s.substr(limiter+1));
return true;
}
else if (areaS.compare("hand") == 0)
{
hand->parseLine(s.substr(limiter+1));
return true;
}
else if (areaS.compare("inplay") == 0 || areaS.compare("battlefield") == 0)
{
battlefield->parseLine(s.substr(limiter+1));
return true;
}
else if (areaS.compare("removedfromgame") == 0 || areaS.compare("exile") == 0)
{
removedFromGame->parseLine(s.substr(limiter+1));
return true;
}
}
return false;
}