Files
wagic/projects/mtg/src/AllAbilities.cpp
techdragon.nguyen@gmail.com 064dad3085 reverted ability/color parser for AATokenCreator.
fixed color parsing error for Transformer classes
2010-11-22 09:51:36 +00:00

1990 lines
50 KiB
C++

#include "PrecompiledHeader.h"
#include "AllAbilities.h"
//Activated Abilities
//Generic Activated Abilities
GenericActivatedAbility::GenericActivatedAbility(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap,
int limit, int restrictions, MTGGameZone * dest) :
ActivatedAbility(_id, card, _cost, restrictions, _tap), NestedAbility(a), limitPerTurn(limit), activeZone(dest)
{
counters = 0;
target = ability->target;
}
int GenericActivatedAbility::resolve()
{
counters++;
ManaCost * diff = abilityCost->Diff(cost);
source->X = diff->hasX();
SAFE_DELETE(diff);
//SAFE_DELETE(abilityCost); this line has been reported as a bug. removing it doesn't seem to break anything, although I didn't get any error in the test suite by leaving it either, so... leaving it for now as a comment, in case.
ability->target = target; //may have been updated...
if (ability) return ability->resolve();
return 0;
}
const char * GenericActivatedAbility::getMenuText()
{
if (ability) return ability->getMenuText();
return "Error";
}
int GenericActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
{
if (limitPerTurn && counters >= limitPerTurn) return 0;
return ActivatedAbility::isReactingToClick(card, mana);
}
void GenericActivatedAbility::Update(float dt)
{
if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_AFTER_EOT)
{
counters = 0;
}
ActivatedAbility::Update(dt);
}
int GenericActivatedAbility::testDestroy()
{
if (!activeZone) return ActivatedAbility::testDestroy();
if (activeZone->hasCard(source)) return 0;
return 1;
}
GenericActivatedAbility * GenericActivatedAbility::clone() const
{
GenericActivatedAbility * a = NEW GenericActivatedAbility(*this);
a->cost = NEW ManaCost();
a->cost->copy(cost);
a->ability = ability->clone();
return a;
}
GenericActivatedAbility::~GenericActivatedAbility()
{
SAFE_DELETE(ability);
}
//AA Alter Poison
AAAlterPoison::AAAlterPoison(int _id, MTGCardInstance * _source, Targetable * _target, int poison, ManaCost * _cost, int doTap,
int who) :
ActivatedAbilityTP(_id, _source, _target, _cost, doTap, who), poison(poison)
{
}
int AAAlterPoison::resolve()
{
Damageable * _target = (Damageable *) getTarget();
if (_target)
{
_target->poisonCount += poison;
}
return 0;
}
const char * AAAlterPoison::getMenuText()
{
return "Poison";
}
AAAlterPoison * AAAlterPoison::clone() const
{
AAAlterPoison * a = NEW AAAlterPoison(*this);
a->isClone = 1;
return a;
}
AAAlterPoison::~AAAlterPoison()
{
}
//Damage Prevent
AADamagePrevent::AADamagePrevent(int _id, MTGCardInstance * _source, Targetable * _target, int preventing, ManaCost * _cost,
int doTap, int who) :
ActivatedAbilityTP(_id, _source, _target, _cost, doTap, who), preventing(preventing)
{
aType = MTGAbility::STANDARD_PREVENT;
}
int AADamagePrevent::resolve()
{
Damageable * _target = (Damageable *) getTarget();
if (_target)
{
_target->preventable += preventing;
}
return 0;
}
const char * AADamagePrevent::getMenuText()
{
return "Prevent Damage";
}
AADamagePrevent * AADamagePrevent::clone() const
{
AADamagePrevent * a = NEW AADamagePrevent(*this);
a->isClone = 1;
return a;
}
AADamagePrevent::~AADamagePrevent()
{
}
//AADamager
AADamager::AADamager(int _id, MTGCardInstance * _source, Targetable * _target, WParsedInt * damage, ManaCost * _cost, int doTap,
int who) :
ActivatedAbilityTP(_id, _source, _target, _cost, doTap, who), damage(damage)
{
aType = MTGAbility::DAMAGER;
}
int AADamager::resolve()
{
Damageable * _target = (Damageable *) getTarget();
if (_target)
{
game->mLayers->stackLayer()->addDamage(source, _target, damage->getValue());
game->mLayers->stackLayer()->resolve();
return 1;
}
return 0;
}
const char * AADamager::getMenuText()
{
return "Damage";
}
AADamager * AADamager::clone() const
{
AADamager * a = NEW AADamager(*this);
a->damage = NEW WParsedInt(*(a->damage));
a->isClone = 1;
return a;
}
AADamager::~AADamager()
{
SAFE_DELETE(damage);
}
//AADepleter
AADepleter::AADepleter(int _id, MTGCardInstance * card, Targetable * _target, int nbcards, ManaCost * _cost, int _tap, int who) :
ActivatedAbilityTP(_id, card, _target, _cost, _tap, who), nbcards(nbcards)
{
}
int AADepleter::resolve()
{
Targetable * _target = getTarget();
Player * player;
if (_target)
{
if (_target->typeAsTarget() == TARGET_CARD)
{
player = ((MTGCardInstance *) _target)->controller();
}
else
{
player = (Player *) _target;
}
MTGLibrary * library = player->game->library;
for (int i = 0; i < nbcards; i++)
{
if (library->nb_cards) player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->graveyard);
}
}
return 1;
}
const char * AADepleter::getMenuText()
{
return "Deplete";
}
AADepleter * AADepleter::clone() const
{
AADepleter * a = NEW AADepleter(*this);
a->isClone = 1;
return a;
}
//AACopier
AACopier::AACopier(int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost) :
ActivatedAbility(_id, _source, _cost, 0, 0)
{
target = _target;
}
int AACopier::resolve()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target)
{
source->copy(_target);
return 1;
}
return 0;
}
const char * AACopier::getMenuText()
{
return "Copy";
}
AACopier * AACopier::clone() const
{
AACopier * a = NEW AACopier(*this);
a->isClone = 1;
return a;
}
//Counters
AACounter::AACounter(int id, MTGCardInstance * source, MTGCardInstance * target, const char * _name, int power, int toughness,
int nb, ManaCost * cost, int doTap) :
ActivatedAbility(id, source, cost, 0, doTap), nb(nb), power(power), toughness(toughness), name(_name)
{
this->target = target;
if (name.find("Level")) aType = MTGAbility::STANDARD_LEVELUP;
}
int AACounter::resolve()
{
if (target)
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (nb > 0)
{
for (int i = 0; i < nb; i++)
{
while (_target->next)
_target = _target->next;
_target->counters->addCounter(name.c_str(), power, toughness);
}
}
else
{
for (int i = 0; i < -nb; i++)
{
while (_target->next)
_target = _target->next;
_target->counters->removeCounter(name.c_str(), power, toughness);
}
}
return nb;
}
return 0;
}
const char* AACounter::getMenuText()
{
return "Counter";
}
AACounter * AACounter::clone() const
{
AACounter * a = NEW AACounter(*this);
a->isClone = 1;
return a;
}
// Fizzler
AAFizzler::AAFizzler(int _id, MTGCardInstance * card, Spell * _target, ManaCost * _cost, int _tap) :
ActivatedAbility(_id, card, _cost, 0, _tap)
{
target = _target;
}
int AAFizzler::resolve()
{
Spell * _target = (Spell *) target;
if (target && _target->source->has(Constants::NOFIZZLE)) return 0;
game->mLayers->stackLayer()->Fizzle(_target);
return 1;
}
const char * AAFizzler::getMenuText()
{
return "Fizzle";
}
AAFizzler* AAFizzler::clone() const
{
AAFizzler * a = NEW AAFizzler(*this);
a->isClone = 1;
return a;
}
// BanishCard implementations
AABanishCard::AABanishCard(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _banishmentType) :
ActivatedAbility(_id, _source, NULL), banishmentType(_banishmentType)
{
if (_target) target = _target;
}
const char * AABanishCard::getMenuText()
{
return "Send to graveyard";
}
int AABanishCard::resolve()
{
DebugTrace("This is not implemented!");
return 0;
}
AABanishCard * AABanishCard::clone() const
{
AABanishCard * a = NEW AABanishCard(*this);
a->isClone = 1;
return a;
}
// Bury
AABuryCard::AABuryCard(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _banishmentType) :
AABanishCard(_id, _source, _target, AABanishCard::BURY)
{
}
int AABuryCard::resolve()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target)
{
return _target->bury();
}
return 0;
}
const char * AABuryCard::getMenuText()
{
return "Bury";
}
AABuryCard * AABuryCard::clone() const
{
AABuryCard * a = NEW AABuryCard(*this);
a->isClone = 1;
return a;
}
// Destroy
AADestroyCard::AADestroyCard(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _banishmentType) :
AABanishCard(_id, _source, _target, AABanishCard::DESTROY)
{
}
int AADestroyCard::resolve()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target)
{
return _target->destroy();
}
return 0;
}
const char * AADestroyCard::getMenuText()
{
return "Destroy";
}
AADestroyCard * AADestroyCard::clone() const
{
AADestroyCard * a = NEW AADestroyCard(*this);
a->isClone = 1;
return a;
}
// Sacrifice
AASacrificeCard::AASacrificeCard(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _banishmentType) :
AABanishCard(_id, _source, _target, AABanishCard::SACRIFICE)
{
}
int AASacrificeCard::resolve()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target)
{
Player * p = _target->controller();
WEvent * e = NEW WEventCardSacrifice(_target);
GameObserver * game = GameObserver::GetInstance();
game->receiveEvent(e);
p->game->putInGraveyard(_target);
return 1;
}
return 0;
}
const char * AASacrificeCard::getMenuText()
{
return "Sacrifice";
}
AASacrificeCard * AASacrificeCard::clone() const
{
AASacrificeCard * a = NEW AASacrificeCard(*this);
a->isClone = 1;
return a;
}
// Discard
AADiscardCard::AADiscardCard(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _banishmentType) :
AABanishCard(_id, _source, _target, AABanishCard::DISCARD)
{
}
int AADiscardCard::resolve()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target)
{
Player * p = _target->controller();
WEvent * e = NEW WEventCardDiscard(_target);
GameObserver * game = GameObserver::GetInstance();
game->receiveEvent(e);
p->game->putInGraveyard(_target);
return 1;
}
return 0;
}
const char * AADiscardCard::getMenuText()
{
return "Discard";
}
AADiscardCard * AADiscardCard::clone() const
{
AADiscardCard * a = NEW AADiscardCard(*this);
a->isClone = 1;
return a;
}
AADrawer::AADrawer(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, WParsedInt * _nbcards, int _tap,
int who) :
ActivatedAbilityTP(_id, card, _target, _cost, _tap, who), nbcards(_nbcards)
{
aType = MTGAbility::STANDARD_DRAW;
nbcardAmount = nbcards->getValue();
}
int AADrawer::resolve()
{
Targetable * _target = getTarget();
Player * player;
if (_target)
{
if (_target->typeAsTarget() == TARGET_CARD)
{
player = ((MTGCardInstance *) _target)->controller();
}
else
{
player = (Player *) _target;
}
game->mLayers->stackLayer()->addDraw(player, nbcards->getValue());
game->mLayers->stackLayer()->resolve();
}
return 1;
}
const char * AADrawer::getMenuText()
{
return "Draw";
}
AADrawer * AADrawer::clone() const
{
AADrawer * a = NEW AADrawer(*this);
a->nbcards = NEW WParsedInt(*(a->nbcards));
a->isClone = 1;
return a;
}
AADrawer::~AADrawer()
{
SAFE_DELETE(nbcards);
}
// AAFrozen: Prevent a card from untapping during next untap phase
AAFrozen::AAFrozen(int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost, int doTap) :
ActivatedAbility(id, card, _cost, 0, doTap)
{
target = _target;
}
int AAFrozen::resolve()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target)
{
while (_target->next)
_target = _target->next; //This is for cards such as rampant growth
_target->frozen += 1;
}
return 1;
}
const char * AAFrozen::getMenuText()
{
return "Freeze";
}
AAFrozen * AAFrozen::clone() const
{
AAFrozen * a = NEW AAFrozen(*this);
a->isClone = 1;
return a;
}
//AALifer
AALifer::AALifer(int _id, MTGCardInstance * card, Targetable * _target, WParsedInt * life, ManaCost * _cost, int _tap, int who) :
ActivatedAbilityTP(_id, card, _target, _cost, _tap, who), life(life)
{
}
int AALifer::resolve()
{
Damageable * _target = (Damageable *) getTarget();
if (_target)
{
if (_target->type_as_damageable == DAMAGEABLE_MTGCARDINSTANCE)
{
_target = ((MTGCardInstance *) _target)->controller();
}
_target->life += life->getValue();
}
return 1;
}
const char * AALifer::getMenuText()
{
return "Life";
}
AALifer * AALifer::clone() const
{
AALifer * a = NEW AALifer(*this);
a->life = NEW WParsedInt(*(a->life));
a->isClone = 1;
return a;
}
AALifer::~AALifer()
{
SAFE_DELETE(life);
}
//Lifeset
AALifeSet::AALifeSet(int _id, MTGCardInstance * _source, Targetable * _target, WParsedInt * life, ManaCost * _cost, int doTap,
int who) :
ActivatedAbilityTP(_id, _source, _target, _cost, doTap, who), life(life)
{
}
int AALifeSet::resolve()
{
Damageable * _target = (Damageable *) getTarget();
if (_target)
{
if (_target->type_as_damageable == DAMAGEABLE_MTGCARDINSTANCE)
{
_target = ((MTGCardInstance *) _target)->controller();
}
_target->life = life->getValue();
}
return 0;
}
const char * AALifeSet::getMenuText()
{
return "Set Life";
}
AALifeSet * AALifeSet::clone() const
{
AALifeSet * a = NEW AALifeSet(*this);
a->life = NEW WParsedInt(*(a->life));
a->isClone = 1;
return a;
}
AALifeSet::~AALifeSet()
{
SAFE_DELETE(life);
}
//AACloner
//cloning...this makes a token thats a copy of the target.
AACloner::AACloner(int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost, int who,
string abilitiesStringList) :
ActivatedAbility(_id, _source, _cost, 0, 0), who(who)
{
target = _target;
source = _source;
if ( abilitiesStringList.size() > 0 )
{
PopulateAbilityIndexVector(awith, abilitiesStringList);
PopulateColorIndexVector(colors, abilitiesStringList);
}
}
int AACloner::resolve()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target)
{
MTGCardInstance * myClone = NULL;
MTGCard* clone = (_target->isToken ? _target : GameApp::collection->getCardById(_target->getId()));
if (who != 1) myClone = NEW MTGCardInstance(clone, source->controller()->game);
if (who == 1) myClone = NEW MTGCardInstance(clone, source->controller()->opponent()->game);
if (who != 1)
source->controller()->game->temp->addCard(myClone);
else
source->controller()->opponent()->game->temp->addCard(myClone);
Spell * spell = NEW Spell(myClone);
spell->resolve();
spell->source->isToken = 1;
spell->source->fresh = 1;
list<int>::iterator it;
for (it = awith.begin(); it != awith.end(); it++)
{
spell->source->basicAbilities[*it] = 1;
}
for (it = colors.begin(); it != colors.end(); it++)
{
spell->source->setColor(*it);
}
delete spell;
return 1;
}
return 0;
}
const char * AACloner::getMenuText()
{
if (who == 1) return "Clone For Opponent";
return "Clone";
}
ostream& AACloner::toString(ostream& out) const
{
out << "AACloner ::: with : ?" // << abilities
<< " (";
return ActivatedAbility::toString(out) << ")";
}
AACloner * AACloner::clone() const
{
AACloner * a = NEW AACloner(*this);
a->isClone = 1;
return a;
}
AACloner::~AACloner()
{
}
// More Land - allow more lands to be played on a turn
AAMoreLandPlz::AAMoreLandPlz(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, WParsedInt * _additional,
int _tap, int who) :
ActivatedAbilityTP(_id, card, _target, _cost, _tap, who), additional(_additional)
{
}
int AAMoreLandPlz::resolve()
{
Targetable * _target = getTarget();
Player * player;
if (_target)
{
if (_target->typeAsTarget() == TARGET_CARD)
{
player = ((MTGCardInstance *) _target)->controller();
}
else
{
player = (Player *) _target;
}
player->canPutLandsIntoPlay += additional->getValue();
}
return 1;
}
const char * AAMoreLandPlz::getMenuText()
{
return "Additional Lands";
}
AAMoreLandPlz * AAMoreLandPlz::clone() const
{
AAMoreLandPlz * a = NEW AAMoreLandPlz(*this);
a->additional = NEW WParsedInt(*(a->additional));
a->isClone = 1;
return a;
}
AAMoreLandPlz::~AAMoreLandPlz()
{
SAFE_DELETE(additional);
}
//AAMover
AAMover::AAMover(int _id, MTGCardInstance * _source, MTGCardInstance * _target, string dest, ManaCost * _cost, int doTap) :
ActivatedAbility(_id, _source, _cost, 0, doTap), destination(dest)
{
if (_target) target = _target;
}
MTGGameZone * AAMover::destinationZone()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
return MTGGameZone::stringToZone(destination, source, _target);
}
int AAMover::resolve()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (target)
{
Player* p = _target->controller();
if (p)
{
GameObserver * g = GameObserver::GetInstance();
MTGGameZone * fromZone = _target->getCurrentZone();
MTGGameZone * destZone = destinationZone();
//inplay is a special zone !
for (int i = 0; i < 2; i++)
{
if (destZone == g->players[i]->game->inPlay && fromZone != g->players[i]->game->inPlay && fromZone
!= g->players[i]->opponent()->game->inPlay)
{
MTGCardInstance * copy = g->players[i]->game->putInZone(_target, fromZone, g->players[i]->game->temp);
Spell * spell = NEW Spell(copy);
spell->resolve();
delete spell;
return 1;
}
}
p->game->putInZone(_target, fromZone, destZone);
return 1;
}
}
return 0;
}
const char * AAMover::getMenuText()
{
return "Move";
}
AAMover * AAMover::clone() const
{
AAMover * a = NEW AAMover(*this);
a->isClone = 1;
return a;
}
// No Creatures
AANoCreatures::AANoCreatures(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, int _tap, int who) :
ActivatedAbilityTP(_id, card, _target, _cost, _tap, who)
{
}
int AANoCreatures::resolve()
{
Targetable * _target = getTarget();
Player * player;
if (_target)
{
if (_target->typeAsTarget() == TARGET_CARD)
{
player = ((MTGCardInstance *) _target)->controller();
}
else
{
player = (Player *) _target;
}
player->nocreatureinstant = 1;
}
return 1;
}
const char * AANoCreatures::getMenuText()
{
return "No Creatures!";
}
AANoCreatures * AANoCreatures::clone() const
{
AANoCreatures * a = NEW AANoCreatures(*this);
a->isClone = 1;
return a;
}
// AA No Spells
AANoSpells::AANoSpells(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, int _tap, int who) :
ActivatedAbilityTP(_id, card, _target, _cost, _tap, who)
{
}
int AANoSpells::resolve()
{
Targetable * _target = getTarget();
Player * player;
if (_target)
{
if (_target->typeAsTarget() == TARGET_CARD)
{
player = ((MTGCardInstance *) _target)->controller();
}
else
{
player = (Player *) _target;
}
player->nospellinstant = 1;
}
return 1;
}
const char * AANoSpells::getMenuText()
{
return "No Spells!";
}
AANoSpells * AANoSpells::clone() const
{
AANoSpells * a = NEW AANoSpells(*this);
a->isClone = 1;
return a;
}
//OnlyOne
AAOnlyOne::AAOnlyOne(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, int _tap, int who) :
ActivatedAbilityTP(_id, card, _target, _cost, _tap, who)
{
}
int AAOnlyOne::resolve()
{
Targetable * _target = getTarget();
Player * player;
if (_target)
{
if (_target->typeAsTarget() == TARGET_CARD)
{
player = ((MTGCardInstance *) _target)->controller();
}
else
{
player = (Player *) _target;
}
player->onlyoneinstant = 1;
}
return 1;
}
const char * AAOnlyOne::getMenuText()
{
return "Only One Spell!";
}
AAOnlyOne * AAOnlyOne::clone() const
{
AAOnlyOne * a = NEW AAOnlyOne(*this);
a->isClone = 1;
return a;
}
//Random Discard
AARandomDiscarder::AARandomDiscarder(int _id, MTGCardInstance * card, Targetable * _target, int nbcards, ManaCost * _cost,
int _tap, int who) :
ActivatedAbilityTP(_id, card, _target, _cost, _tap, who), nbcards(nbcards)
{
}
int AARandomDiscarder::resolve()
{
Targetable * _target = getTarget();
Player * player;
if (_target)
{
if (_target->typeAsTarget() == TARGET_CARD)
{
player = ((MTGCardInstance *) _target)->controller();
}
else
{
player = (Player *) _target;
}
for (int i = 0; i < nbcards; i++)
{
player->game->discardRandom(player->game->hand, source);
}
}
return 1;
}
const char * AARandomDiscarder::getMenuText()
{
return "Discard Random";
}
AARandomDiscarder * AARandomDiscarder::clone() const
{
AARandomDiscarder * a = NEW AARandomDiscarder(*this);
a->isClone = 1;
return a;
}
// Shuffle
AAShuffle::AAShuffle(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, int _tap, int who) :
ActivatedAbilityTP(_id, card, _target, _cost, _tap, who)
{
}
int AAShuffle::resolve()
{
Targetable * _target = getTarget();
Player * player;
if (_target)
{
if (_target->typeAsTarget() == TARGET_CARD)
{
player = ((MTGCardInstance *) _target)->controller();
}
else
{
player = (Player *) _target;
}
MTGLibrary * library = player->game->library;
library->shuffle();
}
return 1;
}
const char * AAShuffle::getMenuText()
{
return "Shuffle";
}
AAShuffle * AAShuffle::clone() const
{
AAShuffle * a = NEW AAShuffle(*this);
a->isClone = 1;
return a;
}
//Tapper
AATapper::AATapper(int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost, int doTap) :
ActivatedAbility(id, card, _cost, 0, doTap)
{
target = _target;
}
int AATapper::resolve()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target)
{
while (_target->next)
_target = _target->next; //This is for cards such as rampant growth
_target->tap();
}
return 1;
}
const char * AATapper::getMenuText()
{
return "Tap";
}
AATapper * AATapper::clone() const
{
AATapper * a = NEW AATapper(*this);
a->isClone = 1;
return a;
}
//AA Untapper
AAUntapper::AAUntapper(int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost, int doTap) :
ActivatedAbility(id, card, _cost, 0, doTap)
{
target = _target;
}
int AAUntapper::resolve()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target)
{
while (_target->next)
_target = _target->next; //This is for cards such as rampant growth
_target->untap();
}
return 1;
}
const char * AAUntapper::getMenuText()
{
return "Untap";
}
AAUntapper * AAUntapper::clone() const
{
AAUntapper * a = NEW AAUntapper(*this);
a->isClone = 1;
return a;
}
AAWhatsMax::AAWhatsMax(int id, MTGCardInstance * card, MTGCardInstance * source, ManaCost * _cost, int doTap, int value) :
ActivatedAbility(id, card, _cost, 0, doTap), value(value)
{
}
int AAWhatsMax::resolve()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (source)
{
source->MaxLevelUp = value;
}
return 1;
}
AAWhatsMax * AAWhatsMax::clone() const
{
AAWhatsMax * a = NEW AAWhatsMax(*this);
a->isClone = 1;
return a;
}
// Win Game
AAWinGame::AAWinGame(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, int _tap, int who) :
ActivatedAbilityTP(_id, card, _target, _cost, _tap, who)
{
}
int AAWinGame::resolve()
{
Damageable * _target = (Damageable *) getTarget();
if (_target)
{
if (_target->type_as_damageable == DAMAGEABLE_MTGCARDINSTANCE)
{
_target = ((MTGCardInstance *) _target)->controller();
}
int cantlosers = 0;
MTGGameZone * z = ((Player *) _target)->opponent()->game->inPlay;
int nbcards = z->nb_cards;
for (int i = 0; i < nbcards; i++)
{
MTGCardInstance * c = z->cards[i];
if (c->has(Constants::CANTLOSE))
{
cantlosers++;
}
}
MTGGameZone * k = ((Player *) _target)->game->inPlay;
int onbcards = k->nb_cards;
for (int m = 0; m < onbcards; ++m)
{
MTGCardInstance * e = k->cards[m];
if (e->has(Constants::CANTWIN))
{
cantlosers++;
}
}
if (cantlosers < 1)
{
game->gameOver = ((Player *) _target)->opponent();
}
}
return 1;
}
const char * AAWinGame::getMenuText()
{
return "Win Game";
}
AAWinGame * AAWinGame::clone() const
{
AAWinGame * a = NEW AAWinGame(*this);
a->isClone = 1;
return a;
}
//Generic Abilities
//May Abilities
MayAbility::MayAbility(int _id, MTGAbility * _ability, MTGCardInstance * _source, bool must) :
MTGAbility(_id, _source), NestedAbility(_ability), must(must)
{
triggered = 0;
mClone = NULL;
}
void MayAbility::Update(float dt)
{
MTGAbility::Update(dt);
if (!triggered)
{
triggered = 1;
if (TargetAbility * ta = dynamic_cast<TargetAbility *>(ability))
{
if (!ta->tc->validTargetsExist()) return;
}
game->mLayers->actionLayer()->setMenuObject(source, must);
game->mLayers->stackLayer()->setIsInterrupting(source->controller());
}
}
const char * MayAbility::getMenuText()
{
return ability->getMenuText();
}
int MayAbility::testDestroy()
{
if (!triggered) return 0;
if (game->mLayers->actionLayer()->menuObject) return 0;
if (game->mLayers->actionLayer()->getIndexOf(mClone) != -1) return 0;
return 1;
}
int MayAbility::isReactingToTargetClick(Targetable * card)
{
if (card == source) return 1;
return 0;
}
int MayAbility::reactToTargetClick(Targetable * object)
{
mClone = ability->clone();
mClone->addToGame();
mClone->forceDestroy = 1;
return mClone->reactToTargetClick(object);
}
MayAbility * MayAbility::clone() const
{
MayAbility * a = NEW MayAbility(*this);
a->ability = ability->clone();
a->isClone = 1;
return a;
}
MayAbility::~MayAbility()
{
SAFE_DELETE(ability);
}
//MultiAbility : triggers several actions for a cost
MultiAbility::MultiAbility(int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, int _tap) :
ActivatedAbility(_id, card, _cost, 0, _tap)
{
if (_target) target = _target;
}
int MultiAbility::Add(MTGAbility * ability)
{
abilities.push_back(ability);
return 1;
}
int MultiAbility::resolve()
{
vector<int>::size_type sz = abilities.size();
for (unsigned int i = 0; i < sz; i++)
{
if (abilities[i] == NULL) continue;
Targetable * backup = abilities[i]->target;
if (target && target != source && abilities[i]->target == abilities[i]->source) abilities[i]->target = target;
abilities[i]->resolve();
abilities[i]->target = backup;
}
return 1;
}
const char * MultiAbility::getMenuText()
{
if (abilities.size()) return abilities[0]->getMenuText();
return "";
}
MultiAbility * MultiAbility::clone() const
{
MultiAbility * a = NEW MultiAbility(*this);
a->isClone = 1;
return a;
}
MultiAbility::~MultiAbility()
{
if (!isClone)
{
vector<int>::size_type sz = abilities.size();
for (size_t i = 0; i < sz; i++)
{
SAFE_DELETE(abilities[i]);
}
}
abilities.clear();
}
//Generic Target Ability
GenericTargetAbility::GenericTargetAbility(int _id, MTGCardInstance * _source, TargetChooser * _tc, MTGAbility * a,
ManaCost * _cost, int _tap, int limit, int restrictions, MTGGameZone * dest) :
TargetAbility(_id, _source, _tc, _cost, restrictions, _tap), limitPerTurn(limit), activeZone(dest)
{
ability = a;
MTGAbility * core = AbilityFactory::getCoreAbility(a);
if (dynamic_cast<AACopier *> (core)) tc->other = true; //http://code.google.com/p/wagic/issues/detail?id=209 (avoid inifinite loop)
counters = 0;
}
const char * GenericTargetAbility::getMenuText()
{
if (!ability) return "Error";
MTGAbility * core = AbilityFactory::getCoreAbility(ability);
if (AAMover * move = dynamic_cast<AAMover *>(core))
{
MTGGameZone * dest = move->destinationZone();
GameObserver * g = GameObserver::GetInstance();
for (int i = 0; i < 2; i++)
{
if (dest == g->players[i]->game->hand && tc->targetsZone(g->players[i]->game->inPlay))
{
return "Bounce";
}
else if (dest == g->players[i]->game->hand && tc->targetsZone(g->players[i]->game->graveyard))
{
return "Reclaim";
}
else if (dest == g->players[i]->game->graveyard && tc->targetsZone(g->players[i]->game->inPlay))
{
return "Sacrifice";
}
else if (dest == g->players[i]->game->library && tc->targetsZone(g->players[i]->game->graveyard))
{
return "Recycle";
}
else if (dest == g->players[i]->game->battlefield && tc->targetsZone(g->players[i]->game->graveyard))
{
return "Reanimate";
}
else if (dest == g->players[i]->game->library)
{
return "Put in Library";
}
else if (dest == g->players[i]->game->inPlay)
{
return "Put in Play";
}
else if (dest == g->players[i]->game->graveyard && tc->targetsZone(g->players[i]->game->hand))
{
return "Discard";
}
else if (dest == g->players[i]->game->exile)
{
return "Exile";
}
else if (tc->targetsZone(g->players[i]->game->library))
{
return "Fetch";
}
else if (dest == g->players[i]->game->hand && tc->targetsZone(g->opponent()->game->hand))
{
return "Steal";
}
else if (dest == g->players[i]->game->graveyard && tc->targetsZone(g->opponent()->game->hand))
{
return "Opponent Discards";
}
}
}
return ability->getMenuText();
}
int GenericTargetAbility::resolve()
{
counters++;
return TargetAbility::resolve();
}
int GenericTargetAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
{
if (limitPerTurn && counters >= limitPerTurn) return 0;
return TargetAbility::isReactingToClick(card, mana);
}
void GenericTargetAbility::Update(float dt)
{
if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_AFTER_EOT)
{
counters = 0;
}
TargetAbility::Update(dt);
}
int GenericTargetAbility::testDestroy()
{
if (!activeZone) return TargetAbility::testDestroy();
if (activeZone->hasCard(source)) return 0;
return 1;
}
GenericTargetAbility * GenericTargetAbility::clone() const
{
GenericTargetAbility * a = NEW GenericTargetAbility(*this);
a->ability = ability->clone();
a->cost = NEW ManaCost();
a->cost->copy(cost);
if (tc) a->tc = tc->clone();
return a;
}
GenericTargetAbility::~GenericTargetAbility()
{
SAFE_DELETE(ability);
}
//Alter Cost
AAlterCost::AAlterCost(int id, MTGCardInstance * source, MTGCardInstance * target, int amount, int type) :
MTGAbility(id, source, target), amount(amount), type(type)
{
MTGCardInstance * _target = (MTGCardInstance *) target;
}
int AAlterCost::addToGame()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (amount < 0)
{
amount = abs(amount);
if (_target->getManaCost()->hasColor(type))
{
if (_target->getManaCost()->getConvertedCost() >= 1)
{
_target->getManaCost()->remove(type, amount);
if (_target->getManaCost()->alternative > 0)
{
_target->getManaCost()->alternative->remove(type, amount);
}
if (_target->getManaCost()->BuyBack > 0)
{
_target->getManaCost()->BuyBack->remove(type, amount);
}
}
}
}
else
{
_target->getManaCost()->add(type, amount);
if (_target->getManaCost()->alternative > 0)
{
_target->getManaCost()->alternative->add(type, amount);
}
if (_target->getManaCost()->BuyBack > 0)
{
_target->getManaCost()->BuyBack->add(type, amount);
}
}
return MTGAbility::addToGame();
}
AAlterCost * AAlterCost::clone() const
{
AAlterCost * a = NEW AAlterCost(*this);
a->isClone = 1;
return a;
}
AAlterCost::~AAlterCost()
{
}
// ATransformer
ATransformer::ATransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities) :
MTGAbility(id, source, target)
{
MTGCardInstance * _target = (MTGCardInstance *) target;
PopulateAbilityIndexVector(abilities, sabilities);
PopulateColorIndexVector(colors, sabilities);
remove = false;
if (stypes == "removesubtypes") remove = true;
if (stypes == "allsubtypes" || stypes == "removesubtypes")
{
for (int i = Subtypes::LAST_TYPE + 1;; i++)
{
string s = Subtypes::subtypesList->find(i);
{
if (s == "") break;
if (s.find(" ") != string::npos) continue;
if (s == "Nothing" || s == "Swamp" || s == "Plains" || s == "Mountain" || s == "Forest" || s == "Island" || s
== "Shrine" || s == "Basic" || s == "Colony" || s == "Desert" || s == "Dismiss" || s == "Equipment" || s
== "Everglades" || s == "Grasslands" || s == "Lair" || s == "Level" || s == "Levelup" || s == "Mine" || s
== "Oasis" || s == "World" || s == "Aura")
{//dont add "nothing" or land type to this card.
}
else
{
types.push_back(i);
}
}
}
}
else
{
PopulateSubtypesIndexVector(types, stypes);
}
}
int ATransformer::addToGame()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target)
{
while (_target->next)
_target = _target->next;
for (int j = 0; j < Constants::MTG_NB_COLORS; j++)
{
if (_target->hasColor(j)) oldcolors.push_back(j);
}
for (int j = Subtypes::LAST_TYPE + 1;; j++)
{
string otypes = Subtypes::subtypesList->find(j);
if (otypes == "") break;
if (otypes.find(" ") != string::npos) continue;
if (_target->hasSubtype(j))
{
oldtypes.push_back(j);
}
}
list<int>::iterator it;
for (it = colors.begin(); it != colors.end(); it++)
{
_target->setColor(0, 1);
}
for (it = types.begin(); it != types.end(); it++)
{
if (remove == true)
{
_target->removeType(*it);
}
else
{
_target->addType(*it);
}
}
for (it = colors.begin(); it != colors.end(); it++)
{
_target->setColor(*it);
}
for (it = abilities.begin(); it != abilities.end(); it++)
{
_target->basicAbilities[*it]++;
}
for (it = oldcolors.begin(); it != oldcolors.end(); it++)
{
}
}
return MTGAbility::addToGame();
}
int ATransformer::destroy()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target)
{
while (_target->next)
_target = _target->next;
list<int>::iterator it;
for (it = types.begin(); it != types.end(); it++)
{
if (remove == false) _target->removeType(*it);
}
for (it = colors.begin(); it != colors.end(); it++)
{
_target->removeColor(*it);
}
for (it = abilities.begin(); it != abilities.end(); it++)
{
_target->basicAbilities[*it]--;
}
for (it = oldcolors.begin(); it != oldcolors.end(); it++)
{
_target->setColor(*it);
}
if (remove == true)
{
for (it = oldtypes.begin(); it != oldtypes.end(); it++)
{
if (!_target->hasSubtype(*it)) _target->addType(*it);
}
}
}
return 1;
}
const char * ATransformer::getMenuText()
{
return "Transform";
}
ATransformer * ATransformer::clone() const
{
ATransformer * a = NEW ATransformer(*this);
a->isClone = 1;
return a;
}
ATransformer::~ATransformer()
{
}
// AForeverTransformer
AForeverTransformer::AForeverTransformer(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes,
string sabilities) :
MTGAbility(id, source, target)
{
aType = MTGAbility::STANDARD_BECOMES;
MTGCardInstance * _target = (MTGCardInstance *) target;
PopulateAbilityIndexVector(abilities, sabilities);
PopulateColorIndexVector(colors, sabilities);
PopulateSubtypesIndexVector(types, stypes);
}
int AForeverTransformer::addToGame()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
if (_target)
{
while (_target->next)
_target = _target->next;
list<int>::iterator it;
for (it = colors.begin(); it != colors.end(); it++)
{
_target->setColor(0, 1);
}
for (it = types.begin(); it != types.end(); it++)
{
_target->addType(*it);
}
for (it = colors.begin(); it != colors.end(); it++)
{
_target->setColor(*it);
}
for (it = abilities.begin(); it != abilities.end(); it++)
{
_target->basicAbilities[*it]++;
}
}
return MTGAbility::addToGame();
}
const char * AForeverTransformer::getMenuText()
{
return "Transform";
}
AForeverTransformer * AForeverTransformer::clone() const
{
AForeverTransformer * a = NEW AForeverTransformer(*this);
a->isClone = 1;
return a;
}
AForeverTransformer::~AForeverTransformer()
{
}
//ATransformerUEOT
ATransformerUEOT::ATransformerUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities) :
InstantAbility(id, source, target)
{
ability = NEW ATransformer(id, source, target, types, abilities);
aType = MTGAbility::STANDARD_BECOMES;
}
int ATransformerUEOT::resolve()
{
ATransformer * a = ability->clone();
GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source, (Damageable *) (this->target), a);
wrapper->addToGame();
return 1;
}
const char * ATransformerUEOT::getMenuText()
{
return "Transform";
}
ATransformerUEOT * ATransformerUEOT::clone() const
{
ATransformerUEOT * a = NEW ATransformerUEOT(*this);
a->ability = this->ability->clone();
a->isClone = 1;
return a;
}
ATransformerUEOT::~ATransformerUEOT()
{
SAFE_DELETE(ability);
}
// ATransformerFOREVER
ATransformerFOREVER::ATransformerFOREVER(int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities) :
InstantAbility(id, source, target)
{
ability = NEW AForeverTransformer(id, source, target, types, abilities);
aType = MTGAbility::STANDARD_BECOMES;
}
int ATransformerFOREVER::resolve()
{
AForeverTransformer * a = ability->clone();
GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source, (Damageable *) (this->target), a);
wrapper->addToGame();
return 1;
}
const char * ATransformerFOREVER::getMenuText()
{
return "Transform";
}
ATransformerFOREVER * ATransformerFOREVER::clone() const
{
ATransformerFOREVER * a = NEW ATransformerFOREVER(*this);
a->ability = this->ability->clone();
a->isClone = 1;
return a;
}
ATransformerFOREVER::~ATransformerFOREVER()
{
SAFE_DELETE(ability);
}
// ASwapPTUEOT
ASwapPTUEOT::ASwapPTUEOT(int id, MTGCardInstance * source, MTGCardInstance * target) :
InstantAbility(id, source, target)
{
ability = NEW ASwapPT(id, source, target);
}
int ASwapPTUEOT::resolve()
{
ASwapPT * a = ability->clone();
GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source, (Damageable *) (this->target), a);
wrapper->addToGame();
return 1;
}
ASwapPTUEOT * ASwapPTUEOT::clone() const
{
ASwapPTUEOT * a = NEW ASwapPTUEOT(*this);
a->ability = this->ability->clone();
a->isClone = 1;
return a;
}
ASwapPTUEOT::~ASwapPTUEOT()
{
SAFE_DELETE(ability);
}
// ABecomes
ABecomes::ABecomes(int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, WParsedPT * wppt, string sabilities) :
MTGAbility(id, source, target), wppt(wppt)
{
aType = MTGAbility::STANDARD_BECOMES;
PopulateAbilityIndexVector(abilities, sabilities);
PopulateColorIndexVector(colors, sabilities);
PopulateSubtypesIndexVector(types, stypes);
}
int ABecomes::addToGame()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
list<int>::iterator it;
for (it = types.begin(); it != types.end(); it++)
{
_target->addType(*it);
}
for (it = colors.begin(); it != colors.end(); it++)
{
_target->setColor(*it);
}
for (it = abilities.begin(); it != abilities.end(); it++)
{
_target->basicAbilities[*it]++;
}
if (wppt)
{
_target->power = wppt->power.getValue();
_target->toughness = wppt->toughness.getValue();
_target->life = _target->toughness;
}
return MTGAbility::addToGame();
}
int ABecomes::destroy()
{
MTGCardInstance * _target = (MTGCardInstance *) target;
list<int>::iterator it;
for (it = types.begin(); it != types.end(); it++)
{
_target->removeType(*it);
}
for (it = colors.begin(); it != colors.end(); it++)
{
_target->removeColor(*it);
}
for (it = abilities.begin(); it != abilities.end(); it++)
{
_target->basicAbilities[*it]--;
}
return 1;
}
const char * ABecomes::getMenuText()
{
string s = menu;
sprintf(menuText, "Becomes %s", s.c_str());
return menuText;
}
ABecomes * ABecomes::clone() const
{
ABecomes * a = NEW ABecomes(*this);
if (a->wppt) a->wppt = NEW WParsedPT(*(a->wppt));
a->isClone = 1;
return a;
}
ABecomes::~ABecomes()
{
SAFE_DELETE (wppt);
}
// ABecomes
// ABecomesUEOT
ABecomesUEOT::ABecomesUEOT(int id, MTGCardInstance * source, MTGCardInstance * target, string types, WParsedPT * wpt,
string abilities) :
InstantAbility(id, source, target)
{
ability = NEW ABecomes(id, source, target, types, wpt, abilities);
aType = MTGAbility::STANDARD_BECOMES;
}
int ABecomesUEOT::resolve()
{
ABecomes * a = ability->clone();
GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source, (Damageable *) (this->target), a);
wrapper->addToGame();
return 1;
}
const char * ABecomesUEOT::getMenuText()
{
return ability->getMenuText();
}
ABecomesUEOT * ABecomesUEOT::clone() const
{
ABecomesUEOT * a = NEW ABecomesUEOT(*this);
a->ability = this->ability->clone();
a->isClone = 1;
return a;
}
ABecomesUEOT::~ABecomesUEOT()
{
SAFE_DELETE(ability);
}
//APreventDamageTypes
APreventDamageTypes::APreventDamageTypes(int id, MTGCardInstance * source, string to, string from, int type) :
MTGAbility(id, source), to(to), from(from), type(type)
{
re = NULL;
}
int APreventDamageTypes::addToGame()
{
if (re)
{
DebugTrace("FATAL:re shouldn't be already set in APreventDamageTypes\n");
return 0;
}
TargetChooserFactory tcf;
TargetChooser *toTc = tcf.createTargetChooser(to, source, this);
if (toTc) toTc->targetter = NULL;
TargetChooser *fromTc = tcf.createTargetChooser(from, source, this);
if (fromTc) fromTc->targetter = NULL;
if (type != 1 && type != 2)
{//not adding this creates a memory leak.
re = NEW REDamagePrevention(this, fromTc, toTc, -1, false, DAMAGE_COMBAT);
}
else if (type == 1)
{
re = NEW REDamagePrevention(this, fromTc, toTc, -1, false, DAMAGE_ALL_TYPES);
}
else if (type == 2)
{
re = NEW REDamagePrevention(this, fromTc, toTc, -1, false, DAMAGE_OTHER);
}
game->replacementEffects->add(re);
return MTGAbility::addToGame();
}
int APreventDamageTypes::destroy()
{
game->replacementEffects->remove(re);
SAFE_DELETE(re);
return 1;
}
APreventDamageTypes * APreventDamageTypes::clone() const
{
APreventDamageTypes * a = NEW APreventDamageTypes(*this);
a->isClone = 1;
return a;
}
APreventDamageTypes::~APreventDamageTypes()
{
SAFE_DELETE(re);
}
//APreventDamageTypesUEOT
APreventDamageTypesUEOT::APreventDamageTypesUEOT(int id, MTGCardInstance * source, string to, string from, int type) :
InstantAbility(id, source)
{
ability = NEW APreventDamageTypes(id, source, to, from, type);
}
int APreventDamageTypesUEOT::resolve()
{
APreventDamageTypes * a = ability->clone();
GenericInstantAbility * wrapper = NEW GenericInstantAbility(1, source, (Damageable *) (this->target), a);
wrapper->addToGame();
return 1;
}
int APreventDamageTypesUEOT::destroy()
{
for (size_t i = 0; i < clones.size(); ++i)
{
clones[i]->forceDestroy = 0;
}
clones.clear();
return 1;
}
const char * APreventDamageTypesUEOT::getMenuText()
{
return ability->getMenuText();
}
APreventDamageTypesUEOT * APreventDamageTypesUEOT::clone() const
{
APreventDamageTypesUEOT * a = NEW APreventDamageTypesUEOT(*this);
a->ability = this->ability->clone();
a->isClone = 1;
return a;
}
APreventDamageTypesUEOT::~APreventDamageTypesUEOT()
{
SAFE_DELETE(ability);
}
//AUpkeep
AUpkeep::AUpkeep(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap, int restrictions, int _phase,
int _once) :
ActivatedAbility(_id, card, _cost, restrictions, _tap), NestedAbility(a), phase(_phase), once(_once)
{
paidThisTurn = 0;
}
void AUpkeep::Update(float dt)
{
// once: 0 means always go off, 1 means go off only once, 2 means go off only once and already has.
if (newPhase != currentPhase && source->controller() == game->currentPlayer && once < 2)
{
if (newPhase == Constants::MTG_PHASE_UNTAP)
{
paidThisTurn = 0;
}
else if (newPhase == phase + 1 && !paidThisTurn)
{
ability->resolve();
}
if (newPhase == phase + 1 && once) once = 2;
}
ActivatedAbility::Update(dt);
}
int AUpkeep::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
{
if (currentPhase != phase || paidThisTurn || once >= 2) return 0;
return ActivatedAbility::isReactingToClick(card, mana);
}
int AUpkeep::resolve()
{
paidThisTurn = 1;
return 1;
}
const char * AUpkeep::getMenuText()
{
return "Upkeep";
}
ostream& AUpkeep::toString(ostream& out) const
{
out << "AUpkeep ::: paidThisTurn : " << paidThisTurn << " (";
return ActivatedAbility::toString(out) << ")";
}
AUpkeep * AUpkeep::clone() const
{
AUpkeep * a = NEW AUpkeep(*this);
a->isClone = 1;
return a;
}
AUpkeep::~AUpkeep()
{
if (!isClone)
SAFE_DELETE(ability);
}