Files
wagic/projects/mtg/src/TargetChooser.cpp
Anthony Calosa f11cc41df8 revised "colorless" attribute in targetchooser
also fix worldly tutor
2016-09-04 13:14:19 +08:00

1981 lines
62 KiB
C++

#include "PrecompiledHeader.h"
#include "TargetChooser.h"
#include "CardDescriptor.h"
#include "MTGGameZones.h"
#include "GameObserver.h"
#include "Subtypes.h"
#include "Counters.h"
#include "WEvent.h"
#include "AllAbilities.h"
TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInstance * card, MTGAbility * ability)
{
if (!s.size()) return NULL;
int zones[10];
int nbzones = 0;
size_t found;
bool other = false;
found = s.find("blockable");
if (found != string::npos)
{
int maxtargets = 1;
return NEW BlockableChooser(observer, card, maxtargets);
}
found = s.find("pairable");
if (found != string::npos)
{
int maxtargets = 1;
return NEW pairableChooser(observer, card, maxtargets);
}
found = s.find("dredgeable");
if (found != string::npos)
{
int maxtargets = 1;
zones[nbzones++] = MTGGameZone::MY_GRAVEYARD;
return NEW dredgeChooser(observer,zones,nbzones, card, maxtargets);
}
found = s.find("mytgt");
if (found == 0)
{
MTGCardInstance * target = card->target;
if (ability) target = (MTGCardInstance *) (ability->target);
return NEW CardTargetChooser(observer, target, card);
};
found = s.find("targetedplayer");
if (found == 0)
{
Player * pTarget = card->playerTarget;
if (ability)
pTarget = dynamic_cast<Player*>(ability->target);
if(pTarget)
return NEW PlayerTargetChooser(observer, card, 1, pTarget);
};
found = s.find("opponent");
if (found == 0)
{
int maxtargets = 1;
Player * opponent = card->controller()->opponent();
return NEW PlayerTargetChooser(observer, card, maxtargets, opponent);
};
found = s.find("controller");
if (found == 0)
{
int maxtargets = 1;
Player * controller = card->controller();
return NEW PlayerTargetChooser(observer, card, maxtargets, controller);
};
found = s.find("other ");
if (found != string::npos)
{
other = true;
s = s.erase(found,found+6-found);
}
found = s.find("trigger");
if (found == 0)
{
if (s.length() > 7 && s.find("[") == 7)
{
string s1 = s.substr(7, s.find("]"));
if (s1.find("to") != string::npos)
{
if(s1.find("<1>") != string::npos)
{
TriggerTargetChooser * ttc = NEW TriggerTargetChooser(observer, WEvent::TARGET_TO);
ttc->maxtargets = 1;
return ttc;
}
else
return NEW TriggerTargetChooser(observer, WEvent::TARGET_TO);
}
if (s1.find("from") != string::npos) return NEW TriggerTargetChooser(observer, WEvent::TARGET_FROM);
}
return NEW TriggerTargetChooser(observer, 1);
}
found = s.find("player");
if (found != string::npos)
{
int maxtargets = 1;
size_t several = s.find("<anyamount>");
if (several != string::npos) maxtargets = TargetChooser::UNLITMITED_TARGETS;
found = s.find("creature");
if (found != string::npos) return NEW DamageableTargetChooser(observer, card, maxtargets, other); //Any Damageable target (player, creature)
return NEW PlayerTargetChooser(observer, card, maxtargets); //Any player
}
found = s.find("mycurses");
if (found != string::npos)
{
int maxtargets = TargetChooser::UNLITMITED_TARGETS;
return NEW myCursesChooser(observer, card, maxtargets);
}
found = s.find("proliferation");
if (found != string::npos)
{
int maxtargets = TargetChooser::UNLITMITED_TARGETS;
return NEW ProliferateChooser(observer, card, maxtargets);
}
string s1;
found = s.find("|");
if (found != string::npos)
{
string s2;
s1 = s.substr(0, found);
s2 = s.substr(found + 1);
while (s2.size())
{
found = s2.find(",");
string zoneName;
if (found != string::npos)
{
zoneName = s2.substr(0, found);
s2 = s2.substr(found + 1);
}
else
{
zoneName = s2;
s2 = "";
}
zones[nbzones] = MTGGameZone::MY_BATTLEFIELD;
// First, check if it defines multiple zones
if (zoneName.compare("*") == 0)
{
zones[nbzones++] = MTGGameZone::ALL_ZONES;
}
else if (zoneName.compare("reveal") == 0)
{
zones[nbzones++] = MTGGameZone::MY_REVEAL;
zones[nbzones++] = MTGGameZone::OPPONENT_REVEAL;
}
else if (zoneName.compare("graveyard") == 0)
{
zones[nbzones++] = MTGGameZone::MY_GRAVEYARD;
zones[nbzones++] = MTGGameZone::OPPONENT_GRAVEYARD;
}
else if (zoneName.compare("battlefield") == 0 || zoneName.compare("inplay") == 0)
{
zones[nbzones++] = MTGGameZone::MY_BATTLEFIELD;
zones[nbzones++] = MTGGameZone::OPPONENT_BATTLEFIELD;
}
else if (zoneName.compare("hand") == 0)
{
zones[nbzones++] = MTGGameZone::MY_HAND;
zones[nbzones++] = MTGGameZone::OPPONENT_HAND;
}
else if (zoneName.compare("library") == 0)
{
zones[nbzones++] = MTGGameZone::MY_LIBRARY;
zones[nbzones++] = MTGGameZone::OPPONENT_LIBRARY;
}
else if (zoneName.compare("nonbattlezone") == 0)
{
zones[nbzones++] = MTGGameZone::MY_GRAVEYARD;
zones[nbzones++] = MTGGameZone::OPPONENT_GRAVEYARD;
zones[nbzones++] = MTGGameZone::MY_LIBRARY;
zones[nbzones++] = MTGGameZone::OPPONENT_LIBRARY;
zones[nbzones++] = MTGGameZone::MY_HAND;
zones[nbzones++] = MTGGameZone::OPPONENT_HAND;
zones[nbzones++] = MTGGameZone::MY_EXILE;
zones[nbzones++] = MTGGameZone::OPPONENT_EXILE;
}
else if (zoneName.compare("stack") == 0)
{
zones[nbzones++] = MTGGameZone::MY_STACK;
zones[nbzones++] = MTGGameZone::OPPONENT_STACK;
}
else if (zoneName.compare("exile") == 0)
{
zones[nbzones++] = MTGGameZone::MY_EXILE;
zones[nbzones++] = MTGGameZone::OPPONENT_EXILE;
}
else if (zoneName.compare("mycastingzone") == 0)
{
zones[nbzones++] = MTGGameZone::MY_GRAVEYARD;
zones[nbzones++] = MTGGameZone::MY_LIBRARY;
zones[nbzones++] = MTGGameZone::MY_HAND;
zones[nbzones++] = MTGGameZone::MY_EXILE;
}
else if (zoneName.compare("opponentcastingzone") == 0)
{
zones[nbzones++] = MTGGameZone::OPPONENT_GRAVEYARD;
zones[nbzones++] = MTGGameZone::OPPONENT_LIBRARY;
zones[nbzones++] = MTGGameZone::OPPONENT_HAND;
zones[nbzones++] = MTGGameZone::OPPONENT_EXILE;
}
else if (zoneName.compare("mynonplaynonexile") == 0)
{
zones[nbzones++] = MTGGameZone::MY_GRAVEYARD;
zones[nbzones++] = MTGGameZone::MY_LIBRARY;
zones[nbzones++] = MTGGameZone::MY_HAND;
}
else if (zoneName.compare("opponentnonplaynonexile") == 0)
{
zones[nbzones++] = MTGGameZone::OPPONENT_GRAVEYARD;
zones[nbzones++] = MTGGameZone::OPPONENT_LIBRARY;
zones[nbzones++] = MTGGameZone::OPPONENT_HAND;
}
else if (zoneName.compare("myzones") == 0)
{
zones[nbzones++] = MTGGameZone::MY_BATTLEFIELD;
zones[nbzones++] = MTGGameZone::MY_STACK;
zones[nbzones++] = MTGGameZone::MY_GRAVEYARD;
zones[nbzones++] = MTGGameZone::MY_LIBRARY;
zones[nbzones++] = MTGGameZone::MY_HAND;
zones[nbzones++] = MTGGameZone::MY_EXILE;
}
else if (zoneName.compare("opponentzones") == 0)
{
zones[nbzones++] = MTGGameZone::OPPONENT_BATTLEFIELD;
zones[nbzones++] = MTGGameZone::OPPONENT_STACK;
zones[nbzones++] = MTGGameZone::OPPONENT_GRAVEYARD;
zones[nbzones++] = MTGGameZone::OPPONENT_LIBRARY;
zones[nbzones++] = MTGGameZone::OPPONENT_HAND;
zones[nbzones++] = MTGGameZone::OPPONENT_EXILE;
}
else
{
int zone = MTGGameZone::zoneStringToId(zoneName);
if (zone) zones[nbzones++] = zone;
}
}
}
else
{
s1 = s;
nbzones = 2;
zones[0] = MTGGameZone::MY_BATTLEFIELD;
zones[1] = MTGGameZone::OPPONENT_BATTLEFIELD;
}
TargetChooser * tc = NULL;
int maxtargets = 1;
bool targetMin = false;
CardDescriptor * cd = NULL;
//max targets allowed
size_t limit = s1.find('<');
if (limit != string::npos)
{
size_t end = s1.find(">", limit);
string howmany;
if (end != string::npos)
{
howmany = s1.substr(limit + 1, end - limit - 1);
size_t uptoamount= howmany.find("upto:");
if(uptoamount != string::npos)
{
howmany = s1.substr(uptoamount + 6, end - uptoamount - 6);
}
else
{
targetMin = true;//if upto: is not found, then we need to have a minimum of the amount....
}
if (howmany.find("anyamount") != string::npos)
{
maxtargets = TargetChooser::UNLITMITED_TARGETS;
targetMin = false;
}
else
{
WParsedInt * howmuch = NEW WParsedInt(howmany, NULL, card);
maxtargets = howmuch->getValue();
delete howmuch;
}
s1 = s1.substr(end + 1);
}
}
if (s1.find("children") != string::npos || s1.find("parents") != string::npos)
{
TargetChooser * deeperTc = NULL;
if(s1.find("[") != string::npos)
{
AbilityFactory af(observer);
vector<string>deepTc = parseBetween(s1,"[","]");
deeperTc = createTargetChooser(deepTc[1],card);
}
return NEW ParentChildChooser(observer, card, maxtargets,deeperTc,s1.find("parents") != string::npos?2:1);
}
while (s1.size())
{
found = s1.find(",");
string typeName;
if (found != string::npos)
{
typeName = s1.substr(0, found);
s1 = s1.substr(found + 1);
}
else
{
typeName = s1;
s1 = "";
}
//Advanced cards caracteristics ?
found = typeName.find("[");
if (found != string::npos)
{
int nbminuses = 0;
int end = typeName.find("]");
string attributes = typeName.substr(found + 1, end - found - 1);
cd = NEW CardDescriptor();
while (attributes.size())
{
size_t found2 = attributes.find(";");
size_t foundAnd = attributes.find("&");
string attribute;
if (found2 != string::npos)
{
cd->mode = CardDescriptor::CD_OR;
attribute = attributes.substr(0, found2);
attributes = attributes.substr(found2 + 1);
}
else if (foundAnd != string::npos)
{
cd->mode = CardDescriptor::CD_AND;
attribute = attributes.substr(0, foundAnd);
attributes = attributes.substr(foundAnd + 1);
}
else
{
attribute = attributes;
attributes = "";
}
int minus = 0;
if (attribute[0] == '-')
{
minus = 1;
nbminuses++;
attribute = attribute.substr(1);
}
int comparisonMode = COMPARISON_NONE;
int comparisonCriterion = 0;
if (attribute.size() > 1)
{
size_t operatorPosition = attribute.find("=", 1);
if (operatorPosition != string::npos)
{
string numberCD = attribute.substr(operatorPosition + 1, attribute.size() - operatorPosition - 1);
WParsedInt * val = NEW WParsedInt(numberCD,NULL, card);
comparisonCriterion = val->getValue();
delete val;
switch (attribute[operatorPosition - 1])
{
case '<':
if (minus)
{
comparisonMode = COMPARISON_GREATER;
}
else
{
comparisonMode = COMPARISON_AT_MOST;
}
operatorPosition--;
break;
case '>':
if (minus)
{
comparisonMode = COMPARISON_LESS;
}
else
{
comparisonMode = COMPARISON_AT_LEAST;
}
operatorPosition--;
break;
default:
if (minus)
{
comparisonMode = COMPARISON_UNEQUAL;
}
else
{
comparisonMode = COMPARISON_EQUAL;
}
}
attribute = attribute.substr(0, operatorPosition);
}
}
//Attacker
if (attribute.find("attacking") != string::npos)
{
if (minus)
{
cd->attacker = -1;
}
else
{
cd->attacker = 1;
}
}
//Blocker
else if (attribute.find("blocking") != string::npos)
{
if (minus)
{
cd->defenser = &MTGCardInstance::NoCard;
}
else
{
cd->defenser = &MTGCardInstance::AnyCard;
}
}
//Blocked
else if (attribute.find("blocked") != string::npos)
{
if (minus)
{
cd->CDblocked = -1;
}
else
{
cd->CDblocked = 1;
}
}
//Tapped, untapped
else if (attribute.find("tapped") != string::npos)
{
if (minus)
{
cd->unsecureSetTapped(-1);
}
else
{
cd->unsecureSetTapped(1);
}
//Token
}
else if (attribute.find("token") != string::npos)
{
if (minus)
{
cd->isToken = -1;
}
else
{
cd->isToken = 1;
}
//put in its zone this turn
}
else if (attribute.find("fresh") != string::npos)
{
if (minus)
{
cd->unsecuresetfresh(-1);
}
else
{
cd->unsecuresetfresh(1);
}
}
else if (attribute.find("recent") != string::npos)
{
if (minus)
{
cd->unsecuresetrecent(-1);
}
else
{
cd->unsecuresetrecent(1);
}
}
else if (attribute.find("geared") != string::npos)
{
if (minus)
{
cd->CDgeared = -1;
}
else
{
cd->CDgeared = 1;
}
}
//creature is a level up creature
else if (attribute.find("leveler") != string::npos)
{
if (minus)
{
cd->isLeveler = -1;
}
else
{
cd->isLeveler = 1;
}
}
//creature is enchanted
else if (attribute.find("enchanted") != string::npos)
{
if (minus)
{
cd->CDenchanted = -1;
}
else
{
cd->CDenchanted = 1;
}
}
//creature was damaged
else if (attribute.find("damaged") != string::npos)
{
if (minus)
{
cd->CDdamaged = -1;
}
else
{
cd->CDdamaged = 1;
}
}
//creature dealt damage to opponent
else if (attribute.find("opponentdamager") != string::npos)
{
if (minus)
{
cd->CDopponentDamaged = -1;
}
else
{
cd->CDopponentDamaged = 1;
}
}
//creature dealt damage to controller
else if (attribute.find("controllerdamager") != string::npos)
{
if (minus)
{
cd->CDcontrollerDamaged = -1;
}
else
{
cd->CDcontrollerDamaged = 1;
}
}
//creature dealt damage to anything
else if (attribute.find("damager") != string::npos)
{
if (minus)
{
cd->CDdamager = -1;
}
else
{
cd->CDdamager = 1;
}
}
//can produce mana
else if (attribute.find("cmana") != string::npos)
{
if (minus)
{
cd->CDcanProduceC = -1;
}
else
{
cd->CDcanProduceC = 1;
}
}
else if (attribute.find("manag") != string::npos)
{
if (minus)
{
cd->CDcanProduceG = -1;
}
else
{
cd->CDcanProduceG = 1;
}
}
else if (attribute.find("manau") != string::npos)
{
if (minus)
{
cd->CDcanProduceU = -1;
}
else
{
cd->CDcanProduceU = 1;
}
}
else if (attribute.find("manar") != string::npos)
{
if (minus)
{
cd->CDcanProduceR = -1;
}
else
{
cd->CDcanProduceR = 1;
}
}
else if (attribute.find("manab") != string::npos)
{
if (minus)
{
cd->CDcanProduceB = -1;
}
else
{
cd->CDcanProduceB = 1;
}
}
else if (attribute.find("manaw") != string::npos)
{
if (minus)
{
cd->CDcanProduceW = -1;
}
else
{
cd->CDcanProduceW = 1;
}
}
else if (attribute.find("multicolor") != string::npos)
{
//card is multicolored?
if (minus)
{
cd->setisMultiColored(-1);
cd->SetExclusionColor(0);//not multicolored is monocolored not colorless, use iscolorless attribute
cd->SetExclusionColor(6);//restriction... green, red, blue, black or white colored only
cd->mode = CardDescriptor::CD_OR;
}
else
{
cd->setisMultiColored(1);
}
}
else if (attribute.find("power") != string::npos)
{
//Power restrictions
cd->setPower(comparisonCriterion);
cd->powerComparisonMode = comparisonMode;
//Toughness restrictions
}
else if (attribute.find("toughness") != string::npos)
{
cd->setToughness(comparisonCriterion);
cd->toughnessComparisonMode = comparisonMode;
//Manacost restrictions
}
else if (attribute.find("manacost") != string::npos)
{
cd->convertedManacost = comparisonCriterion;
cd->manacostComparisonMode = comparisonMode;
//Counter Restrictions
}
else if (attribute.find("share!") != string::npos)
{
size_t start = attribute.find("share!");
size_t end = attribute.rfind("!");
string CDtype = attribute.substr(start + 6,end - start);
if( card && card->isSpell() && card->backupTargets.size())
{
if (Spell * targetSpell = dynamic_cast<Spell *>(card->backupTargets[0]))
{
//spells always store their targets in :targets[]
//however they are all erased as the spell resolves
//added a array to store these backups incase theyre needed
//again for effects such as these.
card->target = targetSpell->source;
}
}
if( CDtype.find("name") != string::npos )
{
if(card->target)
cd->compareName = card->target->name;
else
cd->compareName = card->name;
cd->nameComparisonMode = COMPARISON_EQUAL;
}
else if( CDtype.find("color") != string::npos )
{
if(card->target)
cd->colors = card->target->colors;
else
cd->colors = card->colors;
cd->mode = CardDescriptor::CD_OR;
}
else if( CDtype.find("types") != string::npos )
{
if(card && card->target)
{
cd->types = card->target->types;
}
else
{
cd->types = card->types;
}
//remove main types because we only care about subtypes here.
cd->removeType("artifact");
cd->removeType("land");
cd->removeType("enchantment");
cd->removeType("instant");
cd->removeType("sorcery");
cd->removeType("legendary");
cd->removeType("creature");
cd->removeType("planeswalker");
cd->removeType("tribal");
cd->mode = CardDescriptor::CD_OR;
}
}
else if (attribute.find("counter") != string::npos)
{
if (attribute.find("{any}") != string::npos)
{
cd->anyCounter = 1;
}
else
{
size_t start = attribute.find("{");
size_t end = attribute.find("}");
string counterString = attribute.substr(start + 1, end - start - 1);
AbilityFactory abf(observer);
Counter * counter = abf.parseCounter(counterString, card);
if (counter)
{
cd->counterName = counter->name;
cd->counterNB = counter->nb;
cd->counterPower = counter->power;
cd->counterToughness = counter->toughness;
delete (counter);
}
if (minus)
{
cd->counterComparisonMode = COMPARISON_LESS;
}
else
{
cd->counterComparisonMode = COMPARISON_AT_LEAST;
}
}
}
else
{
int attributefound = 0;
//Colors - remove Artifact and Land from the loop
for (int cid = 1; cid < Constants::NB_Colors - 1; cid++)
{
if (attribute.find(Constants::MTGColorStrings[cid]) != string::npos)
{
attributefound = 1;
if (minus)
cd->SetExclusionColor(cid);
else
cd->setColor(cid);
}
}
if (attribute.find("colorless") != string::npos)
{
attributefound = 1;
/*for (int cid = 1; cid < Constants::NB_Colors; cid++)
{
cd->SetExclusionColor(cid);
}
cd->mode = CardDescriptor::CD_OR;*/
if (minus)
cd->CDnocolor = -1;
else
cd->CDnocolor = 1;
}
if (attribute.find("chosencolor") != string::npos)
{
attributefound = 1;
if (minus)
cd->SetExclusionColor(card->chooseacolor);
else
cd->setColor(card->chooseacolor);
}
if (attribute.find("chosentype") != string::npos)
{
attributefound = 1;
if (minus)
{
cd->setNegativeSubtype(card->chooseasubtype);
}
else
{
cd->setSubtype(card->chooseasubtype);
}
}
if (!attributefound)
{
//Abilities
for (int j = 0; j < Constants::NB_BASIC_ABILITIES; j++)
{
if (attribute.find(Constants::MTGBasicAbilities[j]) != string::npos)
{
attributefound = 1;
if (minus)
cd->mAbilityExclusions.set(j);
else
cd->basicAbilities.set(j);
}
}
}
if (!attributefound)
{
//Subtypes
if (minus)
{
cd->setNegativeSubtype(attribute);
}
else
{
cd->setSubtype(attribute);
}
}
}
}
if (nbminuses)
cd->mode = CardDescriptor::CD_AND;
typeName = typeName.substr(0, found);
}
if (cd)
{
if (!tc)
{
if (typeName.compare("*") != 0) cd->setSubtype(typeName);
tc = NEW DescriptorTargetChooser(observer, cd, zones, nbzones, card, maxtargets, other, targetMin);
}
else
{
delete (cd);
return NULL;
}
}
else
{
if (!tc)
{
if (typeName.compare("*") == 0)
{
return NEW TargetZoneChooser(observer, zones, nbzones, card, maxtargets, other, targetMin);
}
else if (typeName.compare("this") == 0)
{
return NEW CardTargetChooser(observer, card, card, zones, nbzones);
}
else if (typeName.compare("sourcecard") == 0)
{
CardTargetChooser * ctc = NEW CardTargetChooser(observer, card, card, zones, nbzones);
ctc->setAllZones();
return ctc;
}
else if (typeName.compare("mystored") == 0)
{
return NEW CardTargetChooser(observer, card->storedSourceCard, card, zones, nbzones);
}
else if (typeName.compare("abilitycontroller") == 0)
{
return NEW PlayerTargetChooser(observer, card, 1, card->storedSourceCard->controller());
}
else
{
tc = NEW TypeTargetChooser(observer, typeName.c_str(), zones, nbzones, card, maxtargets, other, targetMin);
}
}
else
{
((TypeTargetChooser *) tc)->addType(typeName.c_str());
tc->maxtargets = maxtargets;
}
}
}
return tc;
}
TargetChooser * TargetChooserFactory::createTargetChooser(MTGCardInstance * card)
{
if(!card)
return NULL;
int id = card->getId();
string s = card->spellTargetType;
if (card->alias)
{
id = card->alias;
//TODO load target as well... ?
}
TargetChooser * tc = createTargetChooser(s, card);
if (tc) return tc;
//Any target than cannot be defined automatically is determined by its id
switch (id)
{
//Spell
case 1224: //Spell blast
{
#if defined (WIN32) || defined (LINUX)
DebugTrace("Counter Spell !\n");
#endif
return NEW SpellTargetChooser(observer, card);
}
//Spell Or Permanent
case 1282: //ChaosLace
case 1152: //DeathLace
case 1358: //PureLace
case 1227: //ThoughLace
case 1257: //Lifelace
{
return NEW SpellOrPermanentTargetChooser(observer, card);
}
//Red Spell or Permanent
case 1191: //Blue Elemental Blast
{
return NEW SpellOrPermanentTargetChooser(observer, card, Constants::MTG_COLOR_RED);
}
//Blue Spell or Permanent
case 1312: //Red Elemental Blast
{
return NEW SpellOrPermanentTargetChooser(observer, card, Constants::MTG_COLOR_BLUE);
}
//Damage History
case 1344: //Eye for an Eye
{
return NEW DamageTargetChooser(observer, card, -1, 1, RESOLVED_OK);
}
default:
{
return NULL;
}
}
}
TargetChooser::TargetChooser(GameObserver *observer, MTGCardInstance * card, int _maxtargets, bool _other,bool _targetMin) :
TargetsList(), observer(observer)
{
forceTargetListReady = 0;
forceTargetListReadyByPlayer = 0;
source = card;
targetter = card;
maxtargets = _maxtargets;
other = _other;
targetMin = _targetMin;
done = false;
attemptsToFill = 0;
if(source)
Owner = source->controller();
else
Owner = 0;
}
//Default targetter : every card can be targetted, unless it is protected from the targetter card
// For spells that do not "target" a specific card, set targetter to NULL
bool TargetChooser::canTarget(Targetable * target, bool withoutProtections)
{
if (!target) return false;
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(target))
{
if (other)
{
MTGCardInstance * tempcard = card;
while (tempcard)
{
if (tempcard == source) return false;
tempcard = tempcard->previous;
}
}
if(source && ((source->hasSubtype(Subtypes::TYPE_AURA) || source->hasSubtype(Subtypes::TYPE_EQUIPMENT)) && source->target && source->target == card && source->target->isPhased && targetter->target == card))
{
return true;
}
//this is kinda cheating but by default we let auras and equipments always continue to target a phased creature.
else if (card && card->isPhased)
{
return false;
}
if (source && targetter && card->isInPlay(observer) && !withoutProtections)
{
if (card->has(Constants::SHROUD)) return targetter->bypassTC;
if (card->protectedAgainst(targetter)) return targetter->bypassTC;
if (card->CantBeTargetby(targetter)) return targetter->bypassTC;
if ((targetter->controller() != card->controller()) && card->has(Constants::OPPONENTSHROUD)) return targetter->bypassTC;
if (card->has(Constants::PROTECTIONFROMCOLOREDSPELLS))
{//a spell that has no target=criteria means it's not targetted unless its a workaround card...
if((targetter->spellTargetType.size()) && (targetter->hasColor(1)||targetter->hasColor(2)||targetter->hasColor(3)||targetter->hasColor(4)||targetter->hasColor(5)))
return targetter->bypassTC;
}
}
return true;
}
else if (dynamic_cast<Interruptible *>(target))
return true;
return false;
}
int TargetChooser::addTarget(Targetable * target)
{
if (canTarget(target))
{
TargetsList::addTarget(target);
}
return targetsReadyCheck();
}
int TargetChooser::ForceTargetListReady()
{
int state = targetsReadyCheck();
if (state == TARGET_OK)
{
forceTargetListReady = 1;
}
return forceTargetListReady;
}
int TargetChooser::targetsReadyCheck()
{
if (targetMin == false && !targets.size() && forceTargetListReadyByPlayer)
{
return TARGET_OK_FULL;//we have no min amount for targets and 0 targets is a valid amount player called for a forced finish.
}
if (!targets.size())
{
return TARGET_NOK;
}
if (full())
{
return TARGET_OK_FULL;
}
if (!ready())
{
return TARGET_OK_NOT_READY;
}
return TARGET_OK;
}
int TargetChooser::targetListSet()
{
int state = targetsReadyCheck();
if (state == TARGET_OK_FULL || forceTargetListReady)
{
return 1;
}
return 0;
}
bool TargetChooser::validTargetsExist(int maxTargets)
{
for (int i = 0; i < 2; ++i)
{
int maxAmount = 0;
Player *p = observer->players[i];
if (canTarget(p)) return true;
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->stack, p->game->reveal };
for (int k = 0; k < 7; k++)
{
MTGGameZone * z = zones[k];
if (targetsZone(z))
{
for (int j = 0; j < z->nb_cards; j++)
{
if (canTarget(z->cards[j])) maxAmount++;
}
}
}
if(maxAmount >= maxTargets)
return true;
}
return false;
}
int TargetChooser::countValidTargets(bool withoutProtections)
{
int result = 0;
//Some TargetChooser objects are created at a point where no observer is available
// see ManaCost::parseManaCost which sets observer to NULL in some cases (namely: when the cards database is loaded at game start)
// This is a workaround for this situation
if (!observer && source)
observer = source->getObserver();
for (int i = 0; i < 2; ++i)
{
assert(observer);
Player *p = observer->players[i];
if(canTarget(p))
result++;
MTGGameZone * zones[] = { p->game->inPlay, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->stack, p->game->reveal };
for (int k = 0; k < 7; k++)
{
MTGGameZone * z = zones[k];
if (targetsZone(z))
{
for (int j = 0; j < z->nb_cards; j++)
{
if (canTarget(z->cards[j], withoutProtections)) result++;
}
}
}
}
return result;
}
bool TargetChooser::equals(TargetChooser *)
{
//This function always return 1 for now, since the default TargetChooser targets everything
//In the future we might need to check some of "targetter" settings to take protection into account...
return true;
}
/**
a specific Card
**/
CardTargetChooser::CardTargetChooser(GameObserver *observer, MTGCardInstance * _card, MTGCardInstance * source, int * _zones, int _nbzones) :
TargetZoneChooser(observer, _zones, _nbzones, source)
{
validTarget = _card;
}
bool CardTargetChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (!target) return false;
MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(target);
if (!card) return false;
if (!nbzones && !TargetChooser::canTarget(target,withoutProtections)) return false;
if (nbzones && !TargetZoneChooser::canTarget(target,withoutProtections)) return false;
while (card)
{
if (card == validTarget) return true;
card = card->previous;
}
return false;
}
CardTargetChooser * CardTargetChooser::clone() const
{
CardTargetChooser * a = NEW CardTargetChooser(*this);
return a;
}
bool CardTargetChooser::equals(TargetChooser * tc)
{
CardTargetChooser * ctc = dynamic_cast<CardTargetChooser *> (tc);
if (!ctc)
return false;
if (validTarget != ctc->validTarget) //todo, check also previous cards, see "cantarget"...
return false;
return TargetZoneChooser::equals(tc);
}
/**
Choose anything that has a given list of types
**/
TypeTargetChooser::TypeTargetChooser(GameObserver *observer, const char * _type, MTGCardInstance * card, int _maxtargets, bool other,bool targetMin) :
TargetZoneChooser(observer, card, _maxtargets, other,targetMin)
{
int id = MTGAllCards::findType(_type);
nbtypes = 0;
addType(id);
int default_zones[] = { MTGGameZone::MY_BATTLEFIELD, MTGGameZone::OPPONENT_BATTLEFIELD };
init(default_zones, 2);
}
TypeTargetChooser::TypeTargetChooser(GameObserver *observer, const char * _type, int * _zones, int nbzones, MTGCardInstance * card, int _maxtargets,
bool other,bool targetMin) :
TargetZoneChooser(observer, card, _maxtargets, other,targetMin)
{
int id = MTGAllCards::findType(_type);
nbtypes = 0;
addType(id);
if (nbzones == 0)
{
int default_zones[] = { MTGGameZone::MY_BATTLEFIELD, MTGGameZone::OPPONENT_BATTLEFIELD };
init(default_zones, 2);
}
else
{
init(_zones, nbzones);
}
}
void TypeTargetChooser::addType(const char * _type)
{
int id = MTGAllCards::findType(_type);
addType(id);
}
void TypeTargetChooser::addType(int type)
{
types[nbtypes] = type;
nbtypes++;
}
bool TypeTargetChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (!TargetZoneChooser::canTarget(target,withoutProtections)) return false;
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(target))
{
for (int i = 0; i < nbtypes; i++)
{
if (card->hasSubtype(types[i])) return true;
if (card->data->basicAbilities[(int)Constants::CHANGELING])
{
if (!MTGAllCards::isSubtypeOfType(i,Subtypes::TYPE_CREATURE))
return false;
return true;
}
if(card->getLCName().size())
{
if (MTGAllCards::findType(card->getLCName()) == types[i])
return true;
if (MTGAllCards::findType(card->getName()) == types[i])
return true;
}
}
return false;
}
else if (Interruptible * action = dynamic_cast<Interruptible *>(target))
{
if (action->type == ACTION_SPELL && action->state == NOT_RESOLVED)
{
Spell * spell = (Spell *) action;
MTGCardInstance * card = spell->source;
for (int i = 0; i < nbtypes; i++)
{
if (card->hasSubtype(types[i])) return true;
if (MTGAllCards::findType(card->name) == types[i]) return true;
}
return false;
}
}
return false;
}
TypeTargetChooser * TypeTargetChooser::clone() const
{
TypeTargetChooser * a = NEW TypeTargetChooser(*this);
return a;
}
bool TypeTargetChooser ::equals(TargetChooser * tc)
{
TypeTargetChooser * ttc = dynamic_cast<TypeTargetChooser *> (tc);
if (!ttc)
return false;
if (nbtypes != ttc->nbtypes)
return false;
map<int,int> counts;
for (int i = 0; i < nbtypes; ++i)
{
counts[types[i]] +=1;
counts[ttc->types[i]] -=1;
}
for (int i = 0; i < nbtypes; ++i)
{
if (counts[types[i]] || counts[ttc->types[i]])
return false;
}
return TargetZoneChooser::equals(tc);
}
/**
A Target Chooser associated to a Card Descriptor object, for fine tuning of targets description
**/
DescriptorTargetChooser::DescriptorTargetChooser(GameObserver *observer, CardDescriptor * _cd, MTGCardInstance * card, int _maxtargets, bool other,bool targetMin) :
TargetZoneChooser(observer, card, _maxtargets, other,targetMin)
{
int default_zones[] = { MTGGameZone::MY_BATTLEFIELD, MTGGameZone::OPPONENT_BATTLEFIELD };
init(default_zones, 2);
cd = _cd;
}
DescriptorTargetChooser::DescriptorTargetChooser(GameObserver *observer, CardDescriptor * _cd, int * _zones, int nbzones, MTGCardInstance * card,
int _maxtargets, bool other,bool targetMin) :
TargetZoneChooser(observer, card, _maxtargets, other,targetMin)
{
if (nbzones == 0)
{
int default_zones[] = { MTGGameZone::MY_BATTLEFIELD, MTGGameZone::OPPONENT_BATTLEFIELD };
init(default_zones, 2);
}
else
{
init(_zones, nbzones);
}
cd = _cd;
}
bool DescriptorTargetChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (!TargetZoneChooser::canTarget(target,withoutProtections)) return false;
if (MTGCardInstance * _target = dynamic_cast<MTGCardInstance *>(target))
{
if (cd->match(_target))
return true;
}
else if (Interruptible * action = dynamic_cast<Interruptible *>(target))
{
if (action->type == ACTION_SPELL && action->state == NOT_RESOLVED)
{
Spell * spell = (Spell *) action;
MTGCardInstance * card = spell->source;
if (cd->match(card)) return true;
}
}
return false;
}
DescriptorTargetChooser::~DescriptorTargetChooser()
{
SAFE_DELETE(cd);
}
DescriptorTargetChooser * DescriptorTargetChooser::clone() const
{
DescriptorTargetChooser * a = NEW DescriptorTargetChooser(*this);
a->cd = NEW CardDescriptor(*cd);
return a;
}
bool DescriptorTargetChooser::equals(TargetChooser * tc)
{
DescriptorTargetChooser * dtc = dynamic_cast<DescriptorTargetChooser *> (tc);
if (!dtc)
return false;
//TODO Descriptors need to have an "equals" method too -_-
return TargetZoneChooser::equals(tc);
}
/* TargetzoneChooser targets everything in a given zone */
TargetZoneChooser::TargetZoneChooser(GameObserver *observer, MTGCardInstance * card, int _maxtargets, bool other,bool targetMin) :
TargetChooser(observer, card, _maxtargets, other,targetMin)
{
init(NULL, 0);
}
TargetZoneChooser::TargetZoneChooser(GameObserver *observer, int * _zones, int _nbzones, MTGCardInstance * card, int _maxtargets, bool other,bool targetMin) :
TargetChooser(observer, card, _maxtargets, other,targetMin)
{
init(_zones, _nbzones);
}
int TargetZoneChooser::init(int * _zones, int _nbzones)
{
for (int i = 0; i < _nbzones; i++)
{
zones[i] = _zones[i];
}
nbzones = _nbzones;
return nbzones;
}
int TargetZoneChooser::setAllZones()
{
int zones[] = { MTGGameZone::ALL_ZONES, };
init(zones, 1);
return 1;
}
bool TargetZoneChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (!TargetChooser::canTarget(target,withoutProtections)) return false;
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(target))
{
for (int i = 0; i < nbzones; i++)
{
if (zones[i] == MTGGameZone::ALL_ZONES) return true;
if (MTGGameZone::intToZone(observer, zones[i], source, card)->hasCard(card)) return true;
}
}
else if (Spell * spell = dynamic_cast<Spell *>(target))
{
DebugTrace("CHECKING Spell\n");
if (spell->state == NOT_RESOLVED)
{
MTGCardInstance * card = spell->source;
for (int i = 0; i < nbzones; i++)
if (MTGGameZone::intToZone(Owner->getObserver(), zones[i], source, card)->hasCard(card)) return true;
}
}
return false;
}
bool TargetZoneChooser::targetsZone(MTGGameZone * z)
{
for (int i = 0; i < nbzones; i++)
if (MTGGameZone::intToZone(Owner->getObserver(), zones[i], source) == z) return true;
return false;
}
bool TargetZoneChooser::targetsZone(MTGGameZone * z,MTGCardInstance * mSource)
{
if (mSource)
source = mSource;
for (int i = 0; i < nbzones; i++)
if (MTGGameZone::intToZone(source->owner->getObserver(), zones[i], source) == z) return true;
return false;
}
TargetZoneChooser * TargetZoneChooser::clone() const
{
TargetZoneChooser * a = NEW TargetZoneChooser(*this);
return a;
}
bool TargetZoneChooser::equals(TargetChooser * tc)
{
TargetZoneChooser * tzc = dynamic_cast<TargetZoneChooser *> (tc);
if (!tzc)
return false;
if (nbzones!= tzc->nbzones)
return false;
map<int,int> counts;
for (int i = 0; i < nbzones; ++i)
{
counts[zones[i]] +=1;
counts[tzc->zones[i]] -=1;
}
for (int i = 0; i < nbzones; ++i)
{
if (counts[zones[i]] || counts[tzc->zones[i]])
return false;
}
//TODO: ALL_ZONES should be equivalent to something actually targetting all zones...
return TargetChooser::equals(tc);
}
/* Player Target */
PlayerTargetChooser::PlayerTargetChooser(GameObserver *observer, MTGCardInstance * card, int _maxtargets, Player *p) :
TargetChooser(observer, card, _maxtargets), p(p)
{
}
bool PlayerTargetChooser::canTarget(Targetable * target, bool)
{
if (source && targetter)
{
if ((targetter->controller() != targetter->controller()->opponent())
&& (targetter->controller()->opponent()->game->inPlay->hasAbility(Constants::CONTROLLERSHROUD))
&& targetter->controller() != target)
return targetter->bypassTC;
if ((targetter->controller()->opponent()->game->inPlay->hasAbility(Constants::PLAYERSHROUD))
&& targetter->controller()->opponent() == target)
return targetter->bypassTC;
if ((targetter->controller()->game->inPlay->hasAbility(Constants::PLAYERSHROUD))
&& targetter->controller() == target)
return targetter->bypassTC;
}
Player * pTarget = dynamic_cast<Player *>(target);
return (pTarget && (!p || p == pTarget));
}
PlayerTargetChooser* PlayerTargetChooser::clone() const
{
PlayerTargetChooser * a = NEW PlayerTargetChooser(*this);
return a;
}
bool PlayerTargetChooser::equals(TargetChooser * tc)
{
PlayerTargetChooser * ptc = dynamic_cast<PlayerTargetChooser *> (tc);
if (!ptc)
return false;
if (p != ptc->p)
return false;
return TargetChooser::equals(tc);
}
/*Damageable Target */
bool DamageableTargetChooser::canTarget(Targetable * target,bool withoutProtections)
{
// TODO: get rid of common code with PlayerTargetChooser
if (source && targetter)
{
if ((targetter->controller() != targetter->controller()->opponent())
&& (targetter->controller()->opponent()->game->inPlay->hasAbility(Constants::CONTROLLERSHROUD))
&& targetter->controller() != target)
return false;
if ((targetter->controller()->opponent()->game->inPlay->hasAbility(Constants::PLAYERSHROUD))
&& targetter->controller()->opponent() == target)
return false;
if ((targetter->controller()->game->inPlay->hasAbility(Constants::PLAYERSHROUD))
&& targetter->controller() == target)
return false;
}
if (dynamic_cast<Player *>(target))
{
return true;
}
return TypeTargetChooser::canTarget(target,withoutProtections);
}
DamageableTargetChooser* DamageableTargetChooser::clone() const
{
DamageableTargetChooser * a = NEW DamageableTargetChooser(*this);
return a;
}
bool DamageableTargetChooser::equals(TargetChooser * tc)
{
DamageableTargetChooser * dtc = dynamic_cast<DamageableTargetChooser *> (tc);
if (!dtc)
return false;
return TypeTargetChooser::equals(tc);
}
/*Spell */
SpellTargetChooser::SpellTargetChooser(GameObserver *observer, MTGCardInstance * card, int _color, int _maxtargets, bool other,bool targetMin) :
TargetChooser(observer, card, _maxtargets, other,targetMin)
{
color = _color;
}
bool SpellTargetChooser::canTarget(Targetable * target,bool)
{
Spell * spell = dynamic_cast<Spell *>(target);
if (!spell)
return false;
if (spell->state == NOT_RESOLVED)
{
MTGCardInstance * card = spell->source;
if (card && (color == -1 || card->hasColor(color))) return true;
}
return false;
}
SpellTargetChooser* SpellTargetChooser::clone() const
{
SpellTargetChooser * a = NEW SpellTargetChooser(*this);
return a;
}
bool SpellTargetChooser::equals(TargetChooser * tc)
{
SpellTargetChooser * stc = dynamic_cast<SpellTargetChooser *> (tc);
if (!stc)
return false;
if (color != stc->color)
return false;
return TargetChooser::equals(tc);
}
/*Spell or Permanent */
SpellOrPermanentTargetChooser::SpellOrPermanentTargetChooser(GameObserver *observer, MTGCardInstance * card, int _color, int _maxtargets, bool other,bool targetMin) :
TargetZoneChooser(observer, card, _maxtargets, other,targetMin)
{
int default_zones[] = { MTGGameZone::MY_BATTLEFIELD, MTGGameZone::OPPONENT_BATTLEFIELD };
init(default_zones, 2);
color = _color;
}
bool SpellOrPermanentTargetChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance *>(target))
{
if (color == -1 || card->hasColor(color)) return TargetZoneChooser::canTarget(target,withoutProtections);
}
else if (Spell * spell = dynamic_cast<Spell *>(target))
{
if (spell->state == NOT_RESOLVED)
{
MTGCardInstance * card = spell->source;
if (card && (color == -1 || card->hasColor(color))) return true;
}
}
return false;
}
SpellOrPermanentTargetChooser* SpellOrPermanentTargetChooser::clone() const
{
SpellOrPermanentTargetChooser * a = NEW SpellOrPermanentTargetChooser(*this);
return a;
}
bool SpellOrPermanentTargetChooser::equals(TargetChooser * tc)
{
SpellOrPermanentTargetChooser * sptc = dynamic_cast<SpellOrPermanentTargetChooser *> (tc);
if (!sptc)
return false;
if (color != sptc->color)
return false;
return TargetZoneChooser::equals(tc);
}
/*Damage */
DamageTargetChooser::DamageTargetChooser(GameObserver *observer, MTGCardInstance * card, int _color, int _maxtargets, int _state) :
TargetChooser(observer, card, _maxtargets)
{
color = _color;
state = _state;
}
bool DamageTargetChooser::canTarget(Targetable * target, bool)
{
if ( Damage * damage = dynamic_cast<Damage *>(target))
{
if (damage->state == state || state == -1)
{
MTGCardInstance * card = damage->source;
if (card && (color == -1 || card->hasColor(color))) return true;
}
}
return false;
}
DamageTargetChooser* DamageTargetChooser::clone() const
{
DamageTargetChooser * a = NEW DamageTargetChooser(*this);
return a;
}
bool DamageTargetChooser::equals(TargetChooser * tc)
{
DamageTargetChooser * dtc = dynamic_cast<DamageTargetChooser *> (tc);
if (!dtc)
return false;
if (color != dtc->color || state != dtc->state)
return false;
return TargetChooser::equals(tc);
}
TriggerTargetChooser::TriggerTargetChooser(GameObserver *observer, int _triggerTarget)
: TargetChooser(observer)
{
triggerTarget = _triggerTarget;
target = NULL;
}
bool TriggerTargetChooser::targetsZone(MTGGameZone *)
{
return true;
}
bool TriggerTargetChooser::canTarget(Targetable * _target,bool)
{
//something is wrong with trigger[to] not allowing us to target stack.
if(Spell * spell = dynamic_cast<Spell *>(_target))
{
MTGCardInstance * card = spell->source;
if(card == target)
return true;
}
if (_target == target) return true;
return false;
}
TriggerTargetChooser * TriggerTargetChooser::clone() const
{
TriggerTargetChooser * a = NEW TriggerTargetChooser(*this);
return a;
}
bool TriggerTargetChooser::equals(TargetChooser * tc)
{
TriggerTargetChooser * ttc = dynamic_cast<TriggerTargetChooser *> (tc);
if (!ttc)
return false;
if (triggerTarget != ttc->triggerTarget)
return false;
return TargetChooser::equals(tc);
}
/*my curses */
bool myCursesChooser::canTarget(Targetable * target,bool)
{
for(unsigned int i = 0;i < source->controller()->curses.size();++i)
{
MTGCardInstance * compare = source->controller()->curses[i];
if(compare == dynamic_cast<MTGCardInstance*>(target))
return true;
}
return false;
}
myCursesChooser* myCursesChooser::clone() const
{
myCursesChooser * a = NEW myCursesChooser(*this);
return a;
}
bool myCursesChooser::equals(TargetChooser * tc)
{
myCursesChooser * dtc = dynamic_cast<myCursesChooser *> (tc);
if (!dtc)
return false;
return TypeTargetChooser::equals(tc);
}
/*display cards blockable by source */
bool BlockableChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance*>(target))
{
if(!card->isAttacker() || !source->canBlock(card))
return false;
bool lured = false;
MTGCardInstance * lurers = observer->currentPlayer->game->inPlay->findALurer();
if(lurers)
{
lured = true;
}
if(lured && card->controller()->inPlay()->hasAbility(Constants::LURE) && !card->has(Constants::LURE))
return false;
return true;
}
return TypeTargetChooser::canTarget(target,withoutProtections);
}
BlockableChooser* BlockableChooser::clone() const
{
BlockableChooser * a = NEW BlockableChooser(*this);
return a;
}
bool BlockableChooser::equals(TargetChooser * tc)
{
BlockableChooser * dtc = dynamic_cast<BlockableChooser *> (tc);
if (!dtc)
return false;
return TypeTargetChooser::equals(tc);
}
/*display cards pairable by source */
bool pairableChooser::canTarget(Targetable * target,bool)
{
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance*>(target))
{
if(card->myPair || card == source)
return false;
if(!card->isCreature() || !card->isInPlay(observer))
return false;
if(card->controller() != source->controller())
return false;
if(!card->has(Constants::soulbond) && !source->has(Constants::soulbond))
return false;
return true;
}
return false;
}
pairableChooser* pairableChooser::clone() const
{
pairableChooser * a = NEW pairableChooser(*this);
return a;
}
bool pairableChooser::equals(TargetChooser * tc)
{
pairableChooser * dtc = dynamic_cast<pairableChooser *> (tc);
if (!dtc)
return false;
return TypeTargetChooser::equals(tc);
}
//*Dredge targetchooser*//
bool dredgeChooser::canTarget(Targetable * target,bool)
{
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance*>(target))
{
if((card->data->dredgeAmount < 1) || (card->data->dredgeAmount > card->controller()->game->library->nb_cards))
return false;
if(card->currentZone == card->controller()->game->graveyard)
return true;
}
return false;
}
dredgeChooser* dredgeChooser::clone() const
{
dredgeChooser * a = NEW dredgeChooser(*this);
return a;
}
bool dredgeChooser::equals(TargetChooser * tc)
{
dredgeChooser * dtc = dynamic_cast<dredgeChooser *> (tc);
if (!dtc)
return false;
return TypeTargetChooser::equals(tc);
}
//-----------
//-----------
/*Proliferate Target */
bool ProliferateChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance*>(target))
{
if(card->counters && card->counters->counters.empty())
return false;
return true;
}
else if (Player * p = dynamic_cast<Player*>(target))
{
if(!p->poisonCount)
return false;
return true;
}
return TypeTargetChooser::canTarget(target,withoutProtections);
}
ProliferateChooser* ProliferateChooser::clone() const
{
ProliferateChooser * a = NEW ProliferateChooser(*this);
return a;
}
bool ProliferateChooser::equals(TargetChooser * tc)
{
ProliferateChooser * dtc = dynamic_cast<ProliferateChooser *> (tc);
if (!dtc)
return false;
return TypeTargetChooser::equals(tc);
}
/*parents or children Target */
bool ParentChildChooser::canTarget(Targetable * target,bool withoutProtections)
{
if (MTGCardInstance * card = dynamic_cast<MTGCardInstance*>(target))
{
if(type == 1)
{
if(!source->childrenCards.size())
return false;
for(unsigned int w = 0;w < source->childrenCards.size();w++)
{
MTGCardInstance * child = source->childrenCards[w];
if(child == card)
{
if(deeperTargeting)
{
if(!deeperTargeting->canTarget(child))
return false;
}
return true;
}
}
}
else
{
if(!source->parentCards.size())
return false;
for(unsigned int w = 0;w < source->parentCards.size();w++)
{
MTGCardInstance * parent = source->parentCards[w];
if(parent == card)
{
if(deeperTargeting)
{
if(!deeperTargeting->canTarget(parent))
return false;
}
return true;
}
}
}
return false;
}
return TypeTargetChooser::canTarget(target,withoutProtections);
}
ParentChildChooser* ParentChildChooser::clone() const
{
ParentChildChooser * a = NEW ParentChildChooser(*this);
return a;
}
bool ParentChildChooser::equals(TargetChooser * tc)
{
ParentChildChooser * dtc = dynamic_cast<ParentChildChooser *> (tc);
if (!dtc)
return false;
return TypeTargetChooser::equals(tc);
}
ParentChildChooser::~ParentChildChooser()
{
SAFE_DELETE(deeperTargeting);
}