#include "PrecompiledHeader.h"
#include "AllAbilities.h"
#include "Translate.h"


//display a text animation, this is not a real ability.
MTGEventText::MTGEventText(GameObserver* observer, int _id, MTGCardInstance * card, string textToShow) :
MTGAbility(observer, _id,card)
{
    textAlpha = 255;
    text = textToShow;
}

void MTGEventText::Update(float dt)
{
    if (textAlpha)
    {
        textAlpha -= static_cast<int> (200 * dt);
        Render();
        if (textAlpha < 0)
        {
            textAlpha = 0;
            this->forceDestroy = 1;
        }
    }
    MTGAbility::Update(dt);
}

void MTGEventText::Render()
{
    if (!textAlpha)
        return;
    WFont * mFont = WResourceManager::Instance()->GetWFont(Fonts::OPTION_FONT);
    float backup = mFont->GetScale();
    mFont->SetScale(2 - (float) textAlpha / 130);
    mFont->SetColor(ARGB(255,255,255,255));
    mFont->DrawString(text.c_str(), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, JGETEXT_CENTER);
    mFont->SetScale(backup);
}

MTGEventText * MTGEventText::clone() const
{
    return NEW MTGEventText(*this);
}

//generic activated ability for wrapping reveals.
GenericRevealAbility::GenericRevealAbility(GameObserver* observer, int id, MTGCardInstance * source,
    Targetable * target, string _howMany) :
    ActivatedAbility(observer, id, source, NULL), howMany(_howMany)
{
    this->GetId();
}

int GenericRevealAbility::resolve()
{
    MTGAbility * ability = NEW MTGRevealingCards(game, this->GetId(), source, howMany);
    ability->addToGame();
    return 1;
}

const string GenericRevealAbility::getMenuText()
{
    return "Reveal Cards";
}

GenericRevealAbility * GenericRevealAbility::clone() const
{
    GenericRevealAbility * a = NEW GenericRevealAbility(*this);
    return a;
}

GenericRevealAbility::~GenericRevealAbility()
{
    //SAFE_DELETE(ability);
}

//carddisplay created for use in abilities.
RevealDisplay::RevealDisplay(int id, GameObserver* game, int x, int y, JGuiListener * listener, TargetChooser * tc,
    int nb_displayed_items) :
    CardDisplay(id, game, x, y, listener, tc, nb_displayed_items)
{
}

void RevealDisplay::AddCard(MTGCardInstance * _card)
{
    CardGui * card = NEW CardView(CardView::nullZone, _card, static_cast<float> (x + 20 + (mObjects.size() - start_item) * 30),
        static_cast<float> (y + 25));
    Add(card);
}

bool RevealDisplay::CheckUserInput(JButton key)
{
    if (JGE_BTN_SEC == key || JGE_BTN_PRI == key || JGE_BTN_UP == key || JGE_BTN_DOWN == key)
        return false;

    return CardDisplay::CheckUserInput(key);
}

//display card selector box of specified zone.
MTGRevealingCards::MTGRevealingCards(GameObserver* observer, int _id, MTGCardInstance * card, string coreAbility) :
    MTGAbility(observer, _id, card), CardDisplay(_id, game, x, y, listener, NULL, nb_displayed_items)

{
    abilityToCast = NULL;
    revealDisplay = NULL;
    abilityFirst = NULL;
    abilitySecond = NULL;
    abilityString = coreAbility;
    initCD = false;

    afterReveal = "";
    afterEffectActivated = false;

    repeat = false;
    playerForZone = NULL;
    revealCertainTypes = "";
    revealUntil = "";

    if (card->playerTarget)
        playerForZone = card->playerTarget;
    else
        playerForZone = source->controller();

    RevealZone = playerForZone->game->reveal;
    zone = RevealZone;
    RevealFromZone = playerForZone->game->library;

    vector<string>amount = parseBetween(coreAbility, "", " ");
    if (amount.size())
    {
        number = amount[1];
    }

    vector<string>differentZone = parseBetween(coreAbility, "revealzone(", ")");
    if (differentZone.size())
    {
        RevealFromZone = MTGGameZone::stringToZone(game,differentZone[1],source,NULL);
    }

    vector<string>certainTypes = parseBetween(coreAbility, "revealtype(", ")");
    if (certainTypes.size())
    {
        revealCertainTypes = certainTypes[1];
    }

    vector<string>RevealCardUntil = parseBetween(coreAbility, "revealuntil(", ")");
    if (RevealCardUntil.size())
    {
        revealUntil = RevealCardUntil[1];
    }

    vector<string>first = parseBetween(coreAbility, "optionone ", " optiononeend");
    if (first.size())
    {
    abilityOne = first[1];
    }
    vector<string>second = parseBetween(coreAbility, "optiontwo ", " optiontwoend");
    if (second.size())
    {
    abilityTwo = second[1];
    }
    vector<string>afterEffect = parseBetween(coreAbility, "afterrevealed ", " afterrevealedend");
    if (afterEffect.size())
    {
        afterReveal = afterEffect[1];
    }

    repeat = coreAbility.find("repeat") != string::npos;

}

void MTGRevealingCards::Update(float dt)
{

    if (game->OpenedDisplay  != this->revealDisplay && !initCD)//wait your turn
    {
        //if any carddisplays are open, dont do anything until theyre closed, then wait your turn if multiple reveals trigger.
        return;
    }
    if (game->mLayers->actionLayer()->menuObject)
        return;//dont do any of this if a menuobject exist.
    if (!source->getObserver()->mLayers->actionLayer()->getCurrentTargetChooser() && !revealDisplay && !initCD)
    {

        WParsedInt nbCardP(number, NULL, source);
        nbCard = nbCardP.getValue();
        int adjust = 0;
        switch (nbCard)
        {
            //adjust length and location of carddisplay box.
        case 1:adjust = 120; break;
        case 2:adjust = 145; break;
        case 3:adjust = 175; break;
        case 4:adjust = 200; break;
        case 5:adjust = 225; break;
        default:adjust = 225; break;
        }
        if (revealUntil.size())
        {
            adjust = 225;
            revealDisplay = NEW RevealDisplay(1, game, SCREEN_WIDTH - adjust, SCREEN_HEIGHT, listener, NULL,5);
        }
        else
        revealDisplay = NEW RevealDisplay(1, game, SCREEN_WIDTH - adjust, SCREEN_HEIGHT, listener, NULL, nbCard > 5 ? 5 : nbCard);
        revealDisplay->zone = RevealFromZone;
        trashDisplays.push_back(revealDisplay);

        if (revealCertainTypes.size())//revealing cards of a TARGETCHOOSER type.
        {
            TargetChooserFactory tcf(game);
            TargetChooser * rTc = tcf.createTargetChooser(revealCertainTypes, source);
            int startingNumber = RevealFromZone->nb_cards - 1;
            if (rTc)
                for (int i = startingNumber; i > -1; i--)
                {
                    if (!RevealFromZone->cards.size())
                        break;
                    MTGCardInstance * toMove = RevealFromZone->cards[i];
                    if (toMove)
                    {
                        if (rTc->canTarget(toMove, true))
                        {
                            CardViewBackup(toMove);
                            playerForZone->game->putInZone(toMove, RevealFromZone, RevealZone);
                            source->revealedLast = toMove;
                        }
                    }

                }
            SAFE_DELETE(rTc);
        }
        else if(revealUntil.size())//reveal cards until you reveal a TARGETCHOOSER.
        {
            TargetChooserFactory tcf(game);
            TargetChooser * rUc = tcf.createTargetChooser(revealUntil, source);
            bool foundCard = false;
            int howMany = nbCard;
            int startingNumber = RevealFromZone->nb_cards;
            for (int i = 0; i < startingNumber; i++)
            {
                if (foundCard && howMany == 0)
                    break;
                if (howMany == 0)
                    break; //not allowed to reveal until 0 of something is revealed.
                if (RevealFromZone->nb_cards - 1 < 0)
                    break;
                MTGCardInstance * toMove = RevealFromZone->cards[RevealFromZone->nb_cards - 1];
                if (toMove)
                {
                    if (rUc->canTarget(toMove, true))
                    {
                        foundCard = true;
                        howMany--;
                    }

                    CardViewBackup(toMove);
                    playerForZone->game->putInZone(toMove, RevealFromZone, RevealZone);
                    source->revealedLast = toMove;
                }

            }
            SAFE_DELETE(rUc);
        }
        else
        {
            for (int i = 0; i < nbCard; i++)//normal reveal
            {
                if (RevealFromZone->nb_cards - 1 < 0)
                    break;
                MTGCardInstance * toMove = RevealFromZone->cards[RevealFromZone->nb_cards - 1];
                if (toMove)
                {
                    CardViewBackup(toMove);
                    playerForZone->game->putInZone(toMove, RevealFromZone, RevealZone);
                    source->revealedLast = toMove;
                }

            }

         }

        //build the zone, create the first ability.
        revealDisplay->init(RevealZone);
        revealDisplay->zone = RevealZone;
        game->OpenedDisplay = revealDisplay;
        toResolve();    
        initCD = true;
    }


    //card display is ready and loaded, abilities have fired at this point.
    //critical for testdestroy, a function that determines if a ability can
    //exist in condiations such as source not being in play.
    
    if (!zone->cards.size())
    {
        //all possible actions are done, the zone is empty, lets NULL it so it clears it off the screen.
        //DO NOT SAFE_DELETE here, it destroys the card->view and backups kept for the second ability.
        revealDisplay = NULL;
        game->OpenedDisplay = revealDisplay;

        if (repeat)
        {
            initCD = false;
        }
        else if (afterReveal.size() && !afterEffectActivated)
        { 
            afterEffectActivated = true;
            abilityAfter = contructAbility(afterReveal);
            game->addObserver(abilityAfter);
        }
        else
            this->removeFromGame();
    }

    if (revealDisplay)
    {
        revealDisplay->Update(dt);
        Render();
    }

    MTGAbility::Update(dt);
}

void MTGRevealingCards::CardViewBackup(MTGCardInstance * backup)
{
    CardView* t;

    t = NEW CardView(CardView::nullZone, backup, 0, 0);
    //we store copies of the card view since the safe_delete of card displays also deletes the guis stored in them.
    t->actX = SCREEN_WIDTH;
    t->actY = SCREEN_HEIGHT * -2;
    //correct cards x and y, last known location was the reveal display.
    cards.push_back(t);
    return;
}

int MTGRevealingCards::testDestroy()
{
    if (game->mExtraPayment)
        return 0;
    if (revealDisplay)
        return 0;
    if (zone->cards.size())
        return 0;
    if (!initCD)
        return 0;
    if (game->mLayers->actionLayer()->menuObject)
        return 0;
    if (game->mLayers->actionLayer()->getIndexOf(abilityFirst) != -1)
        return 0;

    return 1;
}

int MTGRevealingCards::toResolve()
{

    TargetChooserFactory tcf(game);
    vector<string>splitTarget = parseBetween(abilityOne, "target(", ")");
    //we build a tc to check if the first ability has any valid targets, if it doesnt, just add the 2nd one.
    if (splitTarget.size()) 
    {
        TargetChooser * rTc = tcf.createTargetChooser(splitTarget[1].c_str(), source);

        if (rTc && rTc->countValidTargets())
        {
            abilityFirst = contructAbility(abilityOne);
            game->addObserver(abilityFirst);
            
        }
        else
        {
            repeat = false;
            abilitySecond = contructAbility(abilityTwo);
            game->addObserver(abilitySecond);
            
        }
        SAFE_DELETE(rTc);
    }
    else//the first ability is not targeted
    {
        abilityFirst = contructAbility(abilityOne);
        game->addObserver(abilityFirst);
    }
    return 1;
}

MTGAbility * MTGRevealingCards::contructAbility(string abilityToMake)
{
    AbilityFactory af(game);
    abilityToCast = af.parseMagicLine(abilityToMake, getMaxId(), NULL, source, false);
    if (!abilityToCast)
        return NULL;
    abilityToCast->canBeInterrupted = false;
    abilityToCast->forceDestroy = 1;
    return abilityToCast;
}

void MTGRevealingCards::Render()
{
    if (!revealDisplay)
        return;
    CheckUserInput(mEngine->ReadButton());
    revealDisplay->CheckUserInput(mEngine->ReadButton());
    revealDisplay->Render();
    return;
}

bool MTGRevealingCards::CheckUserInput(JButton key)
{
    //DO NOT REFACTOR BELOW, IT KEPT SPLIT UP TO MAINTAIN READABILITY.
    //we override check inputs, we MUST complete reveal and its effects before being allowed to do anything else.
    TargetChooser * tc = this->observer->mLayers->actionLayer()->getCurrentTargetChooser();
    if (this->source->controller()->isAI())
    {
        if (this->source->controller() != game->isInterrupting)
            game->mLayers->stackLayer()->cancelInterruptOffer(ActionStack::DONT_INTERRUPT, false);
    }
    if (JGE_BTN_SEC == key || JGE_BTN_PREV == key || JGE_BTN_NEXT == key || JGE_BTN_MENU == key)//android back button
    {
        if (tc && (tc->targetMin == false || tc->maxtargets == TargetChooser::UNLITMITED_TARGETS))
        {
            tc->done = true;
            tc->forceTargetListReadyByPlayer = 1;
            //this is for when we have <upto:x> targets but only want to move Y targets, it allows us to
            //tell the targetchooser we are done.
            if (!abilitySecond && !tc->getNbTargets() && tc->source)
            {//we selected nothing for the first ability.
                tc->source->getObserver()->cardClick(tc->source, 0, false);
                if (abilityFirst)///some abilities resolve themselves and remove faster than you can removethem from the game.
                {
                    abilityFirst->removeFromGame();
                    game->mLayers->stackLayer()->Remove(abilityFirst);
                }
                game->Update(0);
                //remove it from the game, update, and remove it from stack if needed.
                //before adding next ability, otherwise we end up with a menu reactToClick.
                if (zone->cards.size() && abilityFirst->testDestroy())//generally only want to add ability 2 if anything is left in the zone.
                {
                    repeat = false;
                    abilitySecond = contructAbility(abilityTwo);
                    game->addObserver(abilitySecond);
                }
            }
            else if (tc->source)
            {
                tc->source->getObserver()->cardClick(tc->source, 0, false);
            }
        }
        else if (!tc && !abilitySecond)//the actions of the first card have finished and we're done looking at the cards.
        {           //or the first ability was an "all(" which was not a mover ability.
            CheckUserInput(JGE_BTN_OK);
        }
        return false;
    }
    if (JGE_BTN_OK == key)//for ease if we're sitting there looking at the card display and click a card after first ability.
    {                     //looks redundent and can be added above as another condiational, however we would end up with a massive
                          //if statement that becomes very very hard to follow. 
        if (!tc && !abilitySecond)
        {           
            if (abilityFirst)
            {
                abilityFirst->removeFromGame();
                game->mLayers->stackLayer()->Remove(abilityFirst);
            }
            game->Update(1);

            if (zone->cards.size())
            {
                repeat = false;
                abilitySecond = contructAbility(abilityTwo);
                game->addObserver(abilitySecond);
            }

        }
    }
    if(revealDisplay)
        return revealDisplay->CheckUserInput(key);
    return false;
}

MTGRevealingCards * MTGRevealingCards::clone() const
{
    return NEW MTGRevealingCards(*this);
}

MTGRevealingCards::~MTGRevealingCards()
{
    for (vector<CardDisplay*>::iterator it = trashDisplays.begin(); it != trashDisplays.end(); ++it)
        SAFE_DELETE(*it);
    for (vector<CardView*>::iterator it = cards.begin(); it != cards.end(); ++it)
        SAFE_DELETE(*it);
}

int MTGRevealingCards::receiveEvent(WEvent* e)
{

    if (WEventZoneChange* event = dynamic_cast<WEventZoneChange*>(e))
    {
        if (event->from == zone)
        {
            CardView* t;
            if (event->card->view)
                t = NEW CardView(CardView::nullZone, event->card, *(event->card->view));
            else
                t = NEW CardView(CardView::nullZone, event->card, (float)x, (float)y);
            //we store copies of the card view since moving to and from card displays also deletes the guis stored in cards.
            //GuiLayer::resetObjects() is the main reason we need to back them up. card views are set to NULL maybe more often than
            //they should be, possibly someone being to over cautious.
            t->actX = SCREEN_WIDTH;
            t->actY = SCREEN_HEIGHT * -2;
            //correct cards x and y, last known location was the reveal display.
            cards.push_back(t);
            return 1;
        } 
    }
    return 0;
}



//////////////////////////////////////////////////////////////////////////////////////////////////////////
////scry//////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////
//below the effect of "scry X, THEN reveal and do stuff, was impossible to accomplish with reveal alone.
//if a card simply states "scry X" and nothing else use reveal:x. 
//this is for effects that want you to reveal AFTER you scry.
//this ability automatically creates effects, put on top, then whatever you dont get put on buttom,
//then it reveals the top card, and creates the ability written in primitive as core, then it
//handles putting the card back on top of the library when you are done.
///delayed changes the order, makes the ability fire after the 2nd reveal is finished.
///
MTGScryCards::MTGScryCards(GameObserver* observer, int _id, MTGCardInstance * card, string coreAbility) :
    MTGAbility(observer, _id, card), CardDisplay(_id, game, x, y, listener, NULL, nb_displayed_items)

{
    abilityToCast = NULL;
    revealDisplay = NULL;
    abilityFirst = NULL;
    abilitySecond = NULL;
    abilityString = coreAbility;
    delayedAbilityString = "";
    revealTopAmount = 1;//scry, then reveal the top card and do effect.

    initCD = false;
    RevealZone = source->controller()->game->reveal;
    zone =RevealZone;
    RevealFromZone = source->controller()->game->library;

    vector<string>amount = parseBetween(coreAbility, "", " ");
    if (amount.size())
    {
        number = amount[1];
    }

    vector<string>differentZone = parseBetween(coreAbility, "scryzone(", ")");
    if (differentZone.size())
    {
        RevealFromZone = MTGGameZone::stringToZone(game, differentZone[1], source, NULL);
    }

    abilityOne = "name(Place on top) target(<anyamount>*|myreveal) moveto(mylibrary)";
    delayed = coreAbility.find("delayed") != string::npos;
    dontRevealAfter = coreAbility.find("dontshow") != string::npos;
    if(dontRevealAfter)
    revealTopAmount = 0;
    vector<string>second = parseBetween(coreAbility, "scrycore ", " scrycoreend");
    if (second.size())
    {
        if (delayed)
        {
            abilityTwo = "target(*|reveal) name(Reveal the top card) donothing";
            delayedAbilityString = second[1];
        }
        else
        abilityTwo = second[1];
    }

    
}

void MTGScryCards::Update(float dt)
{
    if (game->OpenedDisplay != this->revealDisplay && !initCD)
        return;
    if (game->mLayers->actionLayer()->menuObject)
        return;
    if (!source->getObserver()->mLayers->actionLayer()->getCurrentTargetChooser() && !revealDisplay && !initCD)
    {
        WParsedInt nbCardP(number, NULL, source);
        nbCard = nbCardP.getValue();
        initDisplay(nbCard);
        toResolve();
    }
    initCD = true;
    if (!zone->cards.size() && abilitySecond)
    {
        revealDisplay = NULL;
        game->OpenedDisplay = revealDisplay;
        this->removeFromGame();
    }
    if (revealDisplay)
    {
        revealDisplay->Update(dt);
        Render();
    }
    MTGAbility::Update(dt);
}

void MTGScryCards::initDisplay(int value)
{

    if (RevealZone->cards.size())
    {
        do
        {
            MTGCardInstance * toMove = RevealZone->cards[0];
            if (toMove)
            {   
                MTGAbility * a = NEW AALibraryBottom(game, getMaxId(), source, toMove);
                a->oneShot = 1;
                a->resolve();
                SAFE_DELETE(a);
            }
        } while (RevealZone->cards.size());  

        game->Update(0);
        revealDisplay = NULL;
        game->OpenedDisplay = revealDisplay;
    }
    int adjust = 0;
    switch (value)
    {
    case 1:adjust = 120; break;
    case 2:adjust = 145; break;
    case 3:adjust = 175; break;
    case 4:adjust = 200; break;
    case 5:adjust = 225; break;
    default:adjust = 225; break;
    }
    revealDisplay = NEW RevealDisplay(1, game, SCREEN_WIDTH - adjust, SCREEN_HEIGHT, listener, NULL, nbCard > 5 ? 5 : nbCard);
    revealDisplay->zone = RevealFromZone;
    trashDisplays.push_back(revealDisplay);
    for (int i = 0; i < value; i++)
    {
        if (RevealFromZone->nb_cards - 1 < 0)
            break;
        MTGCardInstance * toMove = RevealFromZone->cards[RevealFromZone->nb_cards - 1];
        if (toMove)
        {
            CardView* t;
            t = NEW CardView(CardView::nullZone, toMove, 0, 0);
            t->actX = SCREEN_WIDTH;
            t->actY = SCREEN_HEIGHT * -2;
            cards.push_back(t);
            source->controller()->game->putInZone(toMove, RevealFromZone, RevealZone);
            source->revealedLast = toMove;
        }
    }
    revealDisplay->init(RevealZone);
    revealDisplay->zone = RevealZone;
    game->OpenedDisplay = revealDisplay;
}

int MTGScryCards::testDestroy()
{
    if (game->mExtraPayment)
        return 0;
    if (revealDisplay)
        return 0;
    if (zone->cards.size())
        return 0;
    if (!initCD)
        return 0;
    if (game->mLayers->actionLayer()->menuObject)
        return 0;
    if (game->mLayers->actionLayer()->getIndexOf(abilityFirst) != -1)
        return 0;

    return 1;
}

int MTGScryCards::toResolve()
{
    //scry will always have valid targets.
        abilityFirst = contructAbility(abilityOne);
        game->addObserver(abilityFirst);
    return 1;
}

MTGAbility * MTGScryCards::contructAbility(string abilityToMake)
{
    AbilityFactory af(game);
    abilityToCast = af.parseMagicLine(abilityToMake, getMaxId(), NULL, source, false);
    if (!abilityToCast)
        return NULL;
    abilityToCast->canBeInterrupted = false;
    abilityToCast->forceDestroy = 1;
    return abilityToCast;
}

void MTGScryCards::Render()
{
    if (!revealDisplay)
        return;
    CheckUserInput(mEngine->ReadButton());
    if (revealDisplay)
    {
        revealDisplay->CheckUserInput(mEngine->ReadButton());
        revealDisplay->Render();
    }
    return;
}

bool MTGScryCards::CheckUserInput(JButton key)
{
    //DO NOT REFACTOR BELOW
    TargetChooser * tc = this->observer->mLayers->actionLayer()->getCurrentTargetChooser();
    if (this->source->controller()->isAI())
    {//ai doesnt click button, and the engine has no way of knowing whos clicking button
        //for now we will cancel interrupts made when ai is making choice
        //in the future we will need a way to find out if the human is pressing the keys and which player.
        if (this->source->controller() != game->isInterrupting)
            game->mLayers->stackLayer()->cancelInterruptOffer(ActionStack::DONT_INTERRUPT, false);
    }
    if (JGE_BTN_SEC == key || JGE_BTN_PREV == key || JGE_BTN_NEXT == key || JGE_BTN_MENU == key)
    {
        if (tc && (tc->targetMin == false || tc->maxtargets == TargetChooser::UNLITMITED_TARGETS))
        {
            tc->done = true;
            tc->forceTargetListReadyByPlayer = 1;
            if (!abilitySecond && !tc->getNbTargets() && tc->source)
            {
                tc->source->getObserver()->cardClick(tc->source, 0, false);
                if (abilityFirst)///some abilities resolve themselves and remove faster than you can removethem from the game.
                {
                    abilityFirst->removeFromGame();
                    game->mLayers->stackLayer()->Remove(abilityFirst);
                }
                game->Update(0);
                if (zone->cards.size() && abilityFirst->testDestroy())
                {
                    initDisplay(revealTopAmount);
                    abilitySecond = contructAbility(abilityTwo);
                    game->addObserver(abilitySecond);
                }
            }
            else if (tc->source)
            {
                tc->source->getObserver()->cardClick(tc->source, 0, false);
            }
        }
        else if (!tc && !abilitySecond)
        {           
            CheckUserInput(JGE_BTN_OK);
        }
        return false;
    }
    if (JGE_BTN_OK == key)
    {                     
        if (!tc && !abilitySecond)
        {
            if (abilityFirst)
            {
                abilityFirst->removeFromGame();
                game->mLayers->stackLayer()->Remove(abilityFirst);
            }
            game->Update(1);

            if (zone->cards.size() || (revealDisplay && !zone->cards.size()))
            {
                initDisplay(revealTopAmount);
                abilitySecond = contructAbility(abilityTwo);
                game->addObserver(abilitySecond);
            }

        }
        if (!tc && abilitySecond && abilitySecond->testDestroy())
        {    
            do
            {
                if (!RevealZone->cards.size())
                    break;
                MTGCardInstance * toMove = RevealZone->cards[0];
                if (toMove)
                {
                    source->revealedLast = toMove;
                    MTGAbility * a = NEW AAMover(game, getMaxId(), source, toMove,"library", "Place on top");
                    a->oneShot = true;
                    a->resolve();
                    SAFE_DELETE(a);
                }
            } while (RevealZone->cards.size());

            if (delayed)
            {
                MTGAbility * delayedA = contructAbility(delayedAbilityString);
                if (delayedA->oneShot)
                {
                    delayedA->resolve();
                    SAFE_DELETE(delayedA);
                }
                else
                delayedA->addToGame();
                    
            }
        }
    }
    if (revealDisplay)
        return revealDisplay->CheckUserInput(key);
    return false;
}

MTGScryCards * MTGScryCards::clone() const
{
    return NEW MTGScryCards(*this);
}

MTGScryCards::~MTGScryCards()
{
    for (vector<CardDisplay*>::iterator it = trashDisplays.begin(); it != trashDisplays.end(); ++it)
        SAFE_DELETE(*it);
    for (vector<CardView*>::iterator it = cards.begin(); it != cards.end(); ++it)
        SAFE_DELETE(*it);
}

int MTGScryCards::receiveEvent(WEvent* e)
{

    if (WEventZoneChange* event = dynamic_cast<WEventZoneChange*>(e))
    {
        if (event->from == zone)
        {
            CardView* t;
            if (event->card->view)
                t = NEW CardView(CardView::nullZone, event->card, *(event->card->view));
            else
                t = NEW CardView(CardView::nullZone, event->card, (float)x, (float)y);
            //we store copies of the card view since moving to and from card displays also deletes the guis stored in cards.
            //GuiLayer::resetObjects() is the main reason we need to back them up. card views are set to NULL maybe more often than
            //they should be, possibly someone being to over cautious.
            t->actX = SCREEN_WIDTH;
            t->actY = SCREEN_HEIGHT * -2;
            //correct cards x and y, last known location was the reveal display.
            cards.push_back(t);
            return 1;
        }
    }
    return 0;
}

//scry wrapper
GenericScryAbility::GenericScryAbility(GameObserver* observer, int id, MTGCardInstance * source,
    Targetable * target, string _howMany) :
    ActivatedAbility(observer, id, source, NULL), howMany(_howMany)
{
    this->GetId();
}

int GenericScryAbility::resolve()
{
    MTGAbility * ability = NEW MTGScryCards(game, this->GetId(), source, howMany);
    ability->addToGame();
    return 1;
}

const string GenericScryAbility::getMenuText()
{
    return "Scry Cards";
}

GenericScryAbility * GenericScryAbility::clone() const
{
    GenericScryAbility * a = NEW GenericScryAbility(*this);
    return a;
}

GenericScryAbility::~GenericScryAbility()
{
    //SAFE_DELETE(ability);
}

////////////////////////
//Activated Abilities

//Generic Activated Abilities
GenericActivatedAbility::GenericActivatedAbility(GameObserver* observer, string newName, string castRestriction, int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost,
        string limit,MTGAbility * sideEffects,string usesBeforeSideEffects, int restrictions, MTGGameZone * dest) :
    ActivatedAbility(observer, _id, card, _cost, restrictions,limit,sideEffects,usesBeforeSideEffects,castRestriction), NestedAbility(a), activeZone(dest),newName(newName)
{
    counters = 0;
    target = ability->target;
}

GenericActivatedAbility::GenericActivatedAbility(const GenericActivatedAbility &other):
    ActivatedAbility(other), NestedAbility(other), activeZone(other.activeZone), newName(other.newName)
{

}

int GenericActivatedAbility::resolve()
{
    //Note: I've seen a similar block in some other MTGAbility, can this be refactored .
    if (abilityCost)
    {
        source->X = 0;
        ManaCost * diff = abilityCost->Diff(getCost());
        source->X = diff->hasX();
        SAFE_DELETE(diff);
    }
    ability->target = target; //may have been updated...
    if (ability)
        return ability->resolve();
    return 0;
}

const string GenericActivatedAbility::getMenuText()
{
if(newName.size())
return newName.c_str();
    if (ability)
        return ability->getMenuText();
    return "Error";
}

int GenericActivatedAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
{
    if (dynamic_cast<AAMorph*> (ability) && !card->isMorphed && !card->morphed && card->turningOver)
        return 0;
    return ActivatedAbility::isReactingToClick(card, mana);
}

void GenericActivatedAbility::Update(float dt)
{
    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->ability = ability->clone();
    return a;
}

GenericActivatedAbility::~GenericActivatedAbility()
{
    SAFE_DELETE(ability);
}

//AA Alter Poison
AAAlterPoison::AAAlterPoison(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable * _target, int poison, ManaCost * _cost,
        int who) :
    ActivatedAbilityTP(observer, _id, _source, _target, _cost, who), poison(poison)
{
}

int AAAlterPoison::resolve()
{
    Damageable * _target = (Damageable *) getTarget();
    if (_target)
    {
        Player * pTarget = (Player*)_target;
        if(!pTarget->inPlay()->hasAbility(Constants::POISONSHROUD) || poison < 0)
            _target->poisonCount += poison;
    }
    return 0;
}

const string AAAlterPoison::getMenuText()
{
    return "Poison";
}

AAAlterPoison * AAAlterPoison::clone() const
{
    return NEW AAAlterPoison(*this);
}

AAAlterPoison::~AAAlterPoison()
{
}

//Damage Prevent
AADamagePrevent::AADamagePrevent(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable * _target, int preventing, ManaCost * _cost,
        int who) :
    ActivatedAbilityTP(observer, _id, _source, _target, _cost, who), preventing(preventing)
{
    aType = MTGAbility::STANDARD_PREVENT;
}

int AADamagePrevent::resolve()
{
    Damageable * _target = (Damageable *) getTarget();
    if (_target)
    {
        _target->preventable += preventing;
    }
    return 0;
}

const string AADamagePrevent::getMenuText()
{
    return "Prevent Damage";
}

AADamagePrevent * AADamagePrevent::clone() const
{
    return NEW AADamagePrevent(*this);
}

AADamagePrevent::~AADamagePrevent()
{
}

//AADamager
AADamager::AADamager(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable * _target, string d, ManaCost * _cost,
        int who) :
    ActivatedAbilityTP(observer, _id, _source, _target, _cost, who), d(d)
{
    aType = MTGAbility::DAMAGER;
    redirected = false;
    }

    int AADamager::resolve()
    {
        Damageable * _target = (Damageable *) getTarget();
        if (_target)
        {
            WParsedInt damage(d, NULL, (MTGCardInstance *)source);
            if(_target == game->opponent() && game->opponent()->inPlay()->hasType("planeswalker") && !redirected)
            {
                vector<MTGAbility*>selection;
                MTGCardInstance * check = NULL;
                this->redirected = true;
                MTGAbility * setPlayer = this->clone();
                this->redirected = false;
                selection.push_back(setPlayer);
                int checkWalkers = ((Player*)_target)->game->battlefield->cards.size();
                for(int i = 0; i < checkWalkers;++i)
                {
                    check = ((Player*)_target)->game->battlefield->cards[i];
                    if(check->hasType(Subtypes::TYPE_PLANESWALKER))
                    {
                        this->redirected = true;
                        MTGAbility * setWalker = this->clone();
                        this->redirected = false;
                        setWalker->oneShot = true;
                        setWalker->target = check;
                        selection.push_back(setWalker);
                    }
                }
                if(selection.size())
                {
                    MTGAbility * a1 = NEW MenuAbility(game, this->GetId(), source, source,true,selection);
                    game->mLayers->actionLayer()->currentActionCard = source;
                    a1->resolve();
                }
                return 1;
            }
            game->mLayers->stackLayer()->addDamage(source, _target, damage.getValue());
            game->mLayers->stackLayer()->resolve();
            return 1;
        }
        return 0;
    }

    int AADamager::getDamage()
    {
        WParsedInt damage(d, NULL, (MTGCardInstance *)source);
        return damage.getValue();
    }

    const string AADamager::getMenuText()
    {
        MTGCardInstance * _target = dynamic_cast<MTGCardInstance*>(target);
        if(_target && _target->hasType(Subtypes::TYPE_PLANESWALKER))
            return _target->name.c_str();
        if(redirected)
            return "Damage Player";
        return "Damage";
    }

AADamager * AADamager::clone() const
{
    return NEW AADamager(*this);
}


//AADepleter
AADepleter::AADepleter(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target,string nbcardsStr, ManaCost * _cost, int who, bool toexile) :
    ActivatedAbilityTP(observer, _id, card, _target, _cost, who),nbcardsStr(nbcardsStr),toexile(toexile)
{
}
    int AADepleter::resolve()
    {
        Player * player = getPlayerFromTarget(getTarget());
        if (player)
        {
            WParsedInt numCards(nbcardsStr, NULL, source);
            MTGLibrary * library = player->game->library;
            for (int i = 0; i < numCards.getValue(); i++)
            {
                if (library->nb_cards)
                {
                    if(toexile)
                        player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->exile);
                    else
                        player->game->putInZone(library->cards[library->nb_cards - 1], library, player->game->graveyard);
                }
            }
        }
        return 1;
    }

const string AADepleter::getMenuText()
{
    if(toexile)
        return "Ingest";
    return "Deplete";
}

AADepleter * AADepleter::clone() const
{
    return NEW AADepleter(*this);
}

//AACascade
AACascade::AACascade(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, string nbcardsStr, ManaCost * _cost) :
    ActivatedAbility(observer, _id, _source, _cost, 0),nbcardsStr(nbcardsStr)
{
    selectedCards.clear();
    oldOrder.clear();
    newOrder.clear();
}
    int AACascade::resolve()
    {
        Player * player = source->controller();
        if (player)
        {
            WParsedInt numCards(nbcardsStr, NULL, source);
            MTGLibrary * library = player->game->library;
            MTGRemovedFromGame * exile = player->game->exile;
            MTGCardInstance * viable = NULL;
            int counter = 0;
            for (int i = 0; i < numCards.getValue(); i++)
            {
                if (library->nb_cards)
                {
                    for(int z = library->nb_cards-1; z >= 0; z--)
                    {
                        if(!library->cards[z]->isLand() && (library->cards[z]->getManaCost()->getConvertedCost() < source->getManaCost()->getConvertedCost()))
                        {
                            viable = library->cards[z];
                            player->game->putInZone(viable, library, exile);
                            {
                                for(int j=0; j < library->nb_cards; j++)
                                {
                                     if(library->cards[j]->isCascaded)
                                     {
                                         library->cards[j]->isCascaded = false;
                                         selectedCards.push_back(library->cards[j]);
                                     }
                                }
                                if(selectedCards.size())
                                {
                                    std::random_shuffle ( selectedCards.begin(), selectedCards.end() );
                                    for(unsigned int i = 0; i < selectedCards.size();++i)
                                    {
                                        oldOrder = library->cards;
                                        newOrder.push_back(selectedCards[i]);
                                        for(unsigned int k = 0;k < oldOrder.size();++k)
                                        {
                                            MTGCardInstance * rearranged = oldOrder[k];
                                            if(rearranged != selectedCards[i])
                                                newOrder.push_back(rearranged);
                                        }
                                        library->cards = newOrder;
                                    }
                                }
                            }
                            toCastCard(viable->next);
                            return 1;
                        }
                        else
                        {
                            library->cards[library->nb_cards - 1]->isCascaded=true;
                            counter++;
                        }
                    }
                }
            }
        }
        return 1;
    }

void AACascade::toCastCard(MTGCardInstance * thisCard)
{
    MTGAbility *ac = NEW AACastCard(game, game->mLayers->actionLayer()->getMaxId(), thisCard, thisCard,false,false,true,"","",false,false);
    MayAbility *ma1 = NEW MayAbility(game, game->mLayers->actionLayer()->getMaxId(), ac->clone(), thisCard,true);
    MTGAbility *ga1 = NEW GenericAddToGame(game, game->mLayers->actionLayer()->getMaxId(), thisCard,NULL,ma1->clone());
    SAFE_DELETE(ac);
    SAFE_DELETE(ma1);
    ga1->resolve();
    return;
}

const string AACascade::getMenuText()
{
    return "Cascade";
}

AACascade * AACascade::clone() const
{
    return NEW AACascade(*this);
}

//take extra turns or skip turns, values in the negitive will make you skip.
AAModTurn::AAModTurn(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target,string nbTurnStr, ManaCost * _cost, int who) :
    ActivatedAbilityTP(observer, _id, card, _target, _cost, who),nbTurnStr(nbTurnStr)
{

}
    int AAModTurn::resolve()
    {
        Player * player = getPlayerFromTarget(getTarget());
        if (player)
        {
            WParsedInt numTurns(nbTurnStr, NULL, source);
            if(numTurns.getValue() > 0)
            {
                player->extraTurn += numTurns.getValue();
            }
            else
            {
                player->skippingTurn += abs(numTurns.getValue());

            }
        }
        return 1;
    }

    const string AAModTurn::getMenuText()
    {
        WParsedInt numTurns(nbTurnStr, NULL, source);
        if(numTurns.getValue() > 0)
            return "Take Extra Turn(s)";
        else
            return "Skip A Turn(s)";
    }

AAModTurn * AAModTurn::clone() const
{
    return NEW AAModTurn(*this);
}

//move target to bottom of owners library
AALibraryBottom::AALibraryBottom(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost) :
ActivatedAbility(observer, _id, _source, _cost, 0)
{
    target = _target;
}

int AALibraryBottom::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    _target = _target->owner->game->putInLibrary(_target);
    if (_target)
    {
        MTGLibrary * library = _target->owner->game->library;
        vector<MTGCardInstance *>oldOrder = library->cards;
        vector<MTGCardInstance *>newOrder;
        newOrder.push_back(_target);
        for(unsigned int k = 0;k < oldOrder.size();++k)
        {
            MTGCardInstance * rearranged = oldOrder[k];
            if(rearranged != _target)
                newOrder.push_back(rearranged);
        }
        library->cards = newOrder;
        return 1;
    }
    return 0;
}

const string AALibraryBottom::getMenuText()
{
    return "Bottom Of Library";
}

AALibraryBottom * AALibraryBottom::clone() const
{
    return NEW AALibraryBottom(*this);
}

//AACopier
AACopier::AACopier(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost) :
    ActivatedAbility(observer, _id, _source, _cost, 0)
{
    target = _target;
}

int AACopier::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        MTGCard* clone = MTGCollection()->getCardById(_target->copiedID);
        MTGCardInstance * myClone = NEW MTGCardInstance(clone, source->controller()->game);
        source->copy(myClone);
        SAFE_DELETE(myClone);
        source->isACopier = true;
        source->copiedID = _target->getMTGId();
        source->modifiedbAbi = _target->modifiedbAbi;
        source->origbasicAbilities = _target->origbasicAbilities;
        source->basicAbilities = _target->basicAbilities;
        if(_target->isMorphed)
        {
            source->power = 2;
            source->life = 2;
            source->toughness = 2;
            source->setColor(0,1);
            source->name = "Morph";
            source->types.clear();
            string cre = "Creature";
            source->setType(cre.c_str());
            source->basicAbilities.reset();
            source->getManaCost()->resetCosts();
        }
        return 1;
    }
    return 0;
}

const string AACopier::getMenuText()
{
    return "Copy";
}

AACopier * AACopier::clone() const
{
    return NEW AACopier(*this);
}

//phaseout
AAPhaseOut::AAPhaseOut(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost) :
    ActivatedAbility(observer, _id, _source, _cost, 0)
{
    target = _target;
}

int AAPhaseOut::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        _target->isPhased = true;
        
        _target->phasedTurn = game->turn;
        if(_target->view)
            _target->view->alpha = 50;
        _target->initAttackersDefensers();
        return 1;
    }
    return 0;
}

const string AAPhaseOut::getMenuText()
{
    return "Phase Out";
}

AAPhaseOut * AAPhaseOut::clone() const
{
    return NEW AAPhaseOut(*this);
}

//AAImprint
AAImprint::AAImprint(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost) :
    ActivatedAbility(observer, _id, _source, _cost, 0)
{
    target = _target;
}

int AAImprint::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        Player * p = _target->controller();
        if(p)
            p->game->putInExile(_target);

        while(_target->next)
            _target = _target->next;

        source->imprintedCards.push_back(_target);

        if (source->imprintedCards.size())
        {
            if (source->imprintedCards.back()->hasColor(Constants::MTG_COLOR_GREEN))
                source->imprintG += 1;
            if (source->imprintedCards.back()->hasColor(Constants::MTG_COLOR_BLUE))
                source->imprintU += 1;
            if (source->imprintedCards.back()->hasColor(Constants::MTG_COLOR_RED))
                source->imprintR += 1;
            if (source->imprintedCards.back()->hasColor(Constants::MTG_COLOR_BLACK))
                source->imprintB += 1;
            if (source->imprintedCards.back()->hasColor(Constants::MTG_COLOR_WHITE))
                source->imprintW += 1;
            if (source->imprintedCards.back()->getName().size())
            {
                source->currentimprintName = source->imprintedCards.back()->getName();
                source->imprintedNames.push_back(source->imprintedCards.back()->getName());
            }
        }
        return 1;
    }
    return 0;
}

const string AAImprint::getMenuText()
{
    return "Imprint";
}

AAImprint * AAImprint::clone() const
{
    return NEW AAImprint(*this);
}

//Counters
AACounter::AACounter(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target,string counterstring, const char * _name, int power, int toughness,
        int nb,int maxNb, ManaCost * cost) :
    ActivatedAbility(observer, id, source, cost, 0),counterstring(counterstring), nb(nb),maxNb(maxNb), power(power), toughness(toughness), name(_name)
{
    this->target = target;
    if (name.find("Level") != string::npos || name.find("level") != string::npos)
        aType = MTGAbility::STANDARD_LEVELUP;
    else
        aType = MTGAbility::COUNTERS;
        
    menu = "";
}

    int AACounter::resolve()
    {
        if (target)
        {
            MTGCardInstance * _target = (MTGCardInstance *) target;
            AbilityFactory af(game);
            if(counterstring.size())
            {
                Counter * checkcounter = af.parseCounter(counterstring, source, NULL);
                nb = checkcounter->nb;
                delete checkcounter;
            }
            if (nb > 0)
            {
                for (int i = 0; i < nb; i++)
                {
                    while (_target->next)
                        _target = _target->next;

                    Counter * targetCounter = NULL;
                    int currentAmount = 0;
                    if (_target->counters && _target->counters->hasCounter(name.c_str(), power, toughness))
                    {
                        targetCounter = _target->counters->hasCounter(name.c_str(), power, toughness);
                        currentAmount = targetCounter->nb;
                    }
                    if(!maxNb || (maxNb && currentAmount < maxNb))
                    {
                        _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);
                }
            }

            _target->doDamageTest = 1;
            if(!_target->afterDamage())
            {
                //If a creature with +1/+1 counters on it gets enough -1/-1 counters to kill it, 
                //it dies before the two counters have the chance to cancel out. For example, 
                //if your Strangleroot Geist with a +1/+1 counter on it got three -1/-1 counters 
                //from Skinrender's "enters the battlefield" ability, the Geist would die with //
                //one +1/+1 counter and three -1/-1 counters and wouldn't return to the battlefield.
                for (int i = 0; i < _target->counters->mCount; i++)
                {
                    if (_target->counters->counters[i]->cancels(power, toughness) && !name.size() && _target->counters->counters[i]->nb > 0)
                    {
                        _target->counters->counters[i]->cancelCounter(power,toughness);
                    }
                }
            }

            //specail cases, indestructible creatures which recieve enough counters to kill it are destroyed as a state based effect
            if(_target->toughness <= 0 && _target->has(Constants::INDESTRUCTIBLE) && toughness < 0)
                _target->controller()->game->putInGraveyard(_target);
            return nb;
        }
        return 0;
    }

const string AACounter::getMenuText()
{
    if (menu.size())
    {
        return menu.c_str();
    }
    char buffer[128];

    if (name.size())
    {
        string s = name;
        menu.append(s.c_str());
    }

    if (power != 0 || toughness != 0)
    {
        sprintf(buffer, " %i/%i", power, toughness);
        menu.append(buffer);
    }

    menu.append(" Counter");
    if (nb != 1 && !(nb < -1000))
    {
        sprintf(buffer, ": %i", nb);
        menu.append(buffer);
    }

    sprintf(menuText, "%s", menu.c_str());
    return menuText;
}

AACounter * AACounter::clone() const
{
    return NEW AACounter(*this);
}

//shield a card from a certain type of counter.
ACounterShroud::ACounterShroud(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target,TargetChooser * tc, Counter * counter) :
MTGAbility(observer, id, source),csTc(tc),counter(counter),re(NULL)
{
}

int ACounterShroud::addToGame()
{
    SAFE_DELETE(re);
    re = NEW RECountersPrevention(this,source,(MTGCardInstance*)target,csTc,counter);
    if (re)
    {
        game->replacementEffects->add(re);
        return MTGAbility::addToGame();
    }
    return 0;
}

int ACounterShroud::destroy()
{
    game->replacementEffects->remove(re);
    SAFE_DELETE(re);
    return 1;
}

ACounterShroud * ACounterShroud::clone() const
{
    ACounterShroud * a = NEW ACounterShroud(*this);
    a->re = NULL;
    return a;
}

ACounterShroud::~ACounterShroud()
{
    SAFE_DELETE(re);
    SAFE_DELETE(counter);
}

//track counters placed on a card
ACounterTracker::ACounterTracker(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target, string scounter) :
MTGAbility(observer, id, source, target),scounter(scounter)
{
    removed = 0;
}

int ACounterTracker::addToGame()
{
    MTGCardInstance * _target = (MTGCardInstance*)target;
    AbilityFactory af(game);
    Counter * counter = af.parseCounter(scounter, _target, NULL); //(Spell*)source);
    if (!counter)
    {
        return 0;
    }
    if(_target && !removed)
    {
        if(_target->counters->hasCounter(counter->name.c_str(),counter->power,counter->toughness) && _target->counters->hasCounter(counter->name.c_str(),counter->power,counter->toughness)->nb >= counter->nb)
        {
            for(int nb = 0;nb < counter->nb;nb++)
            {
                _target->counters->removeCounter(counter->name.c_str(),counter->power,counter->toughness);
                removed++;
            }
        }
        SAFE_DELETE(counter);
        return MTGAbility::addToGame();
    }
    SAFE_DELETE(counter);
    return 0;
}

int ACounterTracker::destroy()
{
    MTGCardInstance * _target = (MTGCardInstance*)target;
    AbilityFactory af(game);
    Counter * counter = af.parseCounter(scounter, _target, NULL); //(Spell*)source);
    if (!counter)
    {
        return 0;
    }
    if(_target)
    {
        if(removed == counter->nb)
        {
            for(int nb = 0;nb < counter->nb;nb++)
            {
                _target->counters->addCounter(counter->name.c_str(),counter->power,counter->toughness);
            }
        }
    }
    SAFE_DELETE(counter);
    return 1;
}

int ACounterTracker::testDestroy()
{
    if(this->source->isInPlay(game))
        return 0;
    return 1;
}

ACounterTracker * ACounterTracker::clone() const
{
    ACounterTracker * a = NEW ACounterTracker(*this);
    return a;
}

ACounterTracker::~ACounterTracker()
{
}

//removeall counters of a certain type or all.
AARemoveAllCounter::AARemoveAllCounter(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target, const char * _name, int power, int toughness,
        int nb,bool all, ManaCost * cost) :
    ActivatedAbility(observer, id, source, cost, 0), nb(nb), power(power), toughness(toughness), name(_name),all(all)
{
    this->target = target;
    menu = "";
}

int AARemoveAllCounter::resolve()
{
    if (!target)
        return 0;

    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (all )
    {
        for(int amount = 0;amount < _target->counters->mCount;amount++)
        {
            while(_target->counters->counters[amount]->nb > 0)
                _target->counters->removeCounter(_target->counters->counters[amount]->name.c_str(),_target->counters->counters[amount]->power,_target->counters->counters[amount]->toughness);

        }
    }
    Counter * targetCounter = NULL;
    if (_target->counters && _target->counters->hasCounter(name.c_str(), power, toughness))
    {
        targetCounter = _target->counters->hasCounter(name.c_str(), power, toughness);
        nb = targetCounter->nb;
    }


    for (int i = 0; i < nb; i++)
    {
        while (_target->next)
            _target = _target->next;
        _target->counters->removeCounter(name.c_str(), power, toughness);
    }

    return nb;
}

const string AARemoveAllCounter::getMenuText()
{
    if (menu.size())
    {
        return menu.c_str();
    }
    char buffer[128];

    if (name.size())
    {
        string s = name;
        menu.append(s.c_str());
    }

    if (power != 0 || toughness != 0)
    {
        sprintf(buffer, " %i/%i", power, toughness);
        menu.append(buffer);
    }

    menu.append(" Counter Removed");
    if (nb != 1)
    {
        sprintf(buffer, ": %i", nb);
        menu.append(buffer);
    }

    return menu.c_str();
}

AARemoveAllCounter * AARemoveAllCounter::clone() const
{
    return NEW AARemoveAllCounter(*this);
}

//proliferate a target
AAProliferate::AAProliferate(GameObserver* observer, int id, MTGCardInstance * source, Targetable * target,ManaCost * cost) :
ActivatedAbility(observer, id, source, cost, 0)
{
    this->GetId();
}
 
int AAProliferate::resolve()
{
    if (!target)
        return 0;

    vector<MTGAbility*>pcounters;
    
    Player * pTarget = dynamic_cast<Player *>(target);
    MTGCardInstance * cTarget = dynamic_cast<MTGCardInstance *>(target);

    if(pTarget && pTarget->poisonCount && pTarget != source->controller())
    {
        MTGAbility * a = NEW AAAlterPoison(game, game->mLayers->actionLayer()->getMaxId(), source, target, 1, NULL);
        a->oneShot = true;
        pcounters.push_back(a);
    }
    else if (cTarget && cTarget->counters)
    {
        Counters * counters = cTarget->counters;
        for(size_t i = 0; i < counters->counters.size(); ++i)
        {
            Counter * counter = counters->counters[i];
            MTGAbility * a = NEW AACounter(game, game->mLayers->actionLayer()->getMaxId(), source, cTarget,"", counter->name.c_str(), counter->power, counter->toughness, 1,0);
            a->oneShot = true;
            pcounters.push_back(a);
        }
    }
    if(pcounters.size())
    {
        MTGAbility * a = NEW MenuAbility(game, this->GetId(), target, source,false,pcounters);
        a->resolve();
    }
    return 1;

}

const string AAProliferate::getMenuText()
{
    return "Proliferate";
}

AAProliferate * AAProliferate::clone() const
{
    return NEW AAProliferate(*this);
}

AAProliferate::~AAProliferate()
{
}
//
//choosing a type or color
GenericChooseTypeColor::GenericChooseTypeColor(GameObserver* observer, int id, MTGCardInstance * source, Targetable *,string _toAdd,bool chooseColor,bool nonwall, ManaCost * cost) :
ActivatedAbility(observer, id, source, cost, 0), baseAbility(_toAdd),chooseColor(chooseColor),ANonWall(nonwall)
{
    this->GetId();
    setColor = NULL;
}
int GenericChooseTypeColor::resolve()
{
    if (!target)
        return 0;
    vector<MTGAbility*>selection;
    if(chooseColor)
    {
        for (int i = Constants::MTG_COLOR_GREEN; i <= Constants::MTG_COLOR_WHITE; ++i)
        {
            setColor = NEW AASetColorChosen(game, game->mLayers->actionLayer()->getMaxId(), source,(MTGCardInstance*)target, i, baseAbility);
            MTGAbility * set = setColor->clone();
            set->oneShot = true;
            selection.push_back(set);
            SAFE_DELETE(setColor);
        }
    }
    else
    {
        vector<string> values = MTGAllCards::getCreatureValuesById();
        for (size_t i = 0; i < values.size(); ++i)
        {
            string menu = values[i];
            if (!ANonWall || (menu != "wall" && menu != "Wall"))
            {
                setType = NEW AASetTypeChosen(game, game->mLayers->actionLayer()->getMaxId(), source,(MTGCardInstance*)target, i,menu,baseAbility);
                MTGAbility * set = setType->clone();
                set->oneShot = true;
                selection.push_back(set);
                SAFE_DELETE(setType);
            }
        }
    }

    if(selection.size())
    {
        MTGAbility * a1 = NEW MenuAbility(game, this->GetId(), target, source,true,selection);
        game->mLayers->actionLayer()->currentActionCard = (MTGCardInstance *)target;
        a1->resolve();
    }
    return 1;

}

const string GenericChooseTypeColor::getMenuText()
{
    if(chooseColor)
        return "Choose a color";
    else
        return "Choose a type";
}

GenericChooseTypeColor * GenericChooseTypeColor::clone() const
{
    GenericChooseTypeColor * a = NEW GenericChooseTypeColor(*this);
    return a;
}

GenericChooseTypeColor::~GenericChooseTypeColor()
{
}

//set color choosen
 AASetColorChosen::AASetColorChosen(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target,int _color , string toAlter):
    InstantAbility(observer, id, source),color(_color), abilityToAlter(toAlter)
{
    this->target = _target;
    abilityAltered = NULL;
}
int AASetColorChosen::resolve()
{
    MTGCardInstance * _target =  (MTGCardInstance *)target; 
    _target->chooseacolor = color;

    if(abilityToAlter.size())
    {
        AbilityFactory af(game);
        abilityAltered = af.parseMagicLine(abilityToAlter, 0, NULL, _target);
        if(!abilityAltered)
            return 0;
        abilityAltered->canBeInterrupted = false;
        if(abilityAltered->oneShot)
        {
            abilityAltered->resolve();
            SAFE_DELETE(abilityAltered);
        }
        else
        {
            abilityAltered->target = _target;
            MayAbility * dontAdd = dynamic_cast<MayAbility*>(abilityAltered);
            if (!dontAdd)
            {
                _target->cardsAbilities.push_back(abilityAltered);
                for(unsigned int j = 0;j < _target->cardsAbilities.size();++j)
                {
                    if(_target->cardsAbilities[j] == this)
                        _target->cardsAbilities.erase(_target->cardsAbilities.begin() + j);
                }
            }
            abilityAltered->addToGame();
        }
        _target->skipDamageTestOnce = true;//some cards rely on this ability updating before damage test are run. otherwise they die before toughnes bonus applies.
    }
    return 1;
}

const string AASetColorChosen::getMenuText()
{
    return Constants::MTGColorStrings[color];
}

AASetColorChosen * AASetColorChosen::clone() const
{
    return NEW AASetColorChosen(*this);
}

AASetColorChosen::~AASetColorChosen()
{
}

//set type choosen
 AASetTypeChosen::AASetTypeChosen(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target,int _type ,string _menu,string toAlter):
    InstantAbility(observer, id, source),type(_type), abilityToAlter(toAlter), menutext(_menu)
{
    this->target = _target;
    abilityAltered = NULL;
}
int AASetTypeChosen::resolve()
{
    MTGCardInstance * _target =  (MTGCardInstance *)target; 
    string typeChoosen = menutext;
    _target->chooseasubtype = typeChoosen;

    if(abilityToAlter.size())
    {
        AbilityFactory af(game);
        abilityAltered = af.parseMagicLine(abilityToAlter, 0, NULL, _target);
        if(abilityAltered->oneShot)
        {
            abilityAltered->resolve();
            SAFE_DELETE(abilityAltered);
        }
        else
        {
            abilityAltered->target = _target;
            MayAbility * dontAdd = dynamic_cast<MayAbility*>(abilityAltered);
            if (!dontAdd)
            {
                _target->cardsAbilities.push_back(abilityAltered);
                for(unsigned int j = 0;j < _target->cardsAbilities.size();++j)
                {
                    if(_target->cardsAbilities[j] == this)
                        _target->cardsAbilities.erase(_target->cardsAbilities.begin() + j);
                }
            }

            abilityAltered->addToGame();
        }
         _target->skipDamageTestOnce = true;//some cards rely on this ability updating before damage test are run. otherwise they die before toughnes bonus applies.
    }
    return 1;
}

const string AASetTypeChosen::getMenuText()
{
    return menutext.c_str();
}

AASetTypeChosen * AASetTypeChosen::clone() const
{
    return NEW AASetTypeChosen(*this);
}

AASetTypeChosen::~AASetTypeChosen()
{
}

//
//choosing a type or color
GenericFlipACoin::GenericFlipACoin(GameObserver* observer, int id, MTGCardInstance * source, Targetable *,string _toAdd, ManaCost * cost) :
ActivatedAbility(observer, id, source, cost, 0), baseAbility(_toAdd)
{
    this->GetId();
    setCoin = NULL;
}

int GenericFlipACoin::resolve()
{
    if (!target)
        return 0;
    vector<MTGAbility*>selection;
    for (int i = 0; i <2; ++i)
    {
        setCoin = NEW AASetCoin(game, game->mLayers->actionLayer()->getMaxId(), source,(MTGCardInstance*)target, i, baseAbility);
        MTGAbility * set = setCoin->clone();
        set->oneShot = true;
        selection.push_back(set);
        SAFE_DELETE(setCoin);
    }

    if(selection.size())
    {
        MTGAbility * a1 = NEW MenuAbility(game, this->GetId(), target, source,false,selection);
        game->mLayers->actionLayer()->currentActionCard = (MTGCardInstance *)target;
        a1->resolve();
    }
    return 1;

}

const string GenericFlipACoin::getMenuText()
{
return "Flip A Coin";
}

GenericFlipACoin * GenericFlipACoin::clone() const
{
    GenericFlipACoin * a = NEW GenericFlipACoin(*this);
    return a;
}

GenericFlipACoin::~GenericFlipACoin()
{
}

//set color choosen
 AASetCoin::AASetCoin(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target,int _side , string toAlter):
    InstantAbility(observer, id, source),side(_side), abilityToAlter(toAlter)
{
    this->target = _target;
    abilityAltered = NULL;
}

int AASetCoin::resolve()
{
    MTGCardInstance * _target =  (MTGCardInstance *)target; 
    _target->coinSide = side;

    int flip = game->getRandomGenerator()->random() % 2;
    vector<string>Win = parseBetween(abilityToAlter,"winability "," winabilityend");
    if(Win.size())
    {
        abilityWin = Win[1];
    }
    vector<string>Lose = parseBetween(abilityToAlter,"loseability "," loseabilityend");
    if(Lose.size())
    {
        abilityLose = Lose[1];
    }

    if(abilityWin.size() && flip == side)
    {
        AbilityFactory af(game);
        abilityAltered = af.parseMagicLine(abilityWin, 0, NULL, _target);
        abilityAltered->canBeInterrupted = false;
        if(abilityAltered->oneShot)
        {
            abilityAltered->resolve();
            SAFE_DELETE(abilityAltered);
        }
        else
        {
            abilityAltered->addToGame();
        }
        MTGAbility * message = NEW MTGEventText(game,this->GetId(), source, "You Won The Flip");
        message->oneShot = true;
        message->addToGame();
    }
    else if(abilityWin.size() && !abilityLose.size())
    {
        MTGAbility * message = NEW MTGEventText(game,this->GetId(), source, "You Lost The Flip");
        message->oneShot = true;
        message->addToGame();
    }
    else if(abilityLose.size() && flip != side)
    {
        AbilityFactory af(game);
        abilityAltered = af.parseMagicLine(abilityLose, 0, NULL, _target);
        abilityAltered->canBeInterrupted = false;
        if(abilityAltered->oneShot)
        {
            abilityAltered->resolve();
            SAFE_DELETE(abilityAltered);
        }
        else
        {
            abilityAltered->addToGame();
        }
        MTGAbility * message = NEW MTGEventText(game,this->GetId(), source, "You Lost The Flip");
        message->oneShot = true;
        message->addToGame();
    }
    else if(abilityLose.size())
    {
        MTGAbility * message = NEW MTGEventText(game,this->GetId(), source, "You Won The Flip");
        message->oneShot = true;
        message->addToGame();
    }
    _target->skipDamageTestOnce = true;
    return 1;
}

const string AASetCoin::getMenuText()
{
    if(side == 1)
        return "Tails";
    return "Heads";
}

AASetCoin * AASetCoin::clone() const
{
    return NEW AASetCoin(*this);
}

AASetCoin::~AASetCoin()
{
}

//paying for an ability as an effect but as a cost
GenericPaidAbility::GenericPaidAbility(GameObserver* observer, int id, MTGCardInstance * source,
    Targetable * target, string _newName, string _castRestriction, string mayCost, string _toAdd, bool asAlternate, ManaCost * cost) :
ActivatedAbility(observer, id, source, cost, 0),
    newName(_newName), restrictions(_castRestriction), baseCost(mayCost), baseAbilityStr(_toAdd), asAlternate(asAlternate)
{
    this->GetId();
    baseAbility = NULL;
    optionalCost = NULL;
}

int GenericPaidAbility::resolve()
{
    if (!target)
        return 0;

    if (restrictions.size())
    {
        AbilityFactory af(game);
        int checkCond = af.parseCastRestrictions(source,source->controller(),restrictions);
        if(!checkCond)
        {
            return 0;
        }
    }
    AbilityFactory Af(game);
    vector<string> baseAbilityStrSplit = split(baseAbilityStr,'?');
    vector<MTGAbility*> selection;
    MTGAbility * nomenuAbility = NULL;
    bool nomenu = false;
    if (baseAbilityStrSplit.size() > 1)
    {
        baseAbility = Af.parseMagicLine(baseAbilityStrSplit[0], this->GetId(), NULL, source);
        baseAbility->target = target;
        optionalCost =  ManaCost::parseManaCost(baseCost, NULL, source);

        /*// hacky way to produce better MenuText
        AAFakeAbility* isFake = dynamic_cast< AAFakeAbility* >( baseAbility );
        size_t findPayN = isFake->named.find(" {value} mana");
        if (isFake && findPayN != string::npos) {
            stringstream parseN;
            parseN << optionalCost->getCost(Constants::MTG_COLOR_ARTIFACT);
            isFake->named.replace(findPayN + 1, 7, parseN.str());
        }//commented out, it crashes cards with recover ability*/

        MTGAbility * set = baseAbility->clone();
        set->oneShot = true;
        selection.push_back(set);
        SAFE_DELETE(baseAbility);

        baseAbility = Af.parseMagicLine(baseAbilityStrSplit[1], this->GetId(), NULL, source);
        baseAbility->target = target;
        set = baseAbility->clone();
        set->oneShot = true;
        selection.push_back(set);
    }
    else
    {
        //dangerous code below, parse a string line that might not exist. baseAbilityStrSplit[0]
        //you either have a string and do stuff, or dont and leave the ability
        //not fixing this since its been heavily modified from the orginal implementation.
        nomenu = true;
        baseAbility = Af.parseMagicLine(baseAbilityStrSplit[0], this->GetId(), NULL, source);
        baseAbility->target = target;
        optionalCost =  ManaCost::parseManaCost(baseCost, NULL, source);
        MTGAbility * set = baseAbility->clone();
        nomenuAbility = baseAbility->clone();
        set->oneShot = true;
        selection.push_back(set);
    }

    if (selection.size())
    {
        bool must = baseAbilityStrSplit.size() > 1 ? true : false;
        //todo get increased - reduced cost if asAlternate cost to cast using castcard
        if(asAlternate)
        {
            must = true;
            //cost increase - reduce + trinisphere effect ability todo...
            optionalCost = ((MTGCardInstance *)target)->computeNewCost(((MTGCardInstance *)target),optionalCost,optionalCost);
            if(optionalCost->extraCosts)
            {
                for(unsigned int i = 0; i < optionalCost->extraCosts->costs.size();i++)
                    optionalCost->extraCosts->costs[i]->setSource(((MTGCardInstance *)target));
            }
        }
        if (source && source->previous && source->basicAbilities[(int)Constants::MADNESS])
        {
            must = true;
            optionalCost = source->computeNewCost(source->previous,optionalCost,optionalCost);
            if(optionalCost->extraCosts)
            {
                for(unsigned int i = 0; i < optionalCost->extraCosts->costs.size();i++)
                    optionalCost->extraCosts->costs[i]->setSource(source);
            }
        }
        if(asAlternate && nomenu && optionalCost->getConvertedCost() < 1)
            nomenuAbility->resolve();
        else
        {
            MenuAbility * a1 = NEW MenuAbility(game, this->GetId(), target, source, must, selection, NULL, newName);
            a1->optionalCosts.push_back(NEW ManaCost(optionalCost));
            game->mLayers->actionLayer()->currentActionCard = (MTGCardInstance *)target;
            a1->resolve();
        }
    }
    return 1;
}

const string GenericPaidAbility::getMenuText()
{
    if (newName.size())
        return newName.c_str();
    return "Pay For Effect";
}

GenericPaidAbility * GenericPaidAbility::clone() const
{
    GenericPaidAbility * a = NEW GenericPaidAbility(*this);
    return a;
}

GenericPaidAbility::~GenericPaidAbility()
{
    SAFE_DELETE(optionalCost);
    SAFE_DELETE(baseAbility);
}

//saves a listed mana type until end of turn.
AManaPoolSaver::AManaPoolSaver(GameObserver* observer, int id, MTGCardInstance * source,string color, bool otherPlayer) :
MTGAbility(observer, id, source),Color(color),OtherPlayer(otherPlayer)
{
}

int AManaPoolSaver::addToGame()
{
    int colorInt = Constants::GetColorStringIndex(Color.c_str());
    source->controller()->poolDoesntEmpty->add(colorInt,1);
    return 1;
}

int AManaPoolSaver::destroy()
{
    int colorInt = Constants::GetColorStringIndex(Color.c_str());
    source->controller()->poolDoesntEmpty->remove(colorInt,1);
    return 1;
}

AManaPoolSaver * AManaPoolSaver::clone() const
{
    AManaPoolSaver * a = NEW AManaPoolSaver(*this);
    return a;
}

AManaPoolSaver::~AManaPoolSaver()
{
}

//replace drawing a card with activation of an ability
ADrawReplacer::ADrawReplacer(GameObserver* observer, int id, MTGCardInstance * source, MTGAbility * replace, bool otherPlayer) :
MTGAbility(observer, id, source),re(NULL),replacer(replace),OtherPlayer(otherPlayer)
{
}

int ADrawReplacer::addToGame()
{
    SAFE_DELETE(re);
    if(OtherPlayer)
        re = NEW REDrawReplacement(this,source->controller()->opponent(),replacer);
    else
        re = NEW REDrawReplacement(this,source->controller(),replacer);
    if (re)
    {
        game->replacementEffects->add(re);
        return MTGAbility::addToGame();
    }
    return 0;
}

int ADrawReplacer::destroy()
{
    game->replacementEffects->remove(re);
    SAFE_DELETE(re);
    return 1;
}

ADrawReplacer * ADrawReplacer::clone() const
{
    ADrawReplacer * a = NEW ADrawReplacer(*this);
    a->re = NULL;
    return a;
}

ADrawReplacer::~ADrawReplacer()
{
    SAFE_DELETE(re);
    SAFE_DELETE(replacer);
}
//Reset Damage on creatures
 AAResetDamage::AAResetDamage(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target, ManaCost * cost):
    ActivatedAbility(observer, id, source, cost, 0)
{
    this->target = _target;
}
int AAResetDamage::resolve()
{
    MTGCardInstance * _target =  (MTGCardInstance *)target; 
    _target->life = _target->toughness;
    return 1;
}

const string AAResetDamage::getMenuText()
{
    return "Reset Damages";
}

AAResetDamage * AAResetDamage::clone() const
{
    return NEW AAResetDamage(*this);
}

//ability that resolves to do nothing.
 AAFakeAbility::AAFakeAbility(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target, string _named,ManaCost * cost):
    ActivatedAbility(observer, id, source, cost, 0),named(_named)
{
    this->target = _target;
}
int AAFakeAbility::resolve()
{
    return 1;
}

const string AAFakeAbility::getMenuText()
{
    if(named.size())
        return named.c_str();
    return "Ability";
}

AAFakeAbility * AAFakeAbility::clone() const
{
    return NEW AAFakeAbility(*this);
}

//EPIC
 AAEPIC::AAEPIC(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target, string _named,ManaCost * cost, bool _ffield):
    ActivatedAbility(observer, id, source, cost, 0),named(_named),FField(_ffield)
{
    this->target = _target;
}
int AAEPIC::resolve()
{  
    MTGCardInstance * _target =  (MTGCardInstance *)target;
    if(FField)
        _target->controller()->forcefield = 1;
    else
        _target->controller()->epic = 1;
    return 1;
}

const string AAEPIC::getMenuText()
{
    if(named.size())
        return named.c_str();
    return "EPIC";
}

AAEPIC * AAEPIC::clone() const
{
    return NEW AAEPIC(*this);
}

// Fizzler
AAFizzler::AAFizzler(GameObserver* observer, int _id, MTGCardInstance * card, Spell * _target, ManaCost * _cost) :
ActivatedAbility(observer, _id, card, _cost, 0)
{
    aType = MTGAbility::STANDARD_FIZZLER;
    target = _target;

    // by default we put the spell to graveyard after fizzling
    fizzleMode = ActionStack::PUT_IN_GRAVEARD;
}

int AAFizzler::resolve()
{
    ActionStack * stack = game->mLayers->stackLayer();
    //the next section helps Ai correctly recieve its targets for this effect
    if (!target && source->target)
    {
        //ai is casting a spell from its hand to fizzle.
        target = stack->getActionElementFromCard(source->target);
    }
    else if(MTGCardInstance * cTarget = dynamic_cast<MTGCardInstance *>(target))
    {
        //ai targeted using an ability on a card to fizzle.
        target = stack->getActionElementFromCard(cTarget);
    }
    Spell * sTarget = (Spell *) target;
    MTGCardInstance* sCard = NULL;
    if (sTarget)
        sCard = sTarget->source;
    if (!sCard || !sTarget || sCard->has(Constants::NOFIZZLE))
        return 0;
    if (source->alias == 111057 && sTarget)//Draining Whelk
    {
        for (int j = sTarget->cost->getConvertedCost(); j > 0; j--)
        {
            source->counters->addCounter(1,1);
        }
    }
    stack->Fizzle(sTarget, fizzleMode);
    return 1;
}

const string AAFizzler::getMenuText()
{
    return "Fizzle";
}

AAFizzler* AAFizzler::clone() const
{
    return NEW AAFizzler(*this);
}

// BanishCard implementations
// Bury

AABuryCard::AABuryCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target) :
   ActivatedAbility(observer, _id, _source)
{
    target = _target;
    andAbility = NULL;
}

int AABuryCard::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        _target->bury();
        while(_target->next)
            _target = _target->next;
        if(andAbility)
        {
            MTGAbility * andAbilityClone = andAbility->clone();
            andAbilityClone->target = _target;
            if(andAbility->oneShot)
            {
                andAbilityClone->resolve();
                SAFE_DELETE(andAbilityClone);
            }
            else
            {
                andAbilityClone->addToGame();
            }
        }
        return 1;
    }
    return 0;
}

const string AABuryCard::getMenuText()
{
    if(menu.size())
        return menu.c_str();
    return "Bury";
}

AABuryCard * AABuryCard::clone() const
{
    AABuryCard * a = NEW AABuryCard(*this);
    if(andAbility)
        a->andAbility = andAbility->clone();
    return a;
}

AABuryCard::~AABuryCard()
{
    SAFE_DELETE(andAbility);
}

// Destroy

AADestroyCard::AADestroyCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target) :
   ActivatedAbility(observer, _id, _source)
{
    target = _target;
    andAbility = NULL;
}

int AADestroyCard::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        _target->destroy();
        while(_target->next)
            _target = _target->next;
        if(andAbility)
        {
            MTGAbility * andAbilityClone = andAbility->clone();
            andAbilityClone->target = _target;
            if(andAbility->oneShot)
            {
                andAbilityClone->resolve();
                SAFE_DELETE(andAbilityClone);
            }
            else
            {
                andAbilityClone->addToGame();
            }
        }
        return 1;
    }
    return 0;
}

const string AADestroyCard::getMenuText()
{
    return "Destroy";
}

AADestroyCard * AADestroyCard::clone() const
{
    AADestroyCard * a = NEW AADestroyCard(*this);
    if(andAbility)
        a->andAbility = andAbility->clone();
    return a;

}
AADestroyCard::~AADestroyCard()
{
    SAFE_DELETE(andAbility);
}
// Sacrifice
AASacrificeCard::AASacrificeCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target) :
   ActivatedAbility(observer, _id, _source)
{
    target = _target;
    andAbility = NULL;
}

int AASacrificeCard::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        Player * p = _target->controller();
        MTGCardInstance * beforeCard = _target;
        p->game->putInGraveyard(_target);
        while(_target->next)
            _target = _target->next;
        WEvent * e = NEW WEventCardSacrifice(beforeCard,_target);
        game->receiveEvent(e);
        if(andAbility)
        {
            MTGAbility * andAbilityClone = andAbility->clone();
            andAbilityClone->target = _target;
            if(andAbility->oneShot)
            {
                andAbilityClone->resolve();
                SAFE_DELETE(andAbilityClone);
            }
            else
            {
                andAbilityClone->addToGame();
            }
        }
        return 1;
    }
    return 0;
}

const string AASacrificeCard::getMenuText()
{
    return "Sacrifice";
}

AASacrificeCard * AASacrificeCard::clone() const
{
    AASacrificeCard * a = NEW AASacrificeCard(*this);
    if(andAbility)
        a->andAbility = andAbility->clone();
    return a;
}
AASacrificeCard::~AASacrificeCard()
{
    SAFE_DELETE(andAbility);
}
// Discard 

AADiscardCard::AADiscardCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target) :
   ActivatedAbility(observer, _id, _source)
{
    target = _target;
    andAbility = NULL;
}

int AADiscardCard::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        Player * p = _target->controller();
        WEvent * e = NEW WEventCardDiscard(_target);
        game->receiveEvent(e);
        p->game->putInGraveyard(_target);
        while(_target->next)
            _target = _target->next;
        if(andAbility)
        {
            MTGAbility * andAbilityClone = andAbility->clone();
            andAbilityClone->target = _target;
            if(andAbility->oneShot)
            {
                andAbilityClone->resolve();
                SAFE_DELETE(andAbilityClone);
            }
            else
            {
                andAbilityClone->addToGame();
            }
        }
        return 1;
    }
    return 0;
}

const string AADiscardCard::getMenuText()
{
    return "Discard";
}

AADiscardCard * AADiscardCard::clone() const
{
    AADiscardCard * a = NEW AADiscardCard(*this);
    if(andAbility)
        a->andAbility = andAbility->clone();
    return a;
}
AADiscardCard::~AADiscardCard()
{
    SAFE_DELETE(andAbility);
}


//
AADrawer::AADrawer(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, string nbcardsStr,
        int who, bool noreplace) :
    ActivatedAbilityTP(observer, _id, card, _target, _cost, who), nbcardsStr(nbcardsStr),noReplace(noreplace)
{
    aType = MTGAbility::STANDARD_DRAW;
}

    int AADrawer::resolve()
    {
        Player * player = getPlayerFromTarget(getTarget());

        if (player)
        {
            WParsedInt numCards(nbcardsStr, NULL, source);
            WEvent * e = NEW WEventDraw(player, numCards.getValue(),this);
            if(!noReplace)
            e = game->replacementEffects->replace(e);
            if(e)
            {
                game->mLayers->stackLayer()->addDraw(player, numCards.getValue());
                game->mLayers->stackLayer()->resolve();
                for(int i = numCards.getValue(); i > 0;i--)
                {
                    player->drawCounter += 1;
                    if ((game->turn < 1) && game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN
                    && game->currentPlayer->game->inPlay->nb_cards == 0 && game->currentPlayer->game->graveyard->nb_cards == 0
                    && game->currentPlayer->game->exile->nb_cards == 0 && game->currentlyActing() == (Player*)game->currentPlayer) //1st Play Check
                    {
                        game->currentPlayer->drawCounter = 0;//Reset drawCounter for pre-game draw
                    }
                    WEvent * e = NEW WEventcardDraw(player, 1);
                    game->receiveEvent(e);
                }
            }
            SAFE_DELETE(e);
        }
        return 1;
    }

    int AADrawer::getNumCards()
    {
        WParsedInt numCards(nbcardsStr, NULL, source);
        return numCards.getValue();
    }

const string AADrawer::getMenuText()
{
    return "Draw";
}

AADrawer * AADrawer::clone() const
{
    return NEW AADrawer(*this);
}

// AAFrozen: Prevent a card from untapping during next untap phase
AAFrozen::AAFrozen(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, bool tap, ManaCost * _cost) :
ActivatedAbility(observer, id, card, _cost, 0)
{
    target = _target;
    freeze = tap;
}

int AAFrozen::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        while (_target->next)
            _target = _target->next; //This is for cards such as rampant growth
        if (freeze)
        {
            _target->tap();//easier to manage for cards that allow you to tap and also freeze.
        }
        _target->frozen += 1;
    }
    return 1;
}

const string AAFrozen::getMenuText()
{
    return "Freeze";
}

AAFrozen * AAFrozen::clone() const
{
    return NEW AAFrozen(*this);
}

// chose a new target for an aura or enchantment and equip it note: VERY basic right now.
AANewTarget::AANewTarget(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target,bool retarget, ManaCost * _cost, bool reequip, bool newhook) :
ActivatedAbility(observer, id, card, _cost, 0),retarget(retarget),reequip(reequip),newhook(newhook)
{
    target = _target;
}

int AANewTarget::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if(retarget)
    {
        _target = source;
        source = (MTGCardInstance *) target;
    }
    if (_target && !reequip)
    {
        while (_target->next)
            _target = _target->next; 
        _target->controller()->game->putInZone(_target, _target->currentZone,
            _target->owner->game->exile);
        _target = _target->next;

        MTGCardInstance * refreshed = source->controller()->game->putInZone(_target,_target->currentZone,source->controller()->game->battlefield);
        Spell * reUp = NEW Spell(game, refreshed);
        if(reUp->source->hasSubtype(Subtypes::TYPE_AURA))
        {
            reUp->source->target = source;
            reUp->resolve();
        }
        if(_target->hasSubtype(Subtypes::TYPE_EQUIPMENT))
        {
            reUp->resolve();
            for (size_t i = 1; i < game->mLayers->actionLayer()->mObjects.size(); i++)
            {
                MTGAbility * a = ((MTGAbility *) game->mLayers->actionLayer()->mObjects[i]);
                AEquip * eq = dynamic_cast<AEquip*> (a);
                if (eq && eq->source == reUp->source)
                {
                    ((AEquip*)a)->unequip();
                    ((AEquip*)a)->equip(source);
                }
            }
        }
        delete reUp;
        if(retarget)
        {
            target = source;
            source = _target;
        }

    }
    if (_target && _target->currentZone == _target->controller()->game->battlefield && reequip)
    {
        if(!newhook)
        {
            _target = source;
            source = (MTGCardInstance *) target;  
        }
        else
        {
            while (_target->next)
                _target = _target->next;  
        }
        if(_target->hasSubtype(Subtypes::TYPE_EQUIPMENT))
        {
            for (size_t i = 1; i < game->mLayers->actionLayer()->mObjects.size(); i++)
            {
                MTGAbility * a = ((MTGAbility *) game->mLayers->actionLayer()->mObjects[i]);
                AEquip * eq = dynamic_cast<AEquip*> (a);
                if (eq && eq->source == _target)
                {
                    ((AEquip*)a)->unequip();
                    ((AEquip*)a)->equip(source);
                }
            }
        }
        if(!newhook)
        {
            target = source;
            source = _target;
        }
    }
    return 1;
}

const string AANewTarget::getMenuText()
{
    return "New Target";
}

AANewTarget * AANewTarget::clone() const
{
    AANewTarget * a = NEW AANewTarget(*this);
    a->oneShot = 1;
    return a;
}
// morph a card
AAMorph::AAMorph(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost) :
ActivatedAbility(observer, id, card, _cost, restrictions)
{
    target = _target;
}

int AAMorph::resolve()
{
    MTGCardInstance * Morpher = (MTGCardInstance*)source;
    if(!Morpher->isMorphed && !Morpher->morphed && Morpher->turningOver)
        return 0;
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        while (_target->next)
            _target = _target->next; 

        AbilityFactory af(game);
        _target->morphed = false;
        _target->isMorphed = false;
        _target->turningOver = true;
        af.getAbilities(&currentAbilities, NULL, _target, 0);
        for (size_t i = 0; i < currentAbilities.size(); ++i)
        {
            MTGAbility * a = currentAbilities[i];
            a->source = (MTGCardInstance *) _target;
            if( a && dynamic_cast<AAMorph *> (a))
            {
                a->removeFromGame();
                game->removeObserver(a);
            }
            if (a)
            {
                if (a->oneShot)
                {
                    a->resolve();
                    delete (a);
                }
                else
                {
                    a->addToGame();
                    MayAbility * dontAdd = dynamic_cast<MayAbility*>(a);
                    if(!dontAdd)
                    {
                        _target->cardsAbilities.push_back(a);
                    }
                }
            }
        }
        currentAbilities.clear();
        testDestroy();
    }
    return 1;
}

int AAMorph::testDestroy()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if(target)
    {
        if(_target->turningOver && !_target->isMorphed && !_target->morphed)
        {
            game->removeObserver(this);
            return 1;
        }
    }
    return 0;
}

const string AAMorph::getMenuText()
{
    return "Morph";
}

AAMorph * AAMorph::clone() const
{
    AAMorph * a = NEW AAMorph(*this);
    a->forceDestroy = 1;
    return a;
}
// flip a card
AAFlip::AAFlip(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target,string flipStats) :
InstantAbility(observer, id, card, _target),flipStats(flipStats)
{
    target = _target;
}

int AAFlip::resolve()
{
    MTGCardInstance * Flipper = (MTGCardInstance*)source;
    this->oneShot = true;
    if(Flipper->isFlipped)
    {
        game->removeObserver(this);
        return 0;
    }
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        while (_target->next)
            _target = _target->next; 

        AbilityFactory af(game);
        _target->isFlipped = true;
        GameObserver * game = _target->getObserver();
        if(flipStats.size())
        {
            MTGCard * fcard = MTGCollection()->getCardByName(flipStats);
            if(!fcard) return 0;
            MTGCardInstance * myFlip = NEW MTGCardInstance(fcard, _target->controller()->game);
            _target->name = myFlip->name;
            _target->setName(myFlip->name);
            _target->colors = myFlip->colors;
            _target->types = myFlip->types;
            _target->text = myFlip->text;
            _target->formattedText = myFlip->formattedText;
            _target->basicAbilities = myFlip->basicAbilities;

            for(unsigned int i = 0;i < _target->cardsAbilities.size();i++)
            {
                MTGAbility * a = dynamic_cast<MTGAbility *>(_target->cardsAbilities[i]);

                if(a) game->removeObserver(a);
            }
            _target->cardsAbilities.clear();
            _target->magicText = myFlip->magicText;
            af.getAbilities(&currentAbilities, NULL, _target);
            for (size_t i = 0; i < currentAbilities.size(); ++i)
            {
                MTGAbility * a = currentAbilities[i];
                a->source = (MTGCardInstance *) _target;
                if (a)
                {
                    if (a->oneShot)
                    {
                        a->resolve();
                        SAFE_DELETE(a);
                    }
                    else
                    {
                        a->addToGame();
                        MayAbility * dontAdd = dynamic_cast<MayAbility*>(a);
                        if(!dontAdd)
                        {
                            _target->cardsAbilities.push_back(a);
                        }
                    }
                }
            }
            //power
            int powerMod = 0;
            int toughMod = 0;
            bool powerlessThanOriginal = false;
            bool toughLessThanOriginal = false;
            if(_target->power < _target->origpower)
            {
                powerMod = _target->origpower - _target->power;
                powerlessThanOriginal = true;
            }
            else
            {
                powerMod =_target->power - _target->origpower;
            }
            //toughness
            if(_target->toughness <= _target->origtoughness)
            {
                toughMod = _target->origtoughness - _target->toughness;
                toughLessThanOriginal = true;
            }
            else
            {
                toughMod =_target->toughness - _target->origtoughness;
            }
            _target->power = powerlessThanOriginal?myFlip->power - powerMod:myFlip->power + powerMod;
            _target->life = toughLessThanOriginal?myFlip->toughness - toughMod:myFlip->toughness + toughMod;
            _target->toughness = toughLessThanOriginal?myFlip->toughness - toughMod:myFlip->toughness + toughMod;
            _target->origpower = myFlip->origpower;
            _target->origtoughness = myFlip->origtoughness;
            SAFE_DELETE(myFlip);
            _target->mPropertiesChangedSinceLastUpdate = true;
        }

        currentAbilities.clear();
        testDestroy();
    }
    return 1;
}

int AAFlip::testDestroy()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if(target)
    {
        if(_target->isFlipped)
        {
            this->forceDestroy = 1;
            //_target->getObserver()->removeObserver(this);
            //originally added as a safegaurd to insure the ability was removed
            //it's been so long and so much has changed that it appears to do nothing but cause a crash now
            _target->isFlipped = false;
            return 1;
        }
    }
    return 0;
}

const string AAFlip::getMenuText()
{
    string s = flipStats;
    sprintf(menuText, "Transform:%s", s.c_str());
    return menuText;
}

AAFlip * AAFlip::clone() const
{
    AAFlip * a = NEW AAFlip(*this);
    a->forceDestroy = 1;
    return a;
}
// AADYNAMIC: dynamic ability builder
AADynamic::AADynamic(GameObserver* observer, int id, MTGCardInstance * card, Damageable * _target,int type,int effect,int who,int amountsource,MTGAbility * storedAbility, ManaCost * _cost) :
ActivatedAbility(observer, id, card, _cost, 0),type(type),effect(effect),who(who),amountsource(amountsource),storedAbility(storedAbility)
{
    target = _target;
    sourceamount = 0;
    targetamount = 0;
    eachother = false;
    tosrc = false;
    menu = "";
    OriginalSrc = source;
    clonedStored = NULL;
    mainAbility = NULL;
}

int AADynamic::resolve()
{
    Damageable * _target = (Damageable *) target;
    Damageable * secondaryTarget = NULL;
    if(amountsource == 2)
        source = (MTGCardInstance * )_target;
    switch(who)
    {
    case DYNAMIC_ABILITY_WHO_EACHOTHER://each other, both take the effect
        eachother = true;
        break;
    case DYNAMIC_ABILITY_WHO_ITSELF:
        source = ((MTGCardInstance *) _target);
        break;
    case DYNAMIC_ABILITY_WHO_TARGETCONTROLLER:
        secondaryTarget = ((MTGCardInstance *) _target)->controller();
        break;
    case DYNAMIC_ABILITY_WHO_TARGETOPPONENT:
        secondaryTarget = ((MTGCardInstance *) _target)->controller()->opponent();
        break;
    case DYNAMIC_ABILITY_WHO_TOSOURCE:
        tosrc = true;
        break;
    case DYNAMIC_ABILITY_WHO_SOURCECONTROLLER:
        secondaryTarget = ((MTGCardInstance *) OriginalSrc)->controller();
        break;
    case DYNAMIC_ABILITY_WHO_SOURCEOPPONENT:
        secondaryTarget = OriginalSrc->controller()->opponent();
        break;
    default:
        break;
    }
    if(amountsource == DYNAMIC_MYSELF_AMOUNT)
        _target = OriginalSrc->controller();//looking at controller for amount
    if(amountsource == DYNAMIC_MYFOE_AMOUNT)
        _target = OriginalSrc->controller()->opponent();//looking at controllers opponent for amount
    if(!_target)
        return 0;
    while (dynamic_cast<MTGCardInstance *>(_target) && ((MTGCardInstance *)_target)->next)
        _target = ((MTGCardInstance *)_target)->next;

    //find the amount variables that will be used
    sourceamount = 0;
    targetamount = 0;
    int colored = 0;
    switch(type)
    {
    case DYNAMIC_ABILITY_TYPE_POWER:
        sourceamount = ((MTGCardInstance *) source)->getCurrentPower();
        targetamount = ((MTGCardInstance *) _target)->getCurrentPower();
        if(eachother )
            sourceamount = ((MTGCardInstance *) source)->getCurrentPower();
        break;
    case DYNAMIC_ABILITY_TYPE_TOUGHNESS:
        sourceamount = ((MTGCardInstance *) source)->getCurrentToughness();
        targetamount = ((MTGCardInstance *) _target)->getCurrentToughness();
        if(eachother )
            sourceamount = ((MTGCardInstance *) source)->getCurrentToughness();
        break;
    case DYNAMIC_ABILITY_TYPE_MANACOST:
        if(amountsource == 1)
            sourceamount = ((MTGCardInstance *) source)->getManaCost()->getConvertedCost();
        else
            sourceamount = ((MTGCardInstance *) _target)->getManaCost()->getConvertedCost();
        break;
    case DYNAMIC_ABILITY_TYPE_COLORS:
        for (int i = Constants::MTG_COLOR_GREEN; i <= Constants::MTG_COLOR_WHITE; ++i)
        {
            if (amountsource == 1 && ((MTGCardInstance *)source)->hasColor(i))
                ++colored;
            else
                if (amountsource == 2 && ((MTGCardInstance *)_target)->hasColor(i))
                    ++colored;
        }
        sourceamount = colored;
        break;
    case DYNAMIC_ABILITY_TYPE_AGE:
        {
            Counter * targetCounter = NULL;
            if(amountsource == 2)
            {
                if (((MTGCardInstance *)_target)->counters && ((MTGCardInstance *)_target)->counters->hasCounter("age", 0, 0))
                {
                    targetCounter = ((MTGCardInstance *)_target)->counters->hasCounter("age", 0, 0);
                    sourceamount = targetCounter->nb;
                }
            }
            else
            {
                if (((MTGCardInstance *)source)->counters && ((MTGCardInstance *)source)->counters->hasCounter("age", 0, 0))
                {
                    targetCounter = ((MTGCardInstance *)source)->counters->hasCounter("age", 0, 0);
                    sourceamount = targetCounter->nb;
                }
            }
            break;
        }
    case DYNAMIC_ABILITY_TYPE_CHARGE:
        {
            Counter * targetCounter = NULL;
            if(amountsource == 2)
            {
                if (((MTGCardInstance *)_target)->counters && ((MTGCardInstance *)_target)->counters->hasCounter("charge", 0, 0))
                {
                    targetCounter = ((MTGCardInstance *)_target)->counters->hasCounter("charge", 0, 0);
                    sourceamount = targetCounter->nb;
                }
            }
            else
            {
                if (((MTGCardInstance *)source)->counters && ((MTGCardInstance *)source)->counters->hasCounter("charge", 0, 0))
                {
                    targetCounter = ((MTGCardInstance *)source)->counters->hasCounter("charge", 0, 0);
                    sourceamount = targetCounter->nb;
                }
            }
            break;
        }
    case DYNAMIC_ABILITY_TYPE_ONEONECOUNTERS:
        {
            Counter * targetCounter = NULL;
            if(amountsource == 2)
            {
                if (((MTGCardInstance *)_target)->counters && ((MTGCardInstance *)_target)->counters->hasCounter(1, 1))
                {
                    targetCounter = ((MTGCardInstance *)_target)->counters->hasCounter(1,1);
                    sourceamount = targetCounter->nb;
                }
            }
            else
            {
                if (((MTGCardInstance *)source)->counters && ((MTGCardInstance *)source)->counters->hasCounter(1, 1))
                {
                    targetCounter = ((MTGCardInstance *)source)->counters->hasCounter(1,1);
                    sourceamount = targetCounter->nb;
                }
            }
            break;
        }
    case DYNAMIC_ABILITY_TYPE_THATMUCH:
        {
            sourceamount = _target->thatmuch;
            break;
        }
    default:
        break;
    }

    if(secondaryTarget != NULL)
        _target = secondaryTarget;
    if (_target)
    {
        while (dynamic_cast<MTGCardInstance *>(_target) && ((MTGCardInstance *)_target)->next)
            _target = ((MTGCardInstance *)_target)->next;
        if(sourceamount < 0)
            sourceamount = 0;
        if(targetamount < 0)
            targetamount = 0;
        std::stringstream out;
        std::stringstream out2;
        out << sourceamount;
        string sourceamountstring = out.str();
        out2 << targetamount;
        string targetamountstring = out2.str();
        //set values less then 0 to 0, it was reported that negitive numbers such as a creature who get -3/-3 having the power become
        //negitive, if then used as the amount, would cuase weird side effects on resolves.
        switch(effect)
        {
        case DYNAMIC_ABILITY_EFFECT_STRIKE://deal damage
            {
                mainAbility = NEW AADamager(game, this->GetId(), source,tosrc == true?(Targetable*)OriginalSrc:(Targetable*)_target,sourceamountstring);
                activateMainAbility(mainAbility,source,tosrc == true?OriginalSrc:(MTGCardInstance*)_target);
                if(eachother)
                {
                    mainAbility = NEW AADamager(game, this->GetId(), (MTGCardInstance*)_target,(Targetable*)OriginalSrc,targetamountstring);
                    activateMainAbility(mainAbility,source,OriginalSrc);
                }
                return 1;
                break;
            }
        case DYNAMIC_ABILITY_EFFECT_DRAW://draw cards
            {
                mainAbility = NEW AADrawer(game, this->GetId(), source,_target,NULL, sourceamountstring);
                return activateMainAbility(mainAbility,source,_target);
                break;
            }
        case DYNAMIC_ABILITY_EFFECT_LIFEGAIN://gain life
            {
                mainAbility = NEW AALifer(game, this->GetId(), source,_target, sourceamountstring);
                return activateMainAbility(mainAbility,source,_target);
                break;
            }
        case DYNAMIC_ABILITY_EFFECT_PUMPPOWER://pump power
            {
                mainAbility = NEW PTInstant(game, this->GetId(), source,tosrc == true?OriginalSrc:(MTGCardInstance*)_target,NEW WParsedPT(sourceamount,0));
                return activateMainAbility(mainAbility,source,tosrc == true?OriginalSrc:(MTGCardInstance*)_target);
                break;
            }
        case DYNAMIC_ABILITY_EFFECT_PUMPTOUGHNESS://pump toughness
            {
                mainAbility = NEW PTInstant(game, this->GetId(), source,tosrc == true?OriginalSrc:(MTGCardInstance*)_target,NEW WParsedPT(0,sourceamount));
                return activateMainAbility(mainAbility,source,tosrc == true?OriginalSrc:(MTGCardInstance*)_target);
                break;
            }
        case DYNAMIC_ABILITY_EFFECT_PUMPBOTH://pump both
            {
                mainAbility = NEW PTInstant(game, this->GetId(), source,tosrc == true?OriginalSrc:(MTGCardInstance*)_target,NEW WParsedPT(sourceamount,sourceamount));
                return activateMainAbility(mainAbility,source,tosrc == true?OriginalSrc:(MTGCardInstance*)_target);
                break;
            }
        case DYNAMIC_ABILITY_EFFECT_LIFELOSS://lose life
            {
                string altered = "-";
                altered.append(sourceamountstring);
                mainAbility = NEW AALifer(game, this->GetId(), source,_target, altered);
                return activateMainAbility(mainAbility,source,_target);
                break;
            }
        case DYNAMIC_ABILITY_EFFECT_DEPLETE://deplete cards
            {
                mainAbility = NEW AADepleter(game, this->GetId(), source,_target, sourceamountstring);
                return activateMainAbility(mainAbility,source,_target);
                break;
            }
        case DYNAMIC_ABILITY_EFFECT_COUNTERSONEONE:
            {
                if(!dynamic_cast<MTGCardInstance *>(_target))
                    _target = OriginalSrc;
                for(int j = 0;j < sourceamount;j++)
                    ((MTGCardInstance*)_target)->counters->addCounter(1,1);
                break;
            }
        default:
            return 0;
        }
    }

    return 0;
}
int AADynamic::activateMainAbility(MTGAbility * toActivate,MTGCardInstance * , Damageable *)
{
    if(storedAbility)
        activateStored();
    if(!toActivate)
        return 0;
    if(PTInstant * a = dynamic_cast<PTInstant *>(toActivate))
    {
        a->addToGame();
        return 1;
    }
    toActivate->oneShot = true;
    toActivate->forceDestroy = 1;
    toActivate->resolve();
    SAFE_DELETE(toActivate);
    return 1;
}

int AADynamic::activateStored()
{
    clonedStored = storedAbility->clone();
    clonedStored->target = target;
    if (clonedStored->oneShot)
    {
        clonedStored->resolve();
        delete (clonedStored);
    }
    else
    {
        clonedStored->addToGame();
    }
    return 1;
}

const string AADynamic::getMenuText()
{
    if (menu.size())
    {
        return menu.c_str();
    }

    switch(type)
    {
    case 0:
        menu.append("Power");
        break;
    case 1:
        menu.append("Tough");
        break;
    case 2:
        menu.append("Mana");
        break;
    case 3:
        menu.append("color");
        break;
    case 4:
        menu.append("Elder");
        break;
    case 5:
        menu.append("Charged");
        break;
    case 6:
        menu.append("Counter");
        break;
    case 7:
        menu.append("That Many ");
        break;
    default:
        break;
    }

    switch(effect)
    {
    case 0:
        menu.append("Strike");
        break;
    case 1:
        menu.append("Draw");
        break;
    case 2:
        menu.append("Life");
        break;
    case 3:
        menu.append("Pump");
        break;
    case 4:
        menu.append("Fortify");
        break;
    case 5:
        menu.append("Buff");
        break;
    case 6:
        menu.append("Drain");
        break;
    case 7:
        menu.append("Deplete!");
        break;
    case 8:
        menu.append("Counters!");
        break;
    default:
        break;
    }
    
    return menu.c_str();
}

AADynamic * AADynamic::clone() const
{
    AADynamic * a = NEW AADynamic(*this);
    a->storedAbility = storedAbility? storedAbility->clone() : NULL;
    return a;
}

AADynamic::~AADynamic()
{
    SAFE_DELETE(storedAbility);
}

//AALifer
AALifer::AALifer(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target, string life_s, ManaCost * _cost, int who) :
ActivatedAbilityTP(observer, _id, card, _target, _cost, who),life_s(life_s)
{
    aType = MTGAbility::LIFER;
}

int AALifer::resolve()
{  
    Damageable * _target = (Damageable *) getTarget();
    if (!_target)
        return 0;

    WParsedInt life(life_s, NULL, source);
    if (_target->type_as_damageable == Damageable::DAMAGEABLE_MTGCARDINSTANCE)
    {
        _target = ((MTGCardInstance *) _target)->controller();
    }
    Player *player = (Player*)_target;
    player->gainOrLoseLife(life.getValue());

    return 1;
}

int AALifer::getLife()
{
    WParsedInt life(life_s, NULL, source);
    return life.getValue();
}

const string AALifer::getMenuText()
{
    if(getLife() < 0)
        return "Life Loss";
    return "Life";
}

AALifer * AALifer::clone() const
{
    return NEW AALifer(*this);
}

//players modify hand size
AModifyHand::AModifyHand(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable * _target, string hand, int who) :
    AbilityTP(observer, _id, _source, _target, who), hand(hand)
{
}

int AModifyHand::addToGame()
{
    Damageable * _target = (Damageable *) getTarget();
    Player * p = getPlayerFromDamageable(_target);

    if (!p)
        return 0;

    WParsedInt handmodifier(hand, NULL, source);
    p->handmodifier += handmodifier.getValue();

    return MTGAbility::addToGame();
}

int AModifyHand::destroy()
{
    Damageable * _target = (Damageable *) getTarget();
    Player * p = getPlayerFromDamageable(_target);

    if (!p)
        return 0;
    
    WParsedInt handmodifier(hand, NULL, source);
    p->handmodifier -= handmodifier.getValue();

    return 1;
}

const string AModifyHand::getMenuText()
{
    return "Modify Hand Size";
}

AModifyHand * AModifyHand::clone() const
{
    return NEW AModifyHand(*this);
}

//players max hand size
AASetHand::AASetHand(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable * _target, int hand, ManaCost * _cost,
        int who) :
    ActivatedAbilityTP(observer, _id, _source, _target, _cost, who), hand(hand)
{
}

int AASetHand::resolve()
{
    Damageable * _target = (Damageable *) getTarget();
    Player * p = getPlayerFromDamageable(_target);

    if (!p)
        return 0;

    p->handsize = hand;

    return 1;
}

const string AASetHand::getMenuText()
{
    return "Set Hand Size";
}

AASetHand * AASetHand::clone() const
{
    return NEW AASetHand(*this);
}

//Lifeset
AALifeSet::AALifeSet(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable * _target, WParsedInt * life, ManaCost * _cost,
        int who) :
    ActivatedAbilityTP(observer, _id, _source, _target, _cost, who), life(life)
{
}

int AALifeSet::resolve()
{
    Damageable * _target = (Damageable *) getTarget();
    Player * p = getPlayerFromDamageable(_target);

    if (!p)
        return 0;

    int lifeDiff = life->getValue() - p->life ;
    p->gainOrLoseLife(lifeDiff);

    return 1;
}

const string AALifeSet::getMenuText()
{
    return "Set Life";
}

AALifeSet * AALifeSet::clone() const
{
    AALifeSet * a = NEW AALifeSet(*this);
    a->life = NEW WParsedInt(*(a->life));
    return a;
}

AALifeSet::~AALifeSet()
{
    SAFE_DELETE(life);
}

//AACloner 
//cloning...this makes a token thats a copy of the target.
AACloner::AACloner(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost, int who,
        string abilitiesStringList,string TypesList) :
    ActivatedAbility(observer, _id, _source, _cost, 0), who(who)
{
    aType = MTGAbility::CLONING;
    target = _target;
    source = _source;
    if (abilitiesStringList.size() > 0)
    {
        PopulateAbilityIndexVector(awith, abilitiesStringList);
        PopulateColorIndexVector(colors, abilitiesStringList);
    }
    if (TypesList.size())
    {
        PopulateSubtypesIndexVector(typesToAdd,TypesList);
    }

}

int AACloner::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (!_target)
        return 0;

    // Use id of the card to have the same image as the original
    MTGCard* clone = (_target->isToken ? _target: MTGCollection()->getCardById(_target->getId()));

    // If its a copier then copy what it is
    if(_target->isACopier)
        clone = _target;

    Player * targetPlayer = who == 1 ? source->controller()->opponent() : source->controller();

    int tokenize = 1;//tokenizer support for cloning
    if (targetPlayer->game->battlefield->hasAbility(Constants::TOKENIZER))
    {
        int nbcards = targetPlayer->game->battlefield->nb_cards;
        for (int j = 0; j < nbcards; j++)
        {
            if (targetPlayer->game->battlefield->cards[j]->has(Constants::TOKENIZER))
                tokenize *= 2;
        }
    }

    for (int i = 0; i < tokenize; ++i)
    {
        MTGCardInstance * myClone = NEW MTGCardInstance(clone, targetPlayer->game);
        targetPlayer->game->temp->addCard(myClone);
                
        Spell * spell = NEW Spell(game, myClone);
        spell->source->isToken = 1;
        spell->resolve();
        spell->source->fresh = 1;
        spell->source->model = spell->source;
        spell->source->model->data = spell->source;
        //if the token doesn't have cda/dynamic pt then allow this...
        if((_target->isToken) && (!_target->isCDA))
        {
            if(_target->pbonus > 0)
                spell->source->power = _target->power - _target->pbonus;
            else
                spell->source->power = _target->power + abs(_target->pbonus);
            if(_target->tbonus > 0)
            {
                spell->source->toughness = _target->toughness - _target->tbonus;
                spell->source->life = _target->toughness - _target->tbonus;
            }
            else
            {
                spell->source->toughness = _target->toughness + abs(_target->tbonus);
                spell->source->life = _target->toughness + abs(_target->tbonus);
            }
        }
        list<int>::iterator it;
        for (it = awith.begin(); it != awith.end(); it++)
        {//there must be a layer of temporary abilities and original abilities
            spell->source->basicAbilities[*it] = 1;
        }
        for (it = colors.begin(); it != colors.end(); it++)
        {
            spell->source->setColor(*it);
        }
        for (it = typesToAdd.begin(); it != typesToAdd.end(); it++)
        {
            spell->source->addType(*it);
        }
        spell->source->modifiedbAbi = _target->modifiedbAbi;
        spell->source->origbasicAbilities = _target->origbasicAbilities;
        delete spell;
    }
    return 1;

}

const string 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
{
    return NEW AACloner(*this);
}
AACloner::~AACloner()
{
}

// Cast/Play Restriction modifier
ACastRestriction::ACastRestriction(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target, TargetChooser * _restrictionsScope, WParsedInt * _value, bool _modifyExisting, int _zoneId, int who) :
   AbilityTP(observer, _id, card, _target, who), restrictionsScope(_restrictionsScope), value(_value), modifyExisting(_modifyExisting),zoneId(_zoneId)
{
    existingRestriction = NULL;
    targetPlayer = NULL;
}

int ACastRestriction::addToGame()
{
    Targetable * _target = getTarget();
    targetPlayer = getPlayerFromTarget(_target);
    if (!targetPlayer)
        return 0;

    if (modifyExisting)
    {
        //For now the only modifying rule is the one for lands, so this is hardcoded here.
        //This means that a modifying rule for anything lands will actually modify the lands rule.
        //In the future, we need a way to "identify" rules that modify an existing restriction, probably by doing a comparison of the TargetChoosers
        existingRestriction = targetPlayer->game->playRestrictions->getMaxPerTurnRestrictionByTargetChooser(restrictionsScope);
        if(existingRestriction && existingRestriction->maxPerTurn != MaxPerTurnRestriction::NO_MAX)
            existingRestriction->maxPerTurn += value->getValue();
    }
    else
    {
        TargetChooser * _tc = restrictionsScope->clone();
        existingRestriction = NEW MaxPerTurnRestriction(_tc, value->getValue(), MTGGameZone::intToZone(zoneId, targetPlayer));
        targetPlayer->game->playRestrictions->addRestriction(existingRestriction);

    }
    AbilityTP::addToGame();
    return 1;
}

int ACastRestriction::destroy()
{
    if (!existingRestriction)
        return 0;

    if (modifyExisting)
    {
        if(existingRestriction->maxPerTurn != MaxPerTurnRestriction::NO_MAX)
            existingRestriction->maxPerTurn -= value->getValue();
    }
    else
    {
         targetPlayer->game->playRestrictions->removeRestriction(existingRestriction);
         SAFE_DELETE(existingRestriction);
    }
    return 1;
}

const string ACastRestriction::getMenuText()
{
    if (modifyExisting)
        return "Additional Lands"; //hardoced because only the lands rule allows to modify existing rule for now
    return "Cast Restriction";
}

ACastRestriction * ACastRestriction::clone() const
{
    ACastRestriction * a = NEW ACastRestriction(*this);
    a->value = NEW WParsedInt(*(a->value));
    a->restrictionsScope = restrictionsScope->clone();
    return a;
}

ACastRestriction::~ACastRestriction()
{
    SAFE_DELETE(value);
    SAFE_DELETE(restrictionsScope);
}


AInstantCastRestrictionUEOT::AInstantCastRestrictionUEOT(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target, TargetChooser * _restrictionsScope, WParsedInt * _value, bool _modifyExisting, int _zoneId, int who) :
    InstantAbilityTP(observer, _id, card, _target, who)
{
    ability = NEW ACastRestriction(observer, _id, card, _target, _restrictionsScope, _value, _modifyExisting,  _zoneId, who);
}

int AInstantCastRestrictionUEOT::resolve()
{
    ACastRestriction * a = ability->clone();
    GenericInstantAbility * wrapper = NEW GenericInstantAbility(game, 1, source, (Damageable *) (this->target), a);
    wrapper->addToGame();
    return 1;
}
const string AInstantCastRestrictionUEOT::getMenuText()
{
    return ability->getMenuText();
}

AInstantCastRestrictionUEOT * AInstantCastRestrictionUEOT::clone() const
{
    AInstantCastRestrictionUEOT * a = NEW AInstantCastRestrictionUEOT(*this);
    a->ability = this->ability->clone();
    return a;
}

AInstantCastRestrictionUEOT::~AInstantCastRestrictionUEOT()
{
    SAFE_DELETE(ability);
}


//AAMover
AAMover::AAMover(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, string dest,string newName, ManaCost * _cost, bool undying, bool persist) :
    ActivatedAbility(observer, _id, _source, _cost, 0), destination(dest),named(newName),undying(undying),persist(persist)
{
    if (_target)
        target = _target;
    andAbility = NULL;
}

MTGGameZone * AAMover::destinationZone(Targetable * target)
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    return MTGGameZone::stringToZone(game, destination, source, _target);
}

int AAMover::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (target)
    {
        Player* p = _target->controller();
        if (p)
        {
            MTGGameZone * fromZone = _target->getCurrentZone();
            MTGGameZone * destZone = destinationZone(target);

            //inplay is a special zone !
            for (int i = 0; i < 2; i++)
            {
                if (!_target->hasSubtype(Subtypes::TYPE_AURA) && destZone == game->players[i]->game->inPlay && fromZone != game->players[i]->game->inPlay && fromZone
                        != game->players[i]->opponent()->game->inPlay)
                {
                    MTGCardInstance * copy = game->players[i]->game->putInZone(_target, fromZone, game->players[i]->game->temp);
                    Spell * spell = NEW Spell(game, copy);
                    spell->resolve();
                    if(andAbility)
                    {
                        MTGAbility * andAbilityClone = andAbility->clone();
                        andAbilityClone->target = spell->source;
                        if(andAbility->oneShot)
                        {
                            andAbilityClone->resolve();
                            SAFE_DELETE(andAbilityClone);
                        }
                        else
                        {
                            andAbilityClone->addToGame();
                        }
                    }
                    if(persist)
                        spell->source->counters->addCounter(-1,-1);
                    if(undying)
                        spell->source->counters->addCounter(1,1);
                    delete spell;
                    return 1;
                }
                if (destZone == game->players[i]->game->graveyard && fromZone == game->players[i]->game->hand)
                {
                //movers that take a card from hand and place them in graveyard are always discards. we send an event for it here.

                    WEvent * e = NEW WEventCardDiscard(_target);
                    game->receiveEvent(e);
                }

            }

            if(_target->hasSubtype(Subtypes::TYPE_AURA) && (destZone == game->players[0]->game->inPlay || destZone == game->players[1]->game->inPlay))
            {//put into play aura if there is no valid targets then it will be in its current zone
                MTGAbility *a = NEW AACastCard(game, game->mLayers->actionLayer()->getMaxId(), _target, _target,false,false,false,"","Put in play",false,true);
                a->oneShot = false;
                a->canBeInterrupted = false;
                a->addToGame();
                if(andAbility && _target->next)
                {//if successful target->next should be valid
                    MTGAbility * andAbilityClone = andAbility->clone();
                    andAbilityClone->target = _target->next;
                    if(andAbility->oneShot)
                    {
                        andAbilityClone->resolve();
                        SAFE_DELETE(andAbilityClone);
                    }
                    else
                    {
                        andAbilityClone->addToGame();
                    }
                }
            }
            else
            {
                p->game->putInZone(_target, fromZone, destZone);
                while(_target->next)
                    _target = _target->next;
                if(andAbility)
                {
                    MTGAbility * andAbilityClone = andAbility->clone();
                    andAbilityClone->target = _target;
                    if(andAbility->oneShot)
                    {
                        andAbilityClone->resolve();
                        SAFE_DELETE(andAbilityClone);
                    }
                    else
                    {
                        andAbilityClone->addToGame();
                    }
                }
            }
            return 1;
        }
    }
    return 0;
}

const string AAMover::getMenuText()
{
    if(named.size())
        return named.c_str();
    return "Move";
}

const char* AAMover::getMenuText(TargetChooser * tc)
{
    if(named.size())
        return named.c_str();
    MTGGameZone * dest = destinationZone();

    for (int i = 0; i < 2; i++)
    {
        // Move card to hand
        if (dest == game->players[i]->game->hand)
        {
            if (tc->targetsZone(game->players[i]->game->inPlay))
                return "Bounce";
            if (tc->targetsZone(game->players[i]->game->graveyard))
                return "Reclaim";
            if (tc->targetsZone(game->opponent()->game->hand))
                return "Steal";
        }

        // Move card to graveyard
        else if (dest == game->players[i]->game->graveyard)
        {
            if (tc->targetsZone(game->players[i]->game->inPlay))
                return "Sacrifice";
            if (tc->targetsZone(game->players[i]->game->hand))
                return "Discard";
            if (tc->targetsZone(game->opponent()->game->hand))
                return "Opponent Discards";
        }

        // move card to library
        else if (dest == game->players[i]->game->library)
        {
            if (tc->targetsZone(game->players[i]->game->graveyard))
                return "Recycle";
            return "Put in Library";
        }

        // move card to battlefield
        else if (dest == game->players[i]->game->battlefield)
        {
            if (tc->targetsZone(game->players[i]->game->graveyard))
                return "Reanimate";
            return "Put in Play";
        }

        // move card into exile
        else if (dest == game->players[i]->game->exile)
        {
            return "Exile";
        }

        // move card from Library
        else if (tc->targetsZone(game->players[i]->game->library))
        {
            return "Fetch";
        }
    }

    return "Move";
}

AAMover * AAMover::clone() const
{
    AAMover * a = NEW AAMover(*this);
    if(andAbility)
    a->andAbility = andAbility->clone();
    return a;
}

AAMover::~AAMover()
{
SAFE_DELETE(andAbility);
}

//random movement of a card from zone to zone
AARandomMover::AARandomMover(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target, string _tcs, string _from, string _to) :
    ActivatedAbility(observer, _id, _source, NULL, 0), abilityTC(_tcs),fromZone(_from),toZone(_to)
{
    if (_target)
        target = _target;
}

MTGGameZone * AARandomMover::destinationZone(Targetable * target,string zone)
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    return MTGGameZone::stringToZone(game, zone, source, _target);
}

int AARandomMover::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (target)
    {
        Player* p = _target->controller();
        if (p)
        {
            MTGGameZone * fromDest = destinationZone(target,fromZone);
            MTGGameZone * toDest = destinationZone(target,toZone);

            if (!fromDest->nb_cards)
                return 0;

            TargetChooserFactory tcf(game);
            TargetChooser * rTc = tcf.createTargetChooser(abilityTC, source);
            rTc->targetter = NULL;
            rTc->setAllZones();
            vector<MTGCardInstance*>selectedCards;
            for(unsigned int i = 0; i < fromDest->cards.size();++i)
            {
                if(rTc->canTarget(fromDest->cards[i]))
                    selectedCards.push_back(fromDest->cards[i]);
            }
            SAFE_DELETE(rTc);
            if(!selectedCards.size())
                return 0;
            int r = fromDest->owner->getObserver()->getRandomGenerator()->random() % (selectedCards.size());
            MTGCardInstance * toMove = selectedCards[r];


            //inplay is a special zone !
            for (int i = 0; i < 2; i++)
            {
                if (toDest == game->players[i]->game->inPlay && fromDest != game->players[i]->game->inPlay && fromDest
                        != game->players[i]->opponent()->game->inPlay)
                {
                    MTGCardInstance * copy = game->players[i]->game->putInZone(toMove, fromDest, game->players[i]->game->temp);
                    Spell * spell = NEW Spell(game, copy);
                    spell->resolve();
                    delete spell;
                    return 1;
                }
            }
            p->game->putInZone(toMove, fromDest, toDest);
            return 1;
        }
    }
    return 0;
}

const string AARandomMover::getMenuText()
{
    return "Dig";
}

AARandomMover * AARandomMover::clone() const
{
    AARandomMover * a = NEW AARandomMover(*this);
    return a;
}

AARandomMover::~AARandomMover()
{
}

//Random Discard
AARandomDiscarder::AARandomDiscarder(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target,string nbcardsStr, ManaCost * _cost,
         int who) :
    ActivatedAbilityTP(observer, _id, card, _target, _cost, who), nbcardsStr(nbcardsStr)
{
}

int AARandomDiscarder::resolve()
{
    Targetable * _target = getTarget();
    Player * player = getPlayerFromTarget(_target);
    if (player)
    {
        WParsedInt numCards(nbcardsStr, NULL, source);
        for (int i = 0; i < numCards.intValue; i++)
        {
            player->game->discardRandom(player->game->hand, source);
        }
    }
            
    return 1;
}

const string AARandomDiscarder::getMenuText()
{
    return "Discard Random";
}

AARandomDiscarder * AARandomDiscarder::clone() const
{
    return NEW AARandomDiscarder(*this);
}

// Shuffle 
AAShuffle::AAShuffle(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, int who) :
    ActivatedAbilityTP(observer, _id, card, _target, _cost, who)
{
}

int AAShuffle::resolve()
{
    Player * player = getPlayerFromTarget(getTarget());
    if (player)
    {
        MTGLibrary * library = player->game->library;
        library->shuffle();
    }
    return 1;
}

const string AAShuffle::getMenuText()
{
    return "Shuffle";
}

AAShuffle * AAShuffle::clone() const
{
    return NEW AAShuffle(*this);
}

// Mulligan 
AAMulligan::AAMulligan(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, int who) :
    ActivatedAbilityTP(observer, _id, card, _target, _cost, who)
{
}

int AAMulligan::resolve()
{
    Player * player = getPlayerFromTarget(getTarget());
    if (player)
    {
            player->serumMulligan();
    }
    return 1;
}

const string AAMulligan::getMenuText()
{
    return "Mulligan";
}

AAMulligan * AAMulligan::clone() const
{
    return NEW AAMulligan(*this);
}

// Remove Mana From ManaPool
AARemoveMana::AARemoveMana(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target, string manaDesc, int who) :
    ActivatedAbilityTP(observer, _id, card, _target, NULL, who)
{
    if (!manaDesc.size())
    {
        DebugTrace("ALL_ABILITIES: AARemoveMana ctor error"); 
        return;
    }
    mRemoveAll = (manaDesc[0] == '*');
    if (mRemoveAll)
        manaDesc = manaDesc.substr(1);
    
    mManaDesc = (manaDesc.size()) ? ManaCost::parseManaCost(manaDesc) : NULL;

}

int AARemoveMana::resolve()
{
    Player * player = getPlayerFromTarget(getTarget());
    if (player)
    {
        ManaPool * manaPool = player->getManaPool();
        if (mRemoveAll)
        {
            if (mManaDesc) // Remove all mana Matching a description
            {
                for (int i = 0; i < Constants::NB_Colors; i++)
                {
                    if (mManaDesc->hasColor(i))
                        manaPool->removeAll(i);
                }
            }
            else //Remove all mana
            {
                if(game->getCurrentGamePhase() != MTG_PHASE_ENDOFTURN)
                {
                    if (player->doesntEmpty->getConvertedCost() && !player->poolDoesntEmpty->getConvertedCost())
                    {
                        ManaCost * toRemove =  manaPool->Diff(player->doesntEmpty);
                        player->getManaPool()->pay(toRemove);
                        delete(toRemove);
                        return 1;
                    }
                    else if(!player->doesntEmpty->getConvertedCost() && player->poolDoesntEmpty->getConvertedCost())
                    {
                        ManaCost * toSave = NEW ManaCost();
                        for(int k = Constants::MTG_COLOR_ARTIFACT; k < Constants::NB_Colors;k++)
                        {
                            if(player->poolDoesntEmpty->getCost(k))
                                toSave->add(k,manaPool->getCost(k));
                        }
                        player->getManaPool()->pay(manaPool->Diff(toSave));
                        delete(toSave);
                        return 1;
                    }
                    else if(player->doesntEmpty->getConvertedCost() && player->poolDoesntEmpty->getConvertedCost())
                    {
                        ManaCost * toSave = NEW ManaCost();
                        for(int k = Constants::MTG_COLOR_ARTIFACT; k < Constants::NB_Colors;k++)
                        {
                            if(player->poolDoesntEmpty->getCost(k))
                            {
                                toSave->add(k,manaPool->getCost(k));//save the whole amount of k;
                            }
                            else if(player->doesntEmpty->getCost(k))
                            {
                                toSave->add(k,player->doesntEmpty->getCost(k));//save the amount of doesnt empty
                            }
                        }
                        player->getManaPool()->pay(manaPool->Diff(toSave));//remove the manacost equal to the difference of toSave and the manapool.
                        delete(toSave);
                        return 1;
                    }
                    manaPool->Empty();
                }
                else
                    manaPool->Empty();
            }
        }
        else //remove a "standard" mana Description
        {
            ((ManaCost *)manaPool)->remove(mManaDesc); //why do I have to cast here?
        }
    }
    return 1;
}

const string AARemoveMana::getMenuText()
{
    if (mRemoveAll && !mManaDesc)
        return "Empty Manapool";
    return "Remove Mana";
}

AARemoveMana * AARemoveMana::clone() const
{
    AARemoveMana * a = NEW AARemoveMana(*this);
    a->mManaDesc = mManaDesc ? NEW ManaCost(mManaDesc) : NULL;
    return a;
}

AARemoveMana::~AARemoveMana()
{
    SAFE_DELETE(mManaDesc);
}

//Bestow
ABestow::ABestow(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost) :
    ActivatedAbility(observer, id, card, _cost, 0)
{
    target = _target;
    aType = MTGAbility::TAPPER;
    _card = card;
}

int ABestow::resolve()
{
    if (target)
    {
        if (_card->hasType("creature"))
        {
            _card->removeType("creature");
            _card->addType("aura");
        }
        _card->target = (MTGCardInstance*)target;
        _card->isBestowed = true;
    }
    return 1;
}

const string ABestow::getMenuText()
{
    return "Bestow";
}

ABestow * ABestow::clone() const
{
    return NEW ABestow(*this);
}

//Tapper
AATapper::AATapper(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost, bool sendNoEvent) :
    ActivatedAbility(observer, id, card, _cost, 0),_sendNoEvent(sendNoEvent)
{
    target = _target;
    aType = MTGAbility::TAPPER;
}

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(_sendNoEvent);
    }
    return 1;
}

const string AATapper::getMenuText()
{
    return "Tap";
}

AATapper * AATapper::clone() const
{
    return NEW AATapper(*this);
}

//AA Untapper
AAUntapper::AAUntapper(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost) :
    ActivatedAbility(observer, id, card, _cost, 0)
{
    target = _target;
    aType = MTGAbility::UNTAPPER;
}

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 string AAUntapper::getMenuText()
{
    return "Untap";
}

AAUntapper * AAUntapper::clone() const
{
    return NEW AAUntapper(*this);
}

AAWhatsMax::AAWhatsMax(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance *, ManaCost * _cost, int value) :
    ActivatedAbility(observer, id, card, _cost, 0), value(value)
{
}

int AAWhatsMax::resolve()
{

    if (source)
    {
        source->MaxLevelUp = value;
        source->isLeveler = 1;
    }
    return 1;
}

AAWhatsMax * AAWhatsMax::clone() const
{
    return NEW AAWhatsMax(*this);
}
//set X value
AAWhatsX::AAWhatsX(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance *, int value, MTGAbility * _costRule) :
    ActivatedAbility(observer, id, card, NULL, 0), value(value),costRule(_costRule)
{
}

int AAWhatsX::resolve()
{
    if (source)
    {
        source->setX = value;
        
    }
    costRule->reactToClick(source);
    return 1;
}

AAWhatsX * AAWhatsX::clone() const
{
    return NEW AAWhatsX(*this);
}
//count objects on field before doing an effect
AACountObject::AACountObject(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance *, ManaCost * _cost, string value) :
    ActivatedAbility(observer, id, card, _cost, 0), value(value)
{
}

int AACountObject::resolve()
{

    if (source)
    {
        int amount = 0;
        WParsedInt * use = NEW WParsedInt(value, NULL, source);
        amount = use->getValue();
        source->CountedObjects = amount;
        SAFE_DELETE(use);
    }
    return 1;
}

AACountObject * AACountObject::clone() const
{
    return NEW AACountObject(*this);
}

// Win Game
AAWinGame::AAWinGame(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost, int who) :
    ActivatedAbilityTP(observer, _id, card, _target, _cost, who)
{
}

int AAWinGame::resolve()
{
    Player * p = getPlayerFromDamageable((Damageable *) getTarget());
    if (!p)
        return 0;

    bool canwin = true;

    MTGGameZone * z = p->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))
        {
            canwin = false;
            break;
        }
    }

    if (canwin)
    {
        MTGGameZone * k = p->game->inPlay;
        int onbcards = k->nb_cards;
        for (int m = 0; m < onbcards; ++m)
        {
            MTGCardInstance * e = k->cards[m];
            if (e->has(Constants::CANTWIN))
            {
                canwin = false;
                break;
            }
        }
    }

    if (canwin)
    {
        game->setLoser(p->opponent());
    }

    return 1;
}

const string AAWinGame::getMenuText()
{
    return "Win Game";
}

AAWinGame * AAWinGame::clone() const
{
    return NEW AAWinGame(*this);
}

//Generic Abilities

//a new affinity
ANewAffinity::ANewAffinity(GameObserver* observer, int _id, MTGCardInstance * _source, string Tc, string mana) :
MTGAbility(observer, _id, _source), tcString(Tc), manaString(mana)
{
}

void ANewAffinity::Update(float)
{
    testDestroy();
    return;
}

int ANewAffinity::testDestroy()
{
    if(this->source->isInPlay(game))
        return 1;
    return 0;
}
ANewAffinity * ANewAffinity::clone() const
{
    return NEW ANewAffinity(*this);
}

//IfThenEffect
IfThenAbility::IfThenAbility(GameObserver* observer, int _id, MTGAbility * delayedAbility, MTGAbility * delayedElseAbility, MTGCardInstance * _source, Targetable * _target, int type,string Cond) :
InstantAbility(observer, _id, _source),delayedAbility(delayedAbility),delayedElseAbility(delayedElseAbility), type(type),Cond(Cond)
{
    target = _target;
}

int IfThenAbility::resolve()
{
    MTGCardInstance * card = (MTGCardInstance*)source;
    AbilityFactory af(game);
    Targetable* aTarget = (Targetable*)target;
    int checkCond = af.parseCastRestrictions(card,card->controller(),Cond);
    if(Cond.find("cantargetcard(") != string::npos)
    {
        TargetChooser * condTc = NULL;
        vector<string>splitTarget = parseBetween(Cond, "card(", ")");
        if (splitTarget.size())
        {
            TargetChooserFactory tcf(game);
            condTc = tcf.createTargetChooser(splitTarget[1], source);
            condTc->targetter = NULL;
            if(aTarget)
                checkCond = condTc->canTarget(aTarget);
            SAFE_DELETE(condTc);
        }

    }
    MTGAbility * a1 = NULL;
    if((checkCond && type == 1)||(!checkCond && type == 2))
    {
        a1 = delayedAbility->clone();
    }
    else if(delayedElseAbility)
    {
        a1 = delayedElseAbility->clone();
    }
    if (!a1)
        return 0;
    else
    {
        if(a1->target && !dynamic_cast<Player *>(a1->target))
            a1->target = aTarget;

        if(a1->oneShot)
        {
            a1->resolve();
            SAFE_DELETE(a1);
        }
        else
            a1->addToGame();
        return 1;
    }
    return 0;
}

const string IfThenAbility::getMenuText()
{
    return "";
}

IfThenAbility * IfThenAbility::clone() const
{
    IfThenAbility * a = NEW IfThenAbility(*this);
    a->delayedAbility = delayedAbility->clone();
    return a;
}

IfThenAbility::~IfThenAbility()
{
    SAFE_DELETE(delayedAbility);
    SAFE_DELETE(delayedElseAbility);
}
//
//May Abilities
MayAbility::MayAbility(GameObserver* observer, int _id, MTGAbility * _ability, MTGCardInstance * _source, bool must,string _cond) :
    MTGAbility(observer, _id, _source), NestedAbility(_ability), must(must), Cond(_cond)
{
    triggered = 0;
    mClone = NULL;
}

void MayAbility::Update(float dt)
{
    MTGAbility::Update(dt);
    if (!triggered && !game->getCurrentTargetChooser() && (!game->mLayers->actionLayer()->menuObject||game->mLayers->actionLayer()->menuObject == source))
    {
        triggered = 1;
        if(Cond.size())
        {
            AbilityFactory af(game);
            int checkCond = af.parseCastRestrictions(source,source->controller(),Cond);
            if(!checkCond)
            {
                return;
            }
        }
        if (TargetAbility * ta = dynamic_cast<TargetAbility *>(ability))
        {
            if (!ta->getActionTc()->validTargetsExist() || ta->getActionTc()->maxtargets == 0)
                return;
        }
        game->mLayers->actionLayer()->setMenuObject(source, must);
        previousInterrupter = game->isInterrupting;
        game->mLayers->stackLayer()->setIsInterrupting(source->controller(), false);
    }
}

const string 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;
    if(game->currentPlayer == source->controller() && game->isInterrupting == source->controller() && dynamic_cast<AManaProducer*>(AbilityFactory::getCoreAbility(ability)))
        //if its my turn, and im interrupting myself(why?) then set interrupting to previous interrupter if the ability was a manaability
        //special case since they don't use the stack.
        game->mLayers->stackLayer()->setIsInterrupting(previousInterrupter, false);
    return 1;
}

int MayAbility::isReactingToTargetClick(Targetable * card)
{
    if (card == source)
    {
        if(Cond.size())
        {
            AbilityFactory af(game);
            int checkCond = af.parseCastRestrictions(source,source->controller(),Cond);
            if(!checkCond)
            {
                return 0;
            }
        }
        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();
    return a;
}

MayAbility::~MayAbility()
{
    SAFE_DELETE(ability);
}

//Menu building ability Abilities
MenuAbility::MenuAbility(GameObserver* observer, int _id, Targetable * mtarget, MTGCardInstance * _source, bool must,vector<MTGAbility*>abilities,Player * who, string newName) :
MayAbility(observer, _id,NULL,_source,must), must(must),abilities(abilities),who(who),newNameString(newName)
{
    triggered = 0;
    mClone = NULL;
    this->target = mtarget;
    removeMenu = false;
    vector<ManaCost*>optionalCost = vector<ManaCost*>();
    toPay = NULL;
    processed = false;
}

bool MenuAbility::CheckUserInput(JButton key)
{
    if (game->mExtraPayment && key == JGE_BTN_SEC)
    {
        if(toPay && toPay->extraCosts == game->mExtraPayment)
        {
            //the user cancelled the paidability. fireAbility() on the second menu item.
            //paidability will always occupy the abilities[0]; in the vector.
            if(abilities.size() > 1)
            {
                abilities[1]->target = abilities[0]->target;
                abilities[1]->fireAbility();
            }
        }
        return false;
    }
    return false;
}

void MenuAbility::Update(float dt)
{
    MTGAbility::Update(dt);
    ActionLayer * object = game->mLayers->actionLayer();
    if(toPay && game->mExtraPayment && !processed)
    {
        if(game->mExtraPayment->isPaymentSet() && game->mExtraPayment->canPay() )
        {
            if (game->mExtraPayment->costs.size())
            {
                if (game->mExtraPayment->costs[0]->costToPay)
                {
                    ManaCost * diff = game->mExtraPayment->costs[0]->costToPay;
                    ManaCost * c = source->controller()->getManaPool()->Diff(diff);
                    source->X = c->getCost(Constants::NB_Colors);
                    delete c;
                }
            }

            game->mExtraPayment->doPay();
            game->mLayers->actionLayer()->reactToClick(game->mExtraPayment->action, game->mExtraPayment->source);
            game->mExtraPayment = NULL;
            processAbility();
            return;
        }

    }
    if (!triggered && !object->menuObject && !object->getCurrentTargetChooser())
    {

        triggered = 1;
        object->currentActionCard = (MTGCardInstance*)this->target;
        if (TargetAbility * ta = dynamic_cast<TargetAbility *>(ability))
        {
            if (!ta->getActionTc()->validTargetsExist())
                return;
        }
    }
    if(object->currentActionCard && this->target != object->currentActionCard)
    {
        triggered = 0;
    }
    if(triggered && !game->mExtraPayment && !processed)
    {
        game->mLayers->actionLayer()->setCustomMenuObject(source, must,abilities,newNameString.size()?newNameString.c_str():"");
        previousInterrupter = game->isInterrupting;
        game->mLayers->stackLayer()->setIsInterrupting(source->controller(), false);
    }
}

int MenuAbility::resolve()
{
    this->triggered = 1;
    MTGAbility * a = this;
    return a->addToGame();
}

const string MenuAbility::getMenuText()
{
    if((abilities.size() > 1 && must)||(abilities.size() > 2 && !must))
        return "choose one";
    return "Action";
}

int MenuAbility::testDestroy()
{
    if (game->mExtraPayment)
        return 0;
    if (!removeMenu)
        return 0;
    if (game->mLayers->actionLayer()->menuObject)
        return 0;
    if (game->mLayers->actionLayer()->getIndexOf(mClone) != -1)
        return 0;

    return 1;
}

int MenuAbility::isReactingToTargetClick(Targetable * card){return 0/*MayAbility::isReactingToTargetClick(card)*/;}
int MenuAbility::reactToTargetClick(Targetable * object){return 1;}

int MenuAbility::processAbility()
{
    if(!mClone)
        return 0;
    if(processed)
        return 0;
    if(abilities[0])
    mClone->target = abilities[0]->target;
    if(MayAbility * toCheck = dynamic_cast<MayAbility*>(mClone))
    {
        toCheck->must = true;
        mClone->addToGame();
    }
    else
    {
        mClone->oneShot = true;
        mClone->forceDestroy = 1;
        mClone->canBeInterrupted = false;
        mClone->resolve();
        SAFE_DELETE(mClone);
        if (source->controller() == game->isInterrupting)
            game->mLayers->stackLayer()->cancelInterruptOffer(ActionStack::DONT_INTERRUPT, false);
    }

    processed = true;
    this->forceDestroy = 1;
    removeMenu = true;
    return 1;
}

int MenuAbility::reactToChoiceClick(Targetable * object,int choice,int control)
{
    ActionElement * currentAction = (ActionElement *) game->mLayers->actionLayer()->mObjects[control];
    if(currentAction != (ActionElement*)this)
        return 0;
    if(!abilities.size()||!triggered)
        return 0;
    for(int i = 0;i < int(abilities.size());i++)
    {

        if(choice == i)
            mClone = abilities[choice]->clone();
        else if(!optionalCosts.size())
            SAFE_DELETE(abilities[i]);
        if (mClone && !toPay && optionalCosts.size() && i < int(optionalCosts.size()) && optionalCosts[i])//paidability only supports the first ability as paid for now.
        {
            toPay = NEW ManaCost();
            if (optionalCosts[i]->extraCosts)
                toPay->extraCosts = optionalCosts[i]->extraCosts->clone();
            toPay->addExtraCost(NEW ExtraManaCost(NEW ManaCost(optionalCosts[i])));
            toPay->setExtraCostsAction(this, source);
            game->mExtraPayment = toPay->extraCosts;
            return 0;
        }
    }
    if(!mClone)
    {
        if (source->controller() == game->isInterrupting)
            game->mLayers->stackLayer()->cancelInterruptOffer(ActionStack::DONT_INTERRUPT, false);
        return 0;
    }
    mClone->target = abilities[choice]->target;
    processAbility();
    return reactToTargetClick(object);
}

MenuAbility * MenuAbility::clone() const
{
    MenuAbility * a = NEW MenuAbility(*this);
    a->canBeInterrupted = false;
    if(abilities.size())
    {
        for(int i = 0;i < int(abilities.size());i++)
        {
            a->abilities.push_back(abilities[i]->clone());
            a->optionalCosts.push_back(NEW ManaCost(optionalCosts[i]));
            a->abilities[i]->target = abilities[i]->target;
        }
    }
    else
    a->ability = ability->clone();
    return a;
}

MenuAbility::~MenuAbility()
{
    if(abilities.size())
    {
        for(int i = 0;i < int(abilities.size());i++)
        {
            if(abilities[i])
            {
                AASetColorChosen * chooseA = dynamic_cast<AASetColorChosen *>(abilities[i]);
                if(chooseA && chooseA->abilityAltered)
                    SAFE_DELETE(chooseA->abilityAltered);
                SAFE_DELETE(abilities[i]);
            }
        }
    }
    else
        SAFE_DELETE(ability);
    SAFE_DELETE(toPay);
    SAFE_DELETE(mClone);
    if(optionalCosts.size())
        for(int i = 0;i < int(optionalCosts.size());i++)
        {
            if(optionalCosts[i])
            {
                SAFE_DELETE(optionalCosts[i]);
            }

        }
}
///
//MultiAbility : triggers several actions for a cost
MultiAbility::MultiAbility(GameObserver* observer, int _id, MTGCardInstance * card, Targetable * _target, ManaCost * _cost) :
    ActivatedAbility(observer, _id, card, _cost, 0)
{
    if (_target)
        target = _target;
}

int MultiAbility::Add(MTGAbility * ability)
{
    abilities.push_back(ability);
    return 1;
}

int MultiAbility::resolve()
{
    Targetable * Phaseactiontarget = NULL;
    for (size_t i = 0; i < abilities.size(); ++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;
            Phaseactiontarget = target;
        }
        abilities[i]->resolve();
        abilities[i]->target = backup;
        if(Phaseactiontarget && dynamic_cast<APhaseActionGeneric *> (abilities[i]))
            abilities[i]->target = Phaseactiontarget;
    }
    return 1;
}

int MultiAbility::addToGame()
{
    for (size_t i = 0; i < abilities.size(); ++i)
    {
        if (abilities[i] == NULL)
            continue;

        MTGAbility * a = abilities[i]->clone();
        a->target = target;
        a->addToGame();
        clones.push_back(a);
    }
    MTGAbility::addToGame();
    return 1;
}

int MultiAbility::destroy()
{
    for (size_t i = 0; i < clones.size(); ++i)
    {
        //I'd like to call game->removeObserver here instead of using forceDestroy, but I get a weird crash after that, need to investigate a bit
        clones[i]->forceDestroy = 1;
    }
    clones.clear();
    return ActivatedAbility::destroy();
}

const string MultiAbility::getMenuText()
{
    if (abilities.size() && abilities[0])
        return abilities[0]->getMenuText();
    return "";
}

MultiAbility * MultiAbility::clone() const
{
    MultiAbility * a = NEW MultiAbility(*this);
    a->abilities.clear();
    for (size_t i = 0; i < abilities.size(); ++i)
    {
        if(abilities[i])
        a->abilities.push_back(abilities[i]->clone());
    }
    return a;
}

MultiAbility::~MultiAbility()
{
    for (size_t i = 0; i < abilities.size(); ++i)
    {
        SAFE_DELETE(abilities[i]);
    }

    abilities.clear();
}
//Generic Target Ability
GenericTargetAbility::GenericTargetAbility(GameObserver* observer, string newName, string castRestriction, int _id, MTGCardInstance * _source, TargetChooser * _tc, MTGAbility * a,
        ManaCost * _cost, string limit,MTGAbility * sideEffects,string usesBeforeSideEffects, int restrictions, MTGGameZone * dest,string _tcString) :
    TargetAbility(observer, _id, _source, _tc, _cost, restrictions, castRestriction), limit(limit), activeZone(dest),newName(newName),sideEffects(sideEffects),usesBeforeSideEffects(usesBeforeSideEffects),tcString(_tcString)
{
    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 string GenericTargetAbility::getMenuText()
{
    if (!ability)
        return "Error";
    if (newName.size())
        return newName.c_str();

    //Special case for move
    MTGAbility * core = AbilityFactory::getCoreAbility(ability);
    if (AAMover * move = dynamic_cast<AAMover *>(core))
        return (move->getMenuText(tc));
    return ability->getMenuText();

}

int GenericTargetAbility::resolve()
{
    counters++;
    tc->done = false;
    if(sideEffects && usesBeforeSideEffects.size())
    {
        WParsedInt * use = NEW WParsedInt(usesBeforeSideEffects.c_str(),NULL,source);
        uses = use->getValue();
        delete use;
        if(counters == uses)
        {
            sa = sideEffects->clone();
            sa->target = this->target;
            sa->source = this->source;
            if(sa->oneShot)
            {
                sa->fireAbility();
            }
            else
            {
                GenericInstantAbility * wrapper = NEW GenericInstantAbility(game, 1, source, (Damageable *) (this->target), sa);
                wrapper->addToGame();
            }
        }
    }
    return TargetAbility::resolve();
}

int GenericTargetAbility::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
{
    limitPerTurn = 0;
    if(limit.size())
    {
        WParsedInt value(limit.c_str(),NULL,source);
        limitPerTurn = value.getValue();
    }
    if (limitPerTurn && counters >= limitPerTurn)
        return 0;
    if(tcString.size() && !tc->targetListSet())
    {
        TargetChooser * current = this->getActionTc();
        TargetChooserFactory tcf(game);
        TargetChooser *refreshed = tcf.createTargetChooser(tcString, source, this);
        refreshed->setTargetsTo(current->getTargetsFrom());
        this->setActionTC(refreshed);
        SAFE_DELETE(current);
    }
    return TargetAbility::isReactingToClick(card, mana);
}

void GenericTargetAbility::Update(float dt)
{
    if (newPhase != currentPhase && newPhase == 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();
    return a;
}

GenericTargetAbility::~GenericTargetAbility()
{
    SAFE_DELETE(ability);
    SAFE_DELETE(sideEffects);
}

//Alter Cost
AAlterCost::AAlterCost(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target, int amount, int type) :
MTGAbility(observer, id, source, target), amount(amount), type(type)
{
    manaReducer = source;
}

int AAlterCost::addToGame()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if(!_target || _target->hasType("land"))
    {
        this->forceDestroy = 1;
        return MTGAbility::addToGame();
    }
    if (amount > 0)
    {
        if(!_target->getIncreasedManaCost()->getConvertedCost())
        {
            ManaCost * increased = NEW ManaCost();
            _target->getIncreasedManaCost()->copy(increased);
            delete increased;

        }
        _target->getIncreasedManaCost()->add(type,amount);
    }
    else
    {
        if(!_target->getReducedManaCost()->getConvertedCost())
        {
            ManaCost * reduced = NEW ManaCost();
            _target->getReducedManaCost()->copy(reduced);
            delete reduced;
        }
        _target->getReducedManaCost()->add(type,abs(amount));
    }
    return MTGAbility::addToGame();
}

int AAlterCost::destroy()
{
    MTGCardInstance * _target = (MTGCardInstance *)target;
    if(!this->manaReducer->isInPlay(game))
    {
        if (amount > 0)
        {
            _target->getIncreasedManaCost()->remove(type,amount);
            refreshCost(_target);//special case for 0 cost.
        }
        else
        {
            _target->getReducedManaCost()->remove(type,abs(amount));
            refreshCost(_target);//special case for 0 cost.
        }
        return MTGAbility::testDestroy();
    }
    return 0;
}

int AAlterCost::testDestroy()
{
    if(!this->manaReducer->isInPlay(game))
    {
        return MTGAbility::testDestroy();
    }
    return 0;
}
void AAlterCost::refreshCost(MTGCardInstance * card)
{
    ManaCost * original = NEW ManaCost();
    original->copy(card->model->data->getManaCost());
    if(card->getIncreasedManaCost()->getConvertedCost())
        original->add(card->getIncreasedManaCost());
    if(card->getReducedManaCost()->getConvertedCost())
        original->remove(card->getReducedManaCost());
    card->getManaCost()->copy(original);
    delete original;
        return;
    }
void AAlterCost::increaseTheCost(MTGCardInstance * card)
{
    if(card->getIncreasedManaCost()->getConvertedCost())
    {
        for(int k = Constants::MTG_COLOR_ARTIFACT; k < Constants::NB_Colors;k++)
        {
            card->getManaCost()->add(k,card->getIncreasedManaCost()->getCost(k));
        }
    }
    return;
}

void AAlterCost::decreaseTheCost(MTGCardInstance * card)
{
    if(card->getReducedManaCost()->getConvertedCost())
    {
        for(int k = Constants::MTG_COLOR_ARTIFACT; k < Constants::NB_Colors;k++)
        {
            card->getManaCost()->remove(k,card->getReducedManaCost()->getCost(k));
        }
    }
    return;
}

AAlterCost * AAlterCost::clone() const
{
    return NEW AAlterCost(*this);
}

AAlterCost::~AAlterCost()
{
}

// ATransformer
ATransformer::ATransformer(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target, string stypes, string sabilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector<string> newAbilitiesList,bool newAbilityFound,bool aForever, bool aUntilNext,string _menu) :
    MTGAbility(observer, id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound),aForever(aForever),UYNT(aUntilNext),menutext(_menu)
{

    if (target != source) {
        target->storedSourceCard = source;
    }

    PopulateAbilityIndexVector(abilities, sabilities);
    PopulateColorIndexVector(colors, sabilities);
    if(sabilities.find("chosencolor") != string::npos)
    {
        colors.push_back(source->chooseacolor);
    }
    myCurrentTurn = 1000;
    //this subkeyword adds a color without removing the existing colors.
    addNewColors = (sabilities.find("newcolors") != string::npos);
    remove = (stypes.find("removealltypes") != string::npos);
    removeCreatureSubtypes = (stypes.find("removecreaturesubtypes") != string::npos);
    removeTypes = (stypes.find("removetypes") != string::npos);

    if (stypes.find("allsubtypes") != string::npos || stypes.find("removecreaturesubtypes") != string::npos)
    {  
        const vector<string> values = MTGAllCards::getValuesById();
        for (size_t i = 0; i <values.size(); ++i)
        {
            if (!MTGAllCards::isSubtypeOfType(i,Subtypes::TYPE_CREATURE))
                continue;

            types.push_back(i);
        }
    }
    else
    {
        if(stypes.find("chosentype") != string::npos)
        {
            stypes = source->chooseasubtype;
        }
        PopulateSubtypesIndexVector(types, stypes);
    }

    menu = stypes;
}

int ATransformer::addToGame()
{
    if(UYNT)
        myCurrentTurn = game->turn;
    MTGCardInstance * _target = NULL;
        Interruptible * action = (Interruptible *) target;
    if (action && action->type == ACTION_SPELL && action->state == NOT_RESOLVED)
    {
        Spell * spell = (Spell *) action;
        _target = spell->source;
        aForever = true;
        //when targeting the stack, set the effect to forever, incase the person does not use it
        //otherwise we will end up with a null pointer on the destroy.
    }
    else
    {
        _target = (MTGCardInstance *) target;
    }

    if (!_target)
    {
        DebugTrace("ALL_ABILITIES: Target not set in ATransformer::addToGame\n");
        return 0;
    }
        
    while (_target->next)
        _target = _target->next;

    for (int j = 0; j < Constants::NB_Colors; j++)
    {
        if (_target->hasColor(j))
            oldcolors.push_back(j);
    }
    for (size_t j = 0; j < _target->types.size(); ++j)
        oldtypes.push_back( _target->types[j]);

    list<int>::iterator it;
    for (it = colors.begin(); it != colors.end(); it++)
    {
        if(!addNewColors)
            _target->setColor(0, 1);
    }

    if (removeTypes)
    {
        //remove the main types from a card, ie: hidden enchantment cycle.
        for (int i = 0; i < Subtypes::LAST_TYPE; ++ i)
            _target->removeType(i,1);
    }
    else if (remove)
    {
        for (it = oldtypes.begin(); it != oldtypes.end(); it++)
        {
            _target->removeType(*it);
        }
    }
    else
    {
for (it = types.begin(); it != types.end(); it++)
        {

            if(removeCreatureSubtypes)
            {
                _target->removeType(*it);
            }
            else if(_target->hasSubtype(*it))
            {
                //we generally don't want to give a creature type creature again
                //all it does is create a sloppy mess of the subtype line on alternative quads
                //also creates instances where a card gained a type from an ability like this one
                //then loses the type through another ability, when this effect is destroyed the creature regains
                //the type, which is wrong.
                dontremove.push_back(*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.set(*it);
        _target->modifiedbAbi += 1;
    }

    if(newAbilityFound)
    {
        for (unsigned int k = 0 ; k < newAbilitiesList.size();k++)
        {
            AbilityFactory af(game);
            MTGAbility * aNew = af.parseMagicLine(newAbilitiesList[k], 0, NULL, _target);
            if(!aNew)
                continue;
            GenericTargetAbility * gta = dynamic_cast<GenericTargetAbility*> (aNew);
            if (gta)
            {
                ((GenericTargetAbility *)aNew)->source = _target;
                ((GenericTargetAbility *)aNew)->ability->source = _target;
            }
            GenericActivatedAbility * gaa = dynamic_cast<GenericActivatedAbility*> (aNew);
            if (gaa)
            {
                ((GenericActivatedAbility *)aNew)->source = _target;
                ((GenericActivatedAbility *)aNew)->ability->source = _target;
            }
            MultiAbility * abi = dynamic_cast<MultiAbility*>(aNew);
            if (abi)
            {
                ((MultiAbility *)aNew)->source = _target;
                ((MultiAbility *)aNew)->abilities[0]->source = _target;
            }

            aNew->target = _target;
            aNew->source = (MTGCardInstance *) _target;
            if(aNew->oneShot)
            {
                aNew->resolve();
                delete aNew;
            }
            else
            {
                aNew->addToGame();
                newAbilities[_target].push_back(aNew);
            }
        }
    }
    if(newpowerfound || newtoughnessfound)
        _target->isSettingBase += 1;
    if(newpowerfound )
    {
        WParsedInt * val = NEW WParsedInt(newpower,NULL, source);
        if(_target->isSwitchedPT)
        {
            _target->switchPT(false);
            _target->addbaseP(val->getValue());
            _target->switchPT(true);
        }
        else
            _target->addbaseP(val->getValue());
        delete val;
    }
    if(newtoughnessfound )
    {//we should consider the damage if there is, if you have a 5/5 creature with 1 damage,
     //and you turn it into 1/1, the 1 damage is still there and the creature must die...
     //the toughness is intact but what we see in the game is the life...
        WParsedInt * val = NEW WParsedInt(newtoughness,NULL, source);
        if(_target->isSwitchedPT)
        {
            _target->switchPT(false);
            _target->addbaseT(val->getValue());
            _target->switchPT(true);
        }
        else
            _target->addbaseT(val->getValue());
        delete val;
    }

    return MTGAbility::addToGame();
}
    
    int ATransformer::reapplyCountersBonus(MTGCardInstance * rtarget,bool , bool toughnessapplied)
    {
        if(!rtarget->counters || !rtarget->counters->counters.size())
            return 0;
        Counter * c = rtarget->counters->counters[0];
        int rNewPower = 0;
        int rNewToughness = 0;
        for (int t = 0; t < rtarget->counters->mCount; t++)
        {
            if (c)
            {
                for(int i = 0;i < c->nb;i++)
                {
                    rNewPower += c->power;
                    rNewToughness += c->toughness;   
                }
            }
            c = rtarget->counters->getNext(c);
        }
        if(toughnessapplied)
            return rNewToughness;
        return rNewPower;
    }

    int ATransformer::testDestroy()
    {
        if(UYNT)
        {
            if(myCurrentTurn != 1000 && game->turn > myCurrentTurn && source->controller()->getId() == game->currentPlayer->getId())
            {
                return 1;
            }
        }
        return MTGAbility::testDestroy();
    }

int ATransformer::destroy()
{
    if(aForever)
        return 0;
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        while (_target->next)
            _target = _target->next;
        list<int>::iterator it;
        
        if (!remove)
        {
            for (it = types.begin(); it != types.end(); it++)
            {
                    bool removing = true;
                    for(unsigned int k = 0;k < dontremove.size();k++)
                    {
                        if(dontremove[k] == *it)
                            removing = false;
                    }
                    if(removing)
                        _target->removeType(*it);
            }
            //iterators annoy me :/
        }

        for (it = colors.begin(); it != colors.end(); it++)
        {
            _target->removeColor(*it);
        }

        for (it = abilities.begin(); it != abilities.end(); it++)
        {
            _target->basicAbilities.reset(*it);
            _target->modifiedbAbi -= 1;
        }

        for (it = oldcolors.begin(); it != oldcolors.end(); it++)
        {
            _target->setColor(*it);
        }
        
        if(newpowerfound || newtoughnessfound)
            _target->isSettingBase -= 1;

        if(newpowerfound )
        {
            _target->revertbaseP();
        }
        if(newtoughnessfound )
        {
            _target->revertbaseT();
        }
        if(newAbilityFound)
        {
            for (unsigned int i = 0;i < newAbilities[_target].size(); i++)
            {
                if(newAbilities[_target].at(i))
                {
                    newAbilities[_target].at(i)->forceDestroy = 1;
                    newAbilities[_target].at(i)->removeFromGame();
                }
            }
            if (newAbilities.find(_target) != newAbilities.end())
            {
                newAbilities.erase(_target);
            }
        }
        if (remove || removeCreatureSubtypes)
        {
            for (it = oldtypes.begin(); it != oldtypes.end(); it++)
            {
                if(!_target->hasSubtype(*it))
                    _target->addType(*it);
            }
        }
        ////in the case that we removed or added types to a card, so that it retains its original name when the effect is removed.
        //if(_target->model->data->name.size())//tokens don't have a model name.
        //    _target->setName(_target->model->data->name.c_str());

        //edit: this ability shouldn't have to reset the name on a card becuase removing a subtype changes the name of a land.
        //that should be handled in addType...not here.
        //im sure commenting this out will reintroduce a bug somewhere but it needs to be handled correctly. furthermore, why does adding and removing a type touch the name of a card?
    }
    return 1;
}

const string ATransformer::getMenuText()
{
    if(menutext.size())
        return menutext.c_str();
    string s = menu;
    sprintf(menuText, "Becomes %s", s.c_str());
    return menuText;
}

ATransformer * ATransformer::clone() const
{
    return NEW ATransformer(*this);
}

ATransformer::~ATransformer()
{
}

//ATransformerInstant
ATransformerInstant::ATransformerInstant(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target, string types, string abilities,string newpower,bool newpowerfound,string newtoughness,bool newtoughnessfound,vector<string>newAbilitiesList,bool newAbilityFound,bool aForever,bool aUntilNext,string _menu) :
    InstantAbility(observer, id, source, target),newpower(newpower),newpowerfound(newpowerfound),newtoughness(newtoughness),newtoughnessfound(newtoughnessfound),newAbilitiesList(newAbilitiesList),newAbilityFound(newAbilityFound),aForever(aForever),UYNT(aUntilNext),menu(_menu)
{
    ability = NEW ATransformer(game, id, source, target, types, abilities,newpower,newpowerfound,newtoughness,newtoughnessfound,newAbilitiesList,newAbilityFound,aForever,aUntilNext,_menu);
    aType = MTGAbility::STANDARD_BECOMES;
}

int ATransformerInstant::resolve()
{
    ATransformer * a = ability->clone();
    GenericInstantAbility * wrapper = NEW GenericInstantAbility(game, 1, source, (Damageable *) (this->target), a);
    wrapper->addToGame();
    return 1;
}
const string ATransformerInstant::getMenuText()
{
    if(menu.size())
        return menu.c_str();
    return ability->getMenuText();
}

ATransformerInstant * ATransformerInstant::clone() const
{
    ATransformerInstant * a = NEW ATransformerInstant(*this);
    a->ability = this->ability->clone();
    return a;
}

ATransformerInstant::~ATransformerInstant()
{
    SAFE_DELETE(ability);
}

//P/t ueot
PTInstant::PTInstant(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target, WParsedPT * wppt,string s,bool nonstatic) :
InstantAbility(observer, id, source, target), wppt(wppt),s(s),nonstatic(nonstatic)
{
    ability = NEW APowerToughnessModifier(game, id, source, target, wppt,s,nonstatic);
    aType = MTGAbility::STANDARD_PUMP;
}

int PTInstant::resolve()
{
    APowerToughnessModifier * a = ability->clone();
    GenericInstantAbility * wrapper = NEW GenericInstantAbility(game, 1, source, (Damageable *) (this->target), a);
    wrapper->addToGame();
    ((Damageable *) (this->target))->afterDamage();//additional check the negative pt after resolving..
    return 1;
}
const string PTInstant::getMenuText()
{
    return ability->getMenuText();
}

PTInstant * PTInstant::clone() const
{
    PTInstant * a = NEW PTInstant(*this);
    a->ability = this->ability->clone();
    return a;
}

PTInstant::~PTInstant()
{
    SAFE_DELETE(ability);
}
// ASwapPTUEOT
ASwapPTUEOT::ASwapPTUEOT(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * target) :
    InstantAbility(observer, id, source, target)
{
    ability = NEW ASwapPT(observer, id, source, target);
}

int ASwapPTUEOT::resolve()
{
    ASwapPT * a = ability->clone();
    GenericInstantAbility * wrapper = NEW GenericInstantAbility(game, 1, source, (Damageable *) (this->target), a);
    wrapper->addToGame();
    return 1;
}

const string ASwapPTUEOT::getMenuText()
{
    return ability->getMenuText();
}

ASwapPTUEOT * ASwapPTUEOT::clone() const
{
    ASwapPTUEOT * a = NEW ASwapPTUEOT(*this);
    a->ability = this->ability->clone();
    return a;
}

ASwapPTUEOT::~ASwapPTUEOT()
{
    SAFE_DELETE(ability);
}

//exhange life with targetchooser
AAExchangeLife::AAExchangeLife(GameObserver* observer, int _id, MTGCardInstance * _source, Targetable * _target, ManaCost * _cost,
    int who) :
ActivatedAbilityTP(observer, _id, _source, _target, _cost, who)
{
}

int AAExchangeLife::resolve()
{
    Damageable * _target = (Damageable *) getTarget();
    if (_target)
    {
        if(_target->type_as_damageable == Damageable::DAMAGEABLE_PLAYER && ((Player*)_target)->inPlay()->hasAbility(Constants::CANTCHANGELIFE))
            return 0;
        Player *player = source->controller();
        int oldlife = player->getLife();
        int targetOldLife = _target->getLife();
        int modifier = oldlife > targetOldLife? oldlife - targetOldLife:targetOldLife - oldlife;
        if (_target->type_as_damageable == Damageable::DAMAGEABLE_MTGCARDINSTANCE)
        {
            int increaser = 0;
            MTGCardInstance * card = ((MTGCardInstance*)_target);
            int toughMod = 0;
            targetOldLife <= card->origtoughness?toughMod = card->origtoughness - targetOldLife: toughMod = targetOldLife - card->origtoughness;
            if(oldlife > targetOldLife)
            {
                increaser = oldlife - targetOldLife;
                player->gainOrLoseLife(modifier * -1);
                card->addToToughness(increaser+toughMod);
            }
            else
            {
                _target->life = oldlife;
                card->toughness = oldlife;
                player->gainOrLoseLife(modifier);
            }

            return 1;
        }
        Player * opponent = (Player*)_target;
        if(oldlife > targetOldLife)
        {
            player->gainOrLoseLife(modifier * -1);
            opponent->gainOrLoseLife(modifier);
        }
        else
        {
            player->gainOrLoseLife(modifier);
            opponent->gainOrLoseLife(modifier * -1);
        }
        return 1;
    }
    return 0;
}

const string AAExchangeLife::getMenuText()
{
    return "Exchange life";
}

AAExchangeLife * AAExchangeLife::clone() const
{
    return NEW AAExchangeLife(*this);
}

//ALoseAbilities
ALoseAbilities::ALoseAbilities(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target) :
    MTGAbility(observer, id, source)
{
    target = _target;
}

int ALoseAbilities::addToGame()
{
    if (storedAbilities.size())
    {
        DebugTrace("FATAL:storedAbilities shouldn't be already set inALoseAbilitie\n");
        return 0;
    }
    MTGCardInstance * _target = (MTGCardInstance *)target;

    ActionLayer * al = game->mLayers->actionLayer();


    //Build a list of Lords in game, this is a hack mostly for lands, see below
    vector <ALord *> lordsInGame;
    for (int i = (int)(al->mObjects.size()) - 1; i > 0; i--)      //0 is not a mtgability...hackish
    {
        if (al->mObjects[i])
        {
            MTGAbility * currentAction = (MTGAbility *) al->mObjects[i];
            ALord * l = dynamic_cast<ALord*> (currentAction);
            if(l)
                lordsInGame.push_back(l);
        }
    }

    for (int i = (int)(al->mObjects.size()) - 1; i > 0; i--)      //0 is not a mtgability...hackish
    {
        if (al->mObjects[i])
        {
            MTGAbility * currentAction = (MTGAbility *) al->mObjects[i];
            ALoseAbilities * la = dynamic_cast<ALoseAbilities*> (currentAction);
            if(la)
                continue;
            if (currentAction->source == _target)
            {
                bool canRemove = true;

                //Hack: we don't remove abilities on the card if they are provided by an external lord ability.
                //This is partly to solve the following issues:
                // http://code.google.com/p/wagic/issues/detail?id=647
                // http://code.google.com/p/wagic/issues/detail?id=700
                // But also because "most" abilities granted by lords will actually go away by themselves,
                // based on the fact that we usually remove abilities AND change the type of the card
                //Also in a general way we don't want to remove the card's abilities if it is provided by a Lord,
                //although there is also a problem with us not handling the P/T layer correctly
                for (size_t i = 0; i < lordsInGame.size(); ++i)
                {
                    if (lordsInGame[i]->isParentOf(_target, currentAction))
                    {
                        canRemove = false;
                        break;
                    }
                }
                
                if (canRemove)
                {
                    storedAbilities.push_back(currentAction);
                    al->removeFromGame(currentAction);
                }
            }
        }
    }

    return MTGAbility::addToGame();
}

int ALoseAbilities::destroy()
{
    for (size_t i = 0; i < storedAbilities.size(); ++i)
    {
        MTGAbility * a = storedAbilities[i];
        //OneShot abilities are not supposed to stay in the game for long.
        // If we copied one, something wrong probably happened
        if (a->oneShot)
        {
            DebugTrace("ALLABILITIES: Ability should not be one shot");
            continue;
        }

        //Avoid inifinite loop of removing/putting back abilities
        if (dynamic_cast<ALoseAbilities*> (a))
        {
            DebugTrace("ALLABILITIES: loseability won't be put in the loseability list");
            continue;
        }

         a->addToGame();
    }
    storedAbilities.clear();
    return 1;
}

ALoseAbilities * ALoseAbilities::clone() const
{
    return NEW ALoseAbilities(*this);
}

//ALoseSubtypes
ALoseSubtypes::ALoseSubtypes(GameObserver* observer, int id, MTGCardInstance * source, MTGCardInstance * _target, int parentType) :
    MTGAbility(observer, id, source), parentType(parentType)
{
    target = _target;
}

int ALoseSubtypes::addToGame()
{
    if (storedSubtypes.size())
    {
        DebugTrace("FATAL:storedSubtypes shouldn't be already set inALoseSubtypes\n");
        return 0;
    }
    MTGCardInstance * _target = (MTGCardInstance *)target;

    for (int i = ((int)_target->types.size())-1; i >= 0; --i)
    {
        int subtype = _target->types[i];
        if (MTGAllCards::isSubtypeOfType(subtype, parentType))
        {
            storedSubtypes.push_back(subtype);
            _target->removeType(subtype);
        }
    }

    return MTGAbility::addToGame();
}

int ALoseSubtypes::destroy()
{
    MTGCardInstance * _target = (MTGCardInstance *)target;
    for (size_t i = 0; i < storedSubtypes.size(); ++i)
        _target->addType(storedSubtypes[i]);
    storedSubtypes.clear();
    return 1;
}

ALoseSubtypes * ALoseSubtypes::clone() const
{
    return NEW ALoseSubtypes(*this);
}

//APreventDamageTypes
APreventDamageTypes::APreventDamageTypes(GameObserver* observer, int id, MTGCardInstance * source, string to, string from, int type) :
    MTGAbility(observer, 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(game);
    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::DAMAGE_COMBAT);
    }
    else if (type == 1)
    {
        re = NEW REDamagePrevention(this, fromTc, toTc, -1, false, Damage::DAMAGE_ALL_TYPES);
    }
    else if (type == 2)
    {
        re = NEW REDamagePrevention(this, fromTc, toTc, -1, false, Damage::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->re = NULL;
    return a;
}

APreventDamageTypes::~APreventDamageTypes()
{
    SAFE_DELETE(re);
}

//APreventDamageTypesUEOT
APreventDamageTypesUEOT::APreventDamageTypesUEOT(GameObserver* observer, int id, MTGCardInstance * source, string to, string from, int type) :
    InstantAbility(observer, id, source)
{
    ability = NEW APreventDamageTypes(observer, id, source, to, from, type);
}

int APreventDamageTypesUEOT::resolve()
{
    APreventDamageTypes * a = ability->clone();
    GenericInstantAbility * wrapper = NEW GenericInstantAbility(game, 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 string APreventDamageTypesUEOT::getMenuText()
{
    return ability->getMenuText();
}

APreventDamageTypesUEOT * APreventDamageTypesUEOT::clone() const
{
    APreventDamageTypesUEOT * a = NEW APreventDamageTypesUEOT(*this);
    a->ability = this->ability->clone();
    return a;
}

APreventDamageTypesUEOT::~APreventDamageTypesUEOT()
{
    SAFE_DELETE(ability);
}

//AVanishing creature also fading
// Comprehensive 702.31a:
// Fading is a keyword that represents two abilities.
// “Fading N” means “This permanent comes into play with N fade counters on it” and
// “At the beginning of your upkeep, remove a fade counter from this permanent.
// If you can’t, sacrifice the permanent.”

// Comprehensive 702.62a:
// Vanishing is a keyword that represents three abilities.
// "Vanishing N" means "This permanent comes into play with N time counters on it,"
// "At the beginning of your upkeep, if this permanent has a time counter on it, remove a time counter from it," and
// "When the last time counter is removed from this permanent, sacrifice it."
AVanishing::AVanishing(GameObserver* observer, int _id, MTGCardInstance * card, ManaCost *, int, int amount, string counterName) :
MTGAbility(observer, _id, source, target),amount(amount),counterName(counterName)
{
    target = card;
    source = card;
    for (int i = 0; i < amount; i++)
        source->counters->addCounter(counterName.c_str(), 0, 0);
}

void AVanishing::Update(float dt)
{
    if (newPhase != currentPhase && source->controller() == game->currentPlayer)
    {
        if (newPhase == MTG_PHASE_UPKEEP)
        {
            bool hasCounters = (source->counters && source->counters->hasCounter(counterName.c_str(), 0, 0));
            if (hasCounters)
            {
                // sacrifice of card with time counter is handled in removeCounter
                source->counters->removeCounter(counterName.c_str(), 0, 0);
            } else
            {
                if (counterName == "fade")
                {
                    MTGCardInstance * beforeCard = source;
                    source->controller()->game->putInGraveyard(source);
                    WEvent * e = NEW WEventCardSacrifice(beforeCard,source);
                    game->receiveEvent(e);
                }
            }
        }
    }
    MTGAbility::Update(dt);
}

int AVanishing::resolve()
{
    return 1;
}

const string AVanishing::getMenuText()
{
    if (counterName.find("fade") != string::npos)
    {
        return "Fading";
    }
    return "Vanishing";
}

AVanishing * AVanishing::clone() const
{
    return NEW AVanishing(*this);
}

AVanishing::~AVanishing()
{
}

//Produce Mana
AProduceMana::AProduceMana(GameObserver* observer, int _id, MTGCardInstance * _source, string ManaDescription) :
MTGAbility(observer, _id, source),ManaDescription(ManaDescription)
{
    source = _source;
    mana[0] = "{g}"; mana[1] = "{u}"; mana[2] = "{r}"; mana[3] = "{b}"; mana[4] = "{w}";
}

int AProduceMana::receiveEvent(WEvent * event)
{
    if(WEventCardTappedForMana * isTappedForMana = dynamic_cast<WEventCardTappedForMana *> (event))
    {
        if ((isTappedForMana->card == source)||(isTappedForMana->card == source->target && ManaDescription == "selectmana"))
            produce();
    }
    return 1;
}

int AProduceMana::produce()
{
    if(ManaDescription == "selectmana")
    {//I tried menu ability and vector<MTGAbility*abi> to have a shorter code but it crashes wagic at end of turn...
     //The may ability on otherhand works but the ability is cumulative...
     //This must be wrapped on menuability so we can use it on successions...
        AManaProducer *ap0 = NEW AManaProducer(game, game->mLayers->actionLayer()->getMaxId(), source, source->controller(), ManaCost::parseManaCost(mana[0],NULL,source), NULL, 0,"",false);
        MayAbility *mw0 = NEW MayAbility(game, game->mLayers->actionLayer()->getMaxId(), ap0, source,true);
        MTGAbility *ga0 = NEW GenericAddToGame(game, game->mLayers->actionLayer()->getMaxId(), source,NULL,mw0);

        AManaProducer *ap1 = NEW AManaProducer(game, game->mLayers->actionLayer()->getMaxId(), source, source->controller(), ManaCost::parseManaCost(mana[1],NULL,source), NULL, 0,"",false);
        MayAbility *mw1 = NEW MayAbility(game, game->mLayers->actionLayer()->getMaxId(), ap1, source,true);
        MTGAbility *ga1 = NEW GenericAddToGame(game, game->mLayers->actionLayer()->getMaxId(), source,NULL,mw1);

        AManaProducer *ap2 = NEW AManaProducer(game, game->mLayers->actionLayer()->getMaxId(), source, source->controller(), ManaCost::parseManaCost(mana[2],NULL,source), NULL, 0,"",false);
        MayAbility *mw2 = NEW MayAbility(game, game->mLayers->actionLayer()->getMaxId(), ap2, source,true);
        MTGAbility *ga2 = NEW GenericAddToGame(game, game->mLayers->actionLayer()->getMaxId(), source,NULL,mw2);

        AManaProducer *ap3 = NEW AManaProducer(game, game->mLayers->actionLayer()->getMaxId(), source, source->controller(), ManaCost::parseManaCost(mana[3],NULL,source), NULL, 0,"",false);
        MayAbility *mw3 = NEW MayAbility(game, game->mLayers->actionLayer()->getMaxId(), ap3, source,true);
        MTGAbility *ga3 = NEW GenericAddToGame(game, game->mLayers->actionLayer()->getMaxId(), source,NULL,mw3);

        AManaProducer *ap4 = NEW AManaProducer(game, game->mLayers->actionLayer()->getMaxId(), source, source->controller(), ManaCost::parseManaCost(mana[4],NULL,source), NULL, 0,"",false);
        MayAbility *mw4 = NEW MayAbility(game, game->mLayers->actionLayer()->getMaxId(), ap4, source,true);
        MTGAbility *ga4 = NEW GenericAddToGame(game, game->mLayers->actionLayer()->getMaxId(), source,NULL,mw4);

        ga0->resolve();
        ga1->resolve();
        ga2->resolve();
        ga3->resolve();
        ga4->resolve();
    }
    else
    {
        AManaProducer *amp = NEW AManaProducer(game, game->mLayers->actionLayer()->getMaxId(), source, source->controller(), ManaCost::parseManaCost(ManaDescription,NULL,source), NULL, 0,"",false);
        amp->resolve();
        SAFE_DELETE(amp);//once you call resolve() on a ability, you can safely delete it.
    }
    return 1;
}

const string AProduceMana::getMenuText()
{
    return "Produce Mana";
}

AProduceMana * AProduceMana::clone() const
{
    return NEW AProduceMana(*this);
}

AProduceMana::~AProduceMana()
{
}

//AUpkeep
AUpkeep::AUpkeep(GameObserver* observer, int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int restrictions, int _phase,
        int _once,bool Cumulative) :
    ActivatedAbility(observer, _id, card, _cost, restrictions), NestedAbility(a), phase(_phase), once(_once),Cumulative(Cumulative)
{
    paidThisTurn = 0;
    aType = MTGAbility::UPCOST;
    if(Cumulative)
    {
        backupMana = NEW ManaCost();
        backupMana->copy(this->getCost());
        backupMana->addExtraCosts(this->getCost()->extraCosts);
    }
}

    int AUpkeep::receiveEvent(WEvent * event)
    {
        if (WEventPhaseChange* pe = dynamic_cast<WEventPhaseChange*>(event))
        {
            if (MTG_PHASE_DRAW == pe->to->id && MTG_PHASE_UPKEEP == pe->from->id)
            {
                if (source->controller() == game->currentPlayer && once < 2 && paidThisTurn < 1)
                {
                    ability->resolve();
                }
            }
        }
        return 1;
    }
    
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 == MTG_PHASE_BEFORE_BEGIN)
        {
            paidThisTurn = 0;
        }
        else if(newPhase == MTG_PHASE_UPKEEP && Cumulative )
        {
            source->counters->addCounter("age",0,0);
                Counter * targetCounter = NULL;
                currentage = 0;

                if (source->counters && source->counters->hasCounter("age", 0, 0))
                {
                    targetCounter = source->counters->hasCounter("age", 0, 0);
                    currentage = targetCounter->nb - 1;
                }
            if(currentage)
            {
                paidThisTurn = 0;
                this->getCost()->copy(backupMana);
                for(int age = 0;age < currentage;age++)
                {
                    this->getCost()->add(backupMana); 
                    this->getCost()->addExtraCosts(backupMana->extraCosts);
                }
            }
        }
        if (newPhase == phase + 1 && once)
            once = 2;
    }
    ActivatedAbility::Update(dt);
}

int AUpkeep::isReactingToClick(MTGCardInstance * card, ManaCost * mana)
{
    if (currentPhase != phase || paidThisTurn > 0 || once >= 2)
        return 0;
    return ActivatedAbility::isReactingToClick(card, mana);
}

int AUpkeep::resolve()
{
    paidThisTurn += 1;
    return 1;
}

const string 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->ability = ability->clone();
    return a;
}

AUpkeep::~AUpkeep()
{
    if(Cumulative)
    {
        SAFE_DELETE(backupMana);
    }
    SAFE_DELETE(ability);
}

//A Phase based Action
APhaseAction::APhaseAction(GameObserver* observer, int _id, MTGCardInstance * card, MTGCardInstance *, string sAbility, int, int _phase,bool forcedestroy,bool next,bool myturn,bool opponentturn,bool once, bool checkexile) :
MTGAbility(observer, _id, card),sAbility(sAbility), phase(_phase),forcedestroy(forcedestroy),next(next),myturn(myturn),opponentturn(opponentturn),once(once),checkexile(checkexile)
{
    abilityId = _id;
    abilityOwner = card->controller();
    psMenuText = "";
    AbilityFactory af(game);
    ability = af.parseMagicLine(sAbility, abilityId, NULL, NULL);
    if(ability)
        psMenuText = ability->getMenuText();
    else
        psMenuText = sAbility.c_str();
    delete (ability);

}

void APhaseAction::Update(float dt)
{
    if(checkexile)
    {
        if(((MTGCardInstance *)target)->next->getCurrentZone() != ((MTGCardInstance *)target)->owner->game->exile)
        {
            this->forceDestroy = 1;
            return;
        }
    }
    if (newPhase != currentPhase)
    {
        if((myturn && game->currentPlayer == source->controller())|| 
            (opponentturn && game->currentPlayer != source->controller())/*||*/
            /*(myturn && opponentturn)*/)
        {
            if(newPhase == phase && next )
            {
                MTGCardInstance * _target = NULL;
                bool isTargetable = false;
                
                if(target)
                {
                    _target = static_cast<MTGCardInstance *>(target);
                    isTargetable = (_target && !_target->currentZone && _target != this->source);
                }
                
                if(!sAbility.size() || (!target || isTargetable))
                {
                    this->forceDestroy = 1;
                    return;
                }
                else
                {
                    while(_target && _target->next)
                        _target = _target->next;
                }
                
                AbilityFactory af(game);
                MTGAbility * ability = af.parseMagicLine(sAbility, abilityId, NULL, _target);

                MTGAbility * a = ability->clone();
                a->target = _target;
                a->resolve();
                delete (a);
                delete (ability);
                if(this->oneShot || once)
                {
                    this->forceDestroy = 1;
                }
            }
            else if(newPhase == phase && next == false)
                next = true;
        }
    }
    MTGAbility::Update(dt);
}

int APhaseAction::resolve()
{

    return 0;
}

const string APhaseAction::getMenuText()
{
    if(psMenuText.size())
    return psMenuText.c_str();
    else
    return "Phase Based Action";
}

APhaseAction * APhaseAction::clone() const
{
    APhaseAction * a = NEW APhaseAction(*this);
    if(forcedestroy == false)
        a->forceDestroy = -1;// we want this ability to stay alive until it resolves.
    return a;
}

APhaseAction::~APhaseAction()
{

}

// the main ability
APhaseActionGeneric::APhaseActionGeneric(GameObserver* observer, int _id, MTGCardInstance * card, MTGCardInstance * target, string sAbility, int restrictions, int _phase,bool forcedestroy,bool next,bool myturn,bool opponentturn,bool once, bool checkexile) :
    InstantAbility(observer, _id, card, target)
{
    MTGCardInstance * _target = target;
    ability = NEW APhaseAction(game, _id, card,_target, sAbility, restrictions, _phase,forcedestroy,next,myturn,opponentturn,once,checkexile);
}

int APhaseActionGeneric::resolve()
{
        APhaseAction * a = ability->clone();
        a->target = target;
        a->addToGame();
        return 1;
}

const string APhaseActionGeneric::getMenuText()
{
    return ability->getMenuText();
}

APhaseActionGeneric * APhaseActionGeneric::clone() const
{
    APhaseActionGeneric * a = NEW APhaseActionGeneric(*this);
    a->ability = this->ability->clone();
    a->oneShot = 1;
    return a;
}

APhaseActionGeneric::~APhaseActionGeneric()
{
    SAFE_DELETE(ability);
}

//AAttackSetCost
AAttackSetCost::AAttackSetCost(GameObserver* observer, int _id, MTGCardInstance * _source, string number, bool pw) :
    MTGAbility(observer, _id, _source), number(number), pw(pw)
{
}

void AAttackSetCost::Update(float dt)
{
    if(game->getCurrentGamePhase() != MTG_PHASE_COMBATATTACKERS)
    {
        source->attackCost = source->attackCostBackup;
        if(pw)
            source->attackPlaneswalkerCost = source->attackPlaneswalkerCostBackup;
        MTGAbility::Update(dt);
    }
}

int AAttackSetCost::addToGame()
{
    WParsedInt attackcost(number, NULL, source);
    source->attackCost += attackcost.getValue();
    source->attackCostBackup += attackcost.getValue();
    if(pw)
    {
        source->attackPlaneswalkerCost += attackcost.getValue();
        source->attackPlaneswalkerCostBackup += attackcost.getValue();
    }

    return MTGAbility::addToGame();
}

int AAttackSetCost::destroy()
{
    
    WParsedInt attackcost(number, NULL, source);
    source->attackCost -= attackcost.getValue();
    source->attackCostBackup -= attackcost.getValue();
    if(pw)
    {
        source->attackPlaneswalkerCost -= attackcost.getValue();
        source->attackPlaneswalkerCostBackup -= attackcost.getValue();
    }

    return 1;
}

const string AAttackSetCost::getMenuText()
{
    return "Attack Cost";
}

AAttackSetCost * AAttackSetCost::clone() const
{
    return NEW AAttackSetCost(*this);
}

//ABlockSetCost
ABlockSetCost::ABlockSetCost(GameObserver* observer, int _id, MTGCardInstance * _source, string number) :
    MTGAbility(observer, _id, _source), number(number)
{
}

void ABlockSetCost::Update(float dt)
{
    if(game->getCurrentGamePhase() != MTG_PHASE_COMBATBLOCKERS)
    {
        source->blockCost = source->blockCostBackup;
        MTGAbility::Update(dt);
    }
}

int ABlockSetCost::addToGame()
{
    WParsedInt blockCost(number, NULL, source);
    source->blockCost += blockCost.getValue();
    source->blockCostBackup += blockCost.getValue();

    return MTGAbility::addToGame();
}

int ABlockSetCost::destroy()
{
    
    WParsedInt blockCost(number, NULL, source);
    source->blockCost -= blockCost.getValue();
    source->blockCostBackup -= blockCost.getValue();

    return 1;
}

const string ABlockSetCost::getMenuText()
{
    return "Block Cost";
}

ABlockSetCost * ABlockSetCost::clone() const
{
    return NEW ABlockSetCost(*this);
}

//AShackle
AShackle::AShackle(GameObserver* observer, int _id, MTGCardInstance * card, MTGCardInstance * _target) :
MTGAbility(observer, _id, card)
{
    target = _target;
    Shackled = NULL;
    previousController = NULL;
    resolved = false;
}

void AShackle::Update(float dt)
{
    if (resolved == false)
    {
        resolved = true;
        resolveShackle();
    }

    if (!source->isTapped() || !source->isInPlay(game))
    {
            if (Shackled == NULL || !Shackled->isInPlay(game))
                MTGAbility::Update(dt);
            MTGCardInstance * _target = Shackled;
            returntoOwner(_target);
    }
    MTGAbility::Update(dt);
}

void AShackle::resolveShackle()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        previousController = _target->controller();
        previousController->game->putInZone(_target, _target->currentZone,
            source->controller()->game->inPlay);
        Shackled = _target;
        source->shackled = Shackled;
        Shackled->shackled = source;
    }
}

void AShackle::returntoOwner(MTGCardInstance* _target) {
    MTGCardInstance * cardToReturn = _target;
    if(!cardToReturn)
    {
        if (source)
            source->shackled = NULL;
        this->forceDestroy = 1;
        return;
    }
    if(previousController && cardToReturn->isInPlay(game))
    {
        cardToReturn->shackled = NULL;
        cardToReturn->controller()->game->putInZone(_target, _target->currentZone,
            previousController->game->inPlay);
    }
    if (source)
        source->shackled = NULL;
    this->forceDestroy = 1;
    Shackled = NULL;
    return;
}

int AShackle::resolve()
{
    return 0;
}
const string AShackle::getMenuText()
{
    return "Gain Control";
}

AShackle * AShackle::clone() const
{
    AShackle * a = NEW AShackle(*this);
    a->forceDestroy = -1;
    return a;
};
AShackle::~AShackle()
{
}

AShackleWrapper::AShackleWrapper(GameObserver* observer, int _id, MTGCardInstance * card, MTGCardInstance * _target) :
    InstantAbility(observer, _id, source, _target)
{
    ability = NEW AShackle(observer, _id,card,_target);
}

int AShackleWrapper::resolve()
{
    AShackle * a = ability->clone();
    a->target = target;
    a->addToGame();
    return 1;
}

const string AShackleWrapper::getMenuText()
{
    return "Gain Control";
}

AShackleWrapper * AShackleWrapper::clone() const
{
    AShackleWrapper * a = NEW AShackleWrapper(*this);
    a->ability = this->ability->clone();
    a->oneShot = 1;
    return a;
}

AShackleWrapper::~AShackleWrapper()
{
    SAFE_DELETE(ability);
}

//grant
AGrant::AGrant(GameObserver* observer, int _id, MTGCardInstance * card, MTGCardInstance * _target, MTGAbility * _Grant) :
    MTGAbility(observer, _id, card)
{
    Granted = _Grant;
    target = _target;
    Blessed = NULL;
    resolved = false;
    toGrant = NULL;
}

void AGrant::Update(float dt)
{
    if (resolved == false)
    {
        resolved = true;
        resolveGrant();
    }

    if (!source->isTapped() || !source->isInPlay(game))
    {
        if (Blessed == NULL || !Blessed->isInPlay(game))
            MTGAbility::Update(dt);
        MTGCardInstance * _target = Blessed;
        removeGranted(_target);
    }
    else
        resolveGrant();
    MTGAbility::Update(dt);
}

void AGrant::resolveGrant()
{
    if (toGrant) return;
    MTGCardInstance * _target = (MTGCardInstance *)target;
    if (_target)
    {
        toGrant = Granted->clone();
        toGrant->target = _target;
        toGrant->addToGame();
        Blessed = _target;
    }
}

void AGrant::removeGranted(MTGCardInstance* _target)
{
    if (!toGrant) return;
    game->removeObserver(toGrant);
    game->removeObserver(this);
    Blessed = NULL;
    return;
}

int AGrant::resolve()
{
    return 0;
}
const string AGrant::getMenuText()
{
    return Granted->getMenuText();
}

AGrant * AGrant::clone() const
{
    AGrant * a = NEW AGrant(*this);
    a->forceDestroy = -1;
    a->Granted = Granted->clone();
    return a;
};
AGrant::~AGrant()
{
    SAFE_DELETE(Granted);
}

AGrantWrapper::AGrantWrapper(GameObserver* observer, int _id, MTGCardInstance * card, MTGCardInstance * _target, MTGAbility * _Grant) :
    InstantAbility(observer, _id, source, _target), Granted(_Grant)
{
    ability = NEW AGrant(observer, _id, card, _target,_Grant);
}

int AGrantWrapper::resolve()
{
    AGrant * a = ability->clone();
    a->target = target;
    a->addToGame();
    return 1;
}

const string AGrantWrapper::getMenuText()
{
    return "Grant";
}

AGrantWrapper * AGrantWrapper::clone() const
{
    AGrantWrapper * a = NEW AGrantWrapper(*this);
    a->ability = this->ability->clone();
    a->oneShot = 1;
    return a;
}

AGrantWrapper::~AGrantWrapper()
{
    SAFE_DELETE(ability);
}

//a blink
ABlink::ABlink(GameObserver* observer, int _id, MTGCardInstance * card, MTGCardInstance * _target, bool blinkueot, bool blinkForSource, bool blinkhand, MTGAbility * stored) :
MTGAbility(observer, _id, card),blinkueot(blinkueot),blinkForSource(blinkForSource),blinkhand(blinkhand),stored(stored)
{
    target = _target;
    Blinked = NULL;
    resolved = false;
}

void ABlink::Update(float dt)
{
    if (resolved == false)
    {
        resolved = true;
        resolveBlink();
    }

    if ((blinkueot && currentPhase == MTG_PHASE_ENDOFTURN) || (blinkForSource && !source->isInPlay(game)))
    {
        if(Blinked->blinked)
        {
            if (Blinked == NULL)
                MTGAbility::Update(dt);
            MTGCardInstance * _target = Blinked;
            returnCardIntoPlay(_target);
        }
    }
    MTGAbility::Update(dt);
}

void ABlink::resolveBlink()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        //going to comment this condiational out, i can't remember if i added this to fix some kind of bug 
        //which is why i plan on leaving it here. seems to work fine though without it.
        //if(blinkhand && !_target->controller()->game->isInZone(_target,_target->controller()->game->hand))
        //{
        //    this->forceDestroy = 1;
        //    return;
        //}
        //else if(!blinkhand && !_target->controller()->game->isInZone(_target,_target->controller()->game->battlefield))
        //{
        //    this->forceDestroy = 1;
        //    return;
        //}
        _target->controller()->game->putInZone(_target, _target->currentZone,
            _target->owner->game->exile);
        if(_target->isToken)
        {
            //if our target is a token, we're done as soon as its sent to exile.
            this->forceDestroy = 1;
            return;
        }
        _target = _target->next;
        _target->blinked = true;
        Blinked = _target;
        if(!blinkueot && !blinkForSource)
        {
            returnCardIntoPlay(_target);
        }
    }
}

void ABlink::returnCardIntoPlay(MTGCardInstance* _target) {
    MTGCardInstance * Blinker = NULL;
    if(!_target->blinked)
    {
        this->forceDestroy = 1;
        return;
    }
    if (!blinkhand)
        Blinker = _target->controller()->game->putInZone(
            _target,
            _target->currentZone,
            _target->owner->game->battlefield);
    if (blinkhand)
    {
        _target->controller()->game->putInZone(
            _target,
            _target->currentZone,
            _target->owner->game->hand);
        return;
    }
    Spell * spell = NEW Spell(game, Blinker);
    spell->source->counters->init();
    if (spell->source->hasSubtype(Subtypes::TYPE_AURA) && !blinkhand)
    {
        TargetChooserFactory tcf(game);
        TargetChooser * tc = tcf.createTargetChooser(
            spell->source->spellTargetType,
            spell->source);
        if (!tc->validTargetsExist())
        {
            spell->source->owner->game->putInExile(spell->source);
            SAFE_DELETE(spell);
            SAFE_DELETE(tc);
            this->forceDestroy = 1;
            return;
        }

        /*MTGGameZone * inplay = spell->source->owner->game->inPlay;
        spell->source->target = NULL;
        for (int i = game->getRandomGenerator()->random()%inplay->nb_cards;;i = game->getRandomGenerator()->random()%inplay->nb_cards)
        {
            if(tc->canTarget(inplay->cards[i]) && spell->source->target == NULL)
            {
                spell->source->target = inplay->cards[i];
                spell->getNextCardTarget();
                spell->resolve();
                SAFE_DELETE(spell);
                SAFE_DELETE(tc);
                this->forceDestroy = 1;
                return;
            }
        }*/
        //replaced with castcard(putinplay)
        MTGAbility *a = NEW AACastCard(game, game->mLayers->actionLayer()->getMaxId(), Blinker, Blinker,false,false,false,"","Return to Play",false,true);
        a->oneShot = false;
        a->canBeInterrupted = false;
        a->addToGame();
        SAFE_DELETE(spell);
        SAFE_DELETE(tc);
        this->forceDestroy = 1;
        return;
    }
    spell->source->power = spell->source->origpower;
    spell->source->toughness = spell->source->origtoughness;
    spell->source->X = 0;
    if (!spell->source->hasSubtype(Subtypes::TYPE_AURA)) {
        spell->resolve();
        if (stored)
        {
            MTGAbility * clonedStored = stored->clone();
            clonedStored->target = spell->source;
            if (clonedStored->oneShot)
            {
                clonedStored->resolve();
                delete (clonedStored);
            }
            else
            {
                clonedStored->addToGame();
            }
        }
    }
    SAFE_DELETE(spell);
    SAFE_DELETE(tc);
    SAFE_DELETE(stored);
    this->forceDestroy = 1;
    Blinked = NULL;
}

int ABlink::resolve()
{
    return 0;
}
const string ABlink::getMenuText()
{
    return "Blink";
}

ABlink * ABlink::clone() const
{
    ABlink * a = NEW ABlink(*this);
    a->stored = stored ? stored->clone() : NULL;
    a->forceDestroy = -1;
    return a;
};
ABlink::~ABlink()
{
    SAFE_DELETE(stored);
}

ABlinkGeneric::ABlinkGeneric(GameObserver* observer, int _id, MTGCardInstance * card, MTGCardInstance * _target,bool blinkueot,bool blinkForSource,bool blinkhand,MTGAbility * stored) :
    InstantAbility(observer, _id, source, _target)
{
    ability = NEW ABlink(observer, _id,card,_target,blinkueot,blinkForSource,blinkhand,stored);
}

int ABlinkGeneric::resolve()
{
    ABlink * a = ability->clone();
    a->target = target;
    a->addToGame();
    return 1;
}

const string ABlinkGeneric::getMenuText()
{
    return "Blink";
}

ABlinkGeneric * ABlinkGeneric::clone() const
{
    ABlinkGeneric * a = NEW ABlinkGeneric(*this);
    a->ability = this->ability->clone();
    a->oneShot = 1;
    return a;
}

ABlinkGeneric::~ABlinkGeneric()
{
    SAFE_DELETE(ability);
}

// target becomes blocked by source
AABlock::AABlock(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost *) :
InstantAbility(observer, id, card, target)
{
    target = _target;
}

int AABlock::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    source = (MTGCardInstance*)source;
    if (_target && source->canBlock(_target))
    {
       source->toggleDefenser(_target);
       source->getObserver()->isInterrupting = NULL;
    }
    return 1;
}

AABlock * AABlock::clone() const
{
    return NEW AABlock(*this);
}

// target becomes pair of source
PairCard::PairCard(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost *) :
InstantAbility(observer, id, card, target)
{
    target = _target;
    oneShot = true;
    forceDestroy = 1;
}

int PairCard::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    source = (MTGCardInstance*)source;
    if (_target && !_target->myPair && source)
    {
        source->myPair = _target;
        _target->myPair = source;
    }
    return 1;
}

PairCard * PairCard::clone() const
{
    return NEW PairCard(*this);
}
//target is dredged
dredgeCard::dredgeCard(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost *) :
InstantAbility(observer, id, card, target)
{
    target = _target;
    oneShot = true;
    forceDestroy = 1;
}

int dredgeCard::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if(_target)
    {
        for(int j = 0; j < _target->data->dredge();j++)
        {
            _target->controller()->game->putInZone(
                _target->controller()->game->library->cards[_target->controller()->game->library->nb_cards - 1],
                _target->controller()->game->library, _target->controller()->game->graveyard);
        }
        _target->controller()->game->putInZone(_target,_target->currentZone,_target->controller()->game->hand);
    }
    return 1;
}

dredgeCard * dredgeCard::clone() const
{
    return NEW dredgeCard(*this);
}

// target becomes a parent of card(source)
AAConnect::AAConnect(GameObserver* observer, int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost *) :
InstantAbility(observer, id, card, target)
{
    target = _target;
}

int AAConnect::resolve()
{
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if (_target)
    {
        while (_target->next)
            _target = _target->next;
        _target->childrenCards.push_back(source);
        source->parentCards.push_back(_target);
        //weapon
        if(source->hasSubtype(Subtypes::TYPE_EQUIPMENT))
        {
            for (size_t i = 1; i < game->mLayers->actionLayer()->mObjects.size(); i++)
            {
                MTGAbility * a = ((MTGAbility *) game->mLayers->actionLayer()->mObjects[i]);
                AEquip * eq = dynamic_cast<AEquip*> (a);
                if (eq && eq->source == source)
                {
                    ((AEquip*)a)->unequip();
                    ((AEquip*)a)->equip(_target);
                }
            }
        }
        else
        {
            if(source->target)
                source->target = NULL;
            //clearing the source target allows us to use target= line
            //without creating side effects on any other abilities a card has
            //connect has to be the first ability in the cards lines unless you want it to do effects to the targeted card!!!
        }
    }
    return 1;
}

AAConnect * AAConnect::clone() const
{
    return NEW AAConnect(*this);
}

AEquip::AEquip(GameObserver* observer, int _id, MTGCardInstance * _source, ManaCost * _cost, int restrictions) :
    TargetAbility(observer, _id, _source, NULL, _cost, restrictions)
{
    aType = MTGAbility::STANDARD_EQUIP;
    isAttach = restrictions != ActivatedAbility::AS_SORCERY;
}

int AEquip::unequip()
{
    if (source->target)
    {
        source->target->equipment -= 1;
        source->parentCards.clear();
        for (unsigned int w = 0; w < source->target->childrenCards.size(); w++)
        {
            MTGCardInstance * child = source->target->childrenCards[w];
            if (child == source)
                source->target->childrenCards.erase(source->target->childrenCards.begin() + w);
        }
    }
    source->target = NULL;
    for (size_t i = 0; i < currentAbilities.size(); ++i)
    {
        MTGAbility * a = currentAbilities[i];
        if (dynamic_cast<AEquip *> (a) || dynamic_cast<ATeach *> (a) || dynamic_cast<AAConnect *> (a)
            || dynamic_cast<AANewTarget *> (AbilityFactory::getCoreAbility(a))
            || (a->aType == MTGAbility::STANDARD_TOKENCREATOR && a->oneShot))
        {
            SAFE_DELETE(a);
            continue;
        }
        game->removeObserver(currentAbilities[i]);
    }
    currentAbilities.clear();
    WEvent * e = NEW WEventCardUnattached(source);
    game->receiveEvent(e);
    return 1;
}

int AEquip::equip(MTGCardInstance * equipped)
{
    source->target = equipped;
    source->target->equipment += 1;
    source->parentCards.push_back(equipped);
    source->target->childrenCards.push_back((MTGCardInstance*)source);
    AbilityFactory af(game);
    af.getAbilities(&currentAbilities, NULL, source);
    for (size_t i = 0; i < currentAbilities.size(); ++i)
    {
        MTGAbility * a = currentAbilities[i];
        if (dynamic_cast<AEquip *> (a)) continue;
        if (dynamic_cast<ATeach *> (a)) continue;
        if (dynamic_cast<AAConnect *> (a)) continue;
        if (dynamic_cast<AANewTarget *> (af.getCoreAbility(a))) continue;
        if (a->aType == MTGAbility::STANDARD_TOKENCREATOR && a->oneShot)
        {
            a->forceDestroy = 1;
            continue;
        }
        if (dynamic_cast<AACopier *> (af.getCoreAbility(a)))
        {
            a->forceDestroy = 1;
            continue;
        }
        //we generally dont want to pass oneShot tokencreators to the cards
        //we equip...
        a->addToGame();
    }
    WEvent * e = NEW WEventCardEquipped(source);
    game->receiveEvent(e);
    return 1;
}

int AEquip::resolve()
{
    MTGCardInstance * mTarget = tc->getNextCardTarget();
    if (!mTarget) return 0;
    if (mTarget == source) return 0;
    unequip();
    equip(mTarget);
    return 1;
}

const string AEquip::getMenuText()
{
    if (isAttach)
        return "Attach";
    else
        return "Equip";
}

int AEquip::testDestroy()
{
    if (source->target && !game->isInPlay(source->target))
        unequip();
    if (!game->connectRule)
    {
        if (source->target && TargetAbility::tc && !TargetAbility::tc->canTarget((Targetable *)source->target,true))
            unequip();
    }
    return TargetAbility::testDestroy();
}

int AEquip::destroy()
{
    unequip();
    return TargetAbility::destroy();
}

AEquip * AEquip::clone() const
{
    return NEW AEquip(*this);
}

// casting a card for free, or casting a copy of a card.
AACastCard::AACastCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target,bool _restricted,bool _copied,bool asNormal,string _namedCard,string _name,bool _noEvent,bool putinplay,bool madness) :
   MTGAbility(observer, _id, _source),restricted(_restricted),asCopy(_copied),normal(asNormal),cardNamed(_namedCard),nameThis(_name),noEvent(_noEvent),putinplay(putinplay), asNormalMadness(madness)
{
    target = _target;
    andAbility = NULL;
    processed = false;
    theNamedCard = NULL;
}


void AACastCard::Update(float dt)
{
   MTGAbility::Update(dt);
   if (processed)
       return;
   if(cardNamed.size() && !theNamedCard)
   {
       theNamedCard = makeCard();
   }
   if(putinplay)
   {
       MTGCardInstance * toCheck = (MTGCardInstance*)target;
       toCheck->target = NULL;
       toCheck->playerTarget = NULL;
       toCheck->bypassTC = true;
       TargetChooserFactory tcf(game);
       TargetChooser * atc = tcf.createTargetChooser(toCheck->spellTargetType,toCheck);
       if ((toCheck->hasType(Subtypes::TYPE_AURA) && !atc->validTargetsExist())||toCheck->isToken)
       {
           processed = true;
           this->forceDestroy = 1;
           return ;
       }
       SAFE_DELETE(atc);
   }
   if (restricted)
   {
       MTGCardInstance * toCheck = (MTGCardInstance*)target;
       if(theNamedCard)
           toCheck = theNamedCard;
       if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(toCheck, source->controller()->game->stack) == PlayRestriction::CANT_PLAY)
       {
           processed = true;
           this->forceDestroy = 1;
           return ;
       }
       if(!allowedToCast(toCheck,source->controller()))
       {
           processed = true;
           this->forceDestroy = 1;
           return;
       }
       /*if(!toCheck->hasType(Subtypes::TYPE_INSTANT) && !(game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN))
       {
           processed = true;
           this->forceDestroy = 1;
           return;
       }*/
   }
   MTGCardInstance * toCheck = (MTGCardInstance*)target;
   if(theNamedCard)
       toCheck = theNamedCard;
   if(toCheck && toCheck->spellTargetType.size())
   {
       TargetChooserFactory tcf(game);
       TargetChooser * stc = tcf.createTargetChooser(toCheck->spellTargetType,toCheck);
       if (!stc->validTargetsExist()||toCheck->isToken)
       {
           processed = true;
           this->forceDestroy = 1;
           return;
       }
       SAFE_DELETE(stc);
   }
   if (Spell * checkSpell = dynamic_cast<Spell*>(target))
   {
       toCheck = checkSpell->source;
   }
   if (!game->targetListIsSet(toCheck))
   {
       if(game->targetChooser)
           game->targetChooser->Owner = source->controller();//sources controller is the caster
       return;
   }
   resolveSpell();
   this->forceDestroy = 1;
   return;
}
int AACastCard::isReactingToTargetClick(Targetable * card){return 0;}
int AACastCard::reactToTargetClick(Targetable * object)
{
   if (MTGCardInstance * cObject = dynamic_cast<MTGCardInstance *>(object))
       return reactToClick(cObject);

   if (waitingForAnswer)
   {
       if (tc->toggleTarget(object) == TARGET_OK_FULL)
       {
           waitingForAnswer = 0;
           game->mLayers->actionLayer()->setCurrentWaitingAction(NULL);
           return MTGAbility::reactToClick(source);
       }
       return 1;
   }
   return 0;
}

MTGCardInstance * AACastCard::makeCard()
{
   MTGCardInstance * card = NULL;
   MTGCard * cardData = MTGCollection()->getCardByName(cardNamed);
   card = NEW MTGCardInstance(cardData, source->controller()->game);
   source->controller()->game->temp->addCard(card);
   return card;
}

int AACastCard::resolveSpell()
{
    if (processed)
        return 0;
    MTGCardInstance * _target = (MTGCardInstance *) target;
    if(theNamedCard)
        _target = theNamedCard;
    if (Spell * checkSpell = dynamic_cast<Spell*>(target))
    {
        _target = checkSpell->source;
    }
    if(asCopy)
    {
        MTGCard * cardToCopy = MTGCollection()->getCardById(_target->getId());
        MTGCardInstance * myDummy = NULL;
        myDummy = NEW MTGCardInstance(cardToCopy, source->controller()->game);
        source->controller()->game->garbage->addCard(myDummy);
        _target = myDummy;
        _target->isToken = 1;
        _target->changeController(source->controller(),true);
    }
    if (_target)
    {
        
        if (_target->isLand())
        {
            MTGCardInstance * copy = _target->controller()->game->putInZone(_target, _target->currentZone, source->controller()->game->temp,noEvent);
            copy->changeController(source->controller(),true);
            Spell * spell = NEW Spell(game, 0,copy,NULL,NULL, 1);
            spell->resolve();
            delete spell;
        }
        else
        {
            Spell * spell = NULL;
            MTGCardInstance * copy = NULL;
            if ((normal || asNormalMadness)||(!_target->hasType(Subtypes::TYPE_INSTANT) && !_target->hasType(Subtypes::TYPE_SORCERY)))
            {
                if (putinplay && (_target->hasType(Subtypes::TYPE_ARTIFACT)||_target->hasType(Subtypes::TYPE_CREATURE)||_target->hasType(Subtypes::TYPE_ENCHANTMENT)||_target->hasType(Subtypes::TYPE_PLANESWALKER)))
                    copy =_target->controller()->game->putInZone(_target, _target->currentZone, source->controller()->game->battlefield,noEvent);
                else
                    copy =_target->controller()->game->putInZone(_target, _target->currentZone, source->controller()->game->stack,noEvent);
                copy->changeController(source->controller(),true);
                if(asNormalMadness)
                copy->MadnessPlay = true;
            }
            else
            {
                if (putinplay && (_target->hasType(Subtypes::TYPE_ARTIFACT)||_target->hasType(Subtypes::TYPE_CREATURE)||_target->hasType(Subtypes::TYPE_ENCHANTMENT)||_target->hasType(Subtypes::TYPE_PLANESWALKER)))
                    copy =_target->controller()->game->putInZone(_target, _target->currentZone, source->controller()->game->battlefield,noEvent);
                else
                    copy =_target->controller()->game->putInZone(_target, _target->currentZone, _target->controller()->game->stack,noEvent);
                copy->changeController(source->controller(),true);
            }
            if (game->targetChooser)
            {
                game->targetChooser->Owner = source->controller();
                spell = game->mLayers->stackLayer()->addSpell(copy, game->targetChooser, NULL, 1, 0);
                game->targetChooser = NULL;
            }
            else
            {
                spell = game->mLayers->stackLayer()->addSpell(copy, NULL, NULL, 1, 0);
            }

            if (copy->has(Constants::STORM))
            {
                int storm = _target->controller()->game->stack->seenThisTurn("*", Constants::CAST_ALL) + source->controller()->opponent()->game->stack->seenThisTurn("*", Constants::CAST_ALL);
                
                for (int i = storm; i > 1; i--)
                {
                    spell = game->mLayers->stackLayer()->addSpell(copy, NULL, 0, 1, 1);

                }
            }
            if (!copy->has(Constants::STORM))
            {
                copy->X = _target->X;
                copy->castX = copy->X;
            }
            if(andAbility)
            {
                MTGAbility * andAbilityClone = andAbility->clone();
                andAbilityClone->target = copy;
                if(andAbility->oneShot)
                {
                    andAbilityClone->resolve();
                    SAFE_DELETE(andAbilityClone);
                }
                else
                {
                    andAbilityClone->addToGame();
                }
            }
        }
        this->forceDestroy = true;
        processed = true;
        return 1;
    }
    return 0;
}

const string AACastCard::getMenuText()
{
    if(nameThis.size())
        return nameThis.c_str();
    if(putinplay)
        return "Put Into Play";
    return "Cast Card";
}

AACastCard * AACastCard::clone() const
{
    AACastCard * a = NEW AACastCard(*this);
    if(tc)
    a->tc = tc->clone();
    if(andAbility)
        a->andAbility = andAbility->clone();
    return a;
}
AACastCard::~AACastCard()
{
    SAFE_DELETE(tc);
    SAFE_DELETE(andAbility);
}

//Tutorial Messaging

ATutorialMessage::ATutorialMessage(GameObserver* observer, MTGCardInstance * source, string message, int limit)
    : MTGAbility(observer, 0, source), IconButtonsController(observer->getInput(), 0, 0), mLimit(limit)
{
    mBgTex = NULL;

    mElapsed = 0;
    mIsImage = false;

    for (int i = 0; i < 9; i++)
        mBg[i] = NULL;

    if(game->getResourceManager())
    {
        string gfx = game->getResourceManager()->graphicsFile(message);
        if (fileExists(gfx.c_str()))
        {
            mIsImage = true;
            mMessage = message;
        }
        else
        {
            mMessage = _(message); //translate directly here, remove this and translate at rendering time if it bites us
            ReplaceString(mMessage, "\\n", "\n");
        }
    }

    if (mIsImage)
    {
        mX = SCREEN_WIDTH_F / 2;
        mY = SCREEN_HEIGHT_F / 2;

    }
    else
    {
        mX = 0;
        mY = -SCREEN_HEIGHT_F - 0.1f; //Offscreen
    }
    mDontShow = mUserCloseRequest = (mLimit > 0) && (alreadyShown() >= mLimit);

    if(mDontShow)
        forceDestroy = 1;
}


string ATutorialMessage::getOptionName()
{
    std::stringstream out;
    out << "tuto_";
    out << hash_djb2(mMessage.c_str());
    return out.str();
}

int ATutorialMessage::alreadyShown()
{
    return options[getOptionName()].number;
}

bool ATutorialMessage::CheckUserInput(JButton key)
{
    if (mUserCloseRequest) return false;

    if(key == JGE_BTN_SEC || key == JGE_BTN_OK)
    {
        ButtonPressed(0, 1);
        return true;
    }

    //Required for Mouse/touch input
    IconButtonsController::CheckUserInput(key);

    return true; //this ability is modal, so it catches all key events until it gets closed
}

void ATutorialMessage::Update(float dt)
{
    if (!game->mLayers->stackLayer()->getCurrentTutorial() && !mDontShow)
        game->mLayers->stackLayer()->setCurrentTutorial(this);

    if (game->mLayers->stackLayer()->getCurrentTutorial() != this)
        return;

    if (mUserCloseRequest && mY < -SCREEN_HEIGHT)
        mDontShow = true;

    if (mDontShow)
    {
        game->mLayers->stackLayer()->setCurrentTutorial(0);
        forceDestroy = 1;
        return;
    }

    mElapsed += dt;

    if(!mUserCloseRequest)
        IconButtonsController::Update(dt);

    if (mIsImage)
        return;

    //Below this only affects "text" mode
    if (!mUserCloseRequest && mY < 0)
    {
        mY = -SCREEN_HEIGHT + (SCREEN_HEIGHT * mElapsed / 0.75f); //Todo: more physical drop-in.
        if (mY >= 0)
            mY = 0;
    }
    else if (mUserCloseRequest && mY > -SCREEN_HEIGHT)
    {
        mY = -(SCREEN_HEIGHT * mElapsed / 0.75f);
    }
}

void ATutorialMessage::ButtonPressed(int, int)
{
    //TODO : cancel ALL tips/tutorials for JGE_BTN_SEC?
    if (mLimit)
    {
        string optionName = getOptionName();
        options[optionName].number = options[optionName].number + 1;
        options.save(); //TODO: if we experience I/O slowness in tutorials, move this save at the end of a turn, or at the end of the game.
    }
    mElapsed = 0;
    mUserCloseRequest = true;
}

void ATutorialMessage::Render()
{
    if (mDontShow)
        return;

    if (mY < -SCREEN_HEIGHT)
        return;

    if (!mBgTex)
    {
        if (mIsImage)
        {
            mBgTex = game->getResourceManager()->RetrieveTexture(mMessage, RETRIEVE_LOCK);
            if (mBgTex)
            {
                mBg[0] = NEW JQuad(mBgTex, 0, 0, (float) mBgTex->mWidth, (float) mBgTex->mHeight);
                mBg[0]->SetHotSpot(mBg[0]->mWidth / 2, mBg[0]->mHeight / 2);

                //Continue Button
                JQuadPtr quad =  game->getResourceManager()->RetrieveQuad("iconspsp.png", 4 * 32, 0, 32, 32, "iconpsp4", RETRIEVE_MANAGE);
                quad->SetHotSpot(16, 16);
                IconButton * iconButton = NEW IconButton(1, this, quad.get(), 0, mBg[0]->mHeight / 2, 0.7f, Fonts::MAGIC_FONT, _("continue"), 0, 16, true);
                Add(iconButton);
            }

            if (options[Options::SFXVOLUME].number > 0)
            {
                game->getResourceManager()->PlaySample("tutorial.wav");
            }
        }
        else
        {
            mBgTex = game->getResourceManager()->RetrieveTexture("taskboard.png", RETRIEVE_LOCK);

            float unitH = static_cast<float> (mBgTex->mHeight / 4);
            float unitW = static_cast<float> (mBgTex->mWidth / 4);
            if (unitH == 0 || unitW == 0) return;

            if (mBgTex)
            {
                mBg[0] = NEW JQuad(mBgTex, 0, 0, unitW, unitH);
                mBg[1] = NEW JQuad(mBgTex, unitW, 0, unitW * 2, unitH);
                mBg[2] = NEW JQuad(mBgTex, unitW * 3, 0, unitW, unitH);
                mBg[3] = NEW JQuad(mBgTex, 0, unitH, unitW, unitH * 2);
                mBg[4] = NEW JQuad(mBgTex, unitW, unitH, unitW * 2, unitH * 2);
                mBg[5] = NEW JQuad(mBgTex, unitW * 3, unitH, unitW, unitH * 2);
                mBg[6] = NEW JQuad(mBgTex, 0, unitH * 3, unitW, unitH);
                mBg[7] = NEW JQuad(mBgTex, unitW, unitH * 3, unitW * 2, unitH);
                mBg[8] = NEW JQuad(mBgTex, unitW * 3, unitH * 3, unitW, unitH);
            }

            //Continue Button
            JQuadPtr quad =  game->getResourceManager()->RetrieveQuad("iconspsp.png", 4 * 32, 0, 32, 32, "iconpsp4", RETRIEVE_MANAGE);
            quad->SetHotSpot(16, 16);
            IconButton * iconButton = NEW IconButton(1, this, quad.get(), SCREEN_WIDTH_F / 2,  SCREEN_HEIGHT_F - 60, 0.7f, Fonts::MAGIC_FONT, _("continue"), 0, 16, true);
            Add(iconButton);

            mSH = 64 / unitH;
            mSW = 64 / unitW;

            if (options[Options::SFXVOLUME].number > 0)
            {
                game->getResourceManager()->PlaySample("chain.wav");
            }
        }
    }

    JRenderer * r = JRenderer::GetInstance();

    //Render background board
    if (mBgTex)
    {
        if (mIsImage)
        {
            int alpha = mUserCloseRequest ? MAX(0, 255 - (int)(mElapsed * 500)) : MIN(255, (int)(mElapsed * 500)) ;
            if (mUserCloseRequest && alpha == 0)
                mDontShow = true;

            r->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(alpha / 2,0,0,0));
            mBg[0]->SetColor(ARGB(alpha,255,255,255));
            r->RenderQuad(mBg[0], SCREEN_WIDTH_F /2 , SCREEN_HEIGHT_F / 2 , 0);
            IconButtonsController::SetColor(ARGB(alpha,255,255,255));
        }
        else 
        {
            //Setup fonts.
            WFont * f2 = game->getResourceManager()->GetWFont(Fonts::MAGIC_FONT);
            f2->SetColor(ARGB(255, 205, 237, 240));

            r->FillRect(0, mY, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(128,0,0,0));
            r->RenderQuad(mBg[0], 0, mY, 0, mSW, mSH); //TL
            r->RenderQuad(mBg[2], SCREEN_WIDTH - 64, mY, 0, mSW, mSH); //TR
            r->RenderQuad(mBg[6], 0, mY + SCREEN_HEIGHT - 64, 0, mSW, mSH); //BL
            r->RenderQuad(mBg[8], SCREEN_WIDTH - 64, mY + SCREEN_HEIGHT - 64, 0, mSW, mSH); //BR

            //Stretch the sides
            float stretchV = (144.0f / 128.0f) * mSH;
            float stretchH = (176.0f / 128.0f) * mSW;
            r->RenderQuad(mBg[3], 0, mY + 64, 0, mSW, stretchV); //L
            r->RenderQuad(mBg[5], SCREEN_WIDTH - 64, mY + 64, 0, mSW, stretchV); //R
            r->RenderQuad(mBg[1], 64, mY, 0, stretchH, mSH); //T1
            r->RenderQuad(mBg[1], 240, mY, 0, stretchH, mSH); //T1
            r->RenderQuad(mBg[7], 64, mY + 208, 0, stretchH, mSH); //B1
            r->RenderQuad(mBg[7], 240, mY + 208, 0, stretchH, mSH); //B1
            r->RenderQuad(mBg[4], 64, mY + 64, 0, stretchH, stretchV); //Center1
            r->RenderQuad(mBg[4], 240, mY + 64, 0, stretchH, stretchV); //Center2
        }
    }
    else
    {
        r->FillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, ARGB(128,0,0,0));
        r->FillRect(10, 10 + mY, SCREEN_WIDTH - 10, SCREEN_HEIGHT - 10, ARGB(128,0,0,0));
    }

    if (!mBgTex || !mIsImage)
    {
        float posX = 40, posY = mY + 20;
        string title = _("Help");

        WFont * f = game->getResourceManager()->GetWFont(Fonts::MAGIC_FONT);
        WFont * f3 = game->getResourceManager()->GetWFont(Fonts::MENU_FONT); //OPTION_FONT
        f->SetColor(ARGB(255, 55, 46, 34));
        f3->SetColor(ARGB(255, 219, 206, 151));

        f3->DrawString(title.c_str(), static_cast<float> ((SCREEN_WIDTH - 20) / 2 - title.length() * 4), posY);
        posY += 30;

        f->DrawString(_(mMessage).c_str(), posX, posY);
    
        f->SetScale(1);
    }

    IconButtonsController::Render();

}

ATutorialMessage * ATutorialMessage::clone() const
{
    ATutorialMessage * copy =  NEW ATutorialMessage(*this);
    copy->mUserCloseRequest = (copy->alreadyShown() > 0);
    return copy;
}

ATutorialMessage::~ATutorialMessage()
{
    if (mBgTex)
    {
        game->getResourceManager()->Release(mBgTex);
        for (int i = 0; i < 9; i++)
            SAFE_DELETE(mBg[i]);
    }
}

// utility functions

// Given a delimited string of abilities, add the ones to the list that are "Basic"  MTG abilities
void PopulateAbilityIndexVector(list<int>& abilities, const string& abilityStringList, char delimiter)
{
    vector<string> abilitiesList = split(abilityStringList, delimiter);
    for (vector<string>::iterator iter = abilitiesList.begin(); iter != abilitiesList.end(); ++iter)
    {
        int abilityIndex = Constants::GetBasicAbilityIndex(*iter);

        if (abilityIndex != -1)
            abilities.push_back(abilityIndex);
    }
}

void PopulateColorIndexVector(list<int>& colors, const string& colorStringList, char delimiter)
{
    vector<string> abilitiesList = split(colorStringList, delimiter);
    for (vector<string>::iterator iter = abilitiesList.begin(); iter != abilitiesList.end(); ++iter)
    {
        for (int colorIndex = Constants::MTG_COLOR_ARTIFACT; colorIndex < Constants::NB_Colors; ++colorIndex)
        {
            // if the text is not a basic ability but contains a valid color add it to the color vector
            if ((Constants::GetBasicAbilityIndex(*iter) == -1)
                    && ((*iter).find(Constants::MTGColorStrings[colorIndex]) != string::npos))
                colors.push_back(colorIndex);
        }
    }
}

void PopulateSubtypesIndexVector(list<int>& types, const string& subTypesStringList, char delimiter)
{
    vector<string> subTypesList = split(subTypesStringList, delimiter);
    for (vector<string>::iterator it = subTypesList.begin(); it != subTypesList.end(); ++it)
    {
        string subtype = *it;
        size_t id = MTGAllCards::findType(subtype);
        if (id != string::npos)
            types.push_back(id);
    }
}
