From a418e10c477c13b7a8d0589b88b4df25fe509a30 Mon Sep 17 00:00:00 2001 From: "wagic.the.homebrew" Date: Wed, 12 Nov 2008 14:38:30 +0000 Subject: [PATCH] Erwan - Trying to add generic classes for Triggered abilities. PLEASE DO NOT USE THESE RIGHT NOW, Not Tested AT ALL ! --- projects/mtg/include/ActionElement.h | 1 - projects/mtg/include/AllAbilities.h | 5838 ++++++++++++------------- projects/mtg/include/MTGAbility.h | 311 +- projects/mtg/include/MTGDefinitions.h | 366 +- projects/mtg/src/ActionElement.cpp | 25 - projects/mtg/src/MTGAbility.cpp | 3486 +++++++-------- 6 files changed, 5003 insertions(+), 5024 deletions(-) diff --git a/projects/mtg/include/ActionElement.h b/projects/mtg/include/ActionElement.h index 3c7d5ff8e..a9444b1f6 100644 --- a/projects/mtg/include/ActionElement.h +++ b/projects/mtg/include/ActionElement.h @@ -29,7 +29,6 @@ class ActionElement: public JGuiObject{ int newPhase; int modal; int waitingForAnswer; - void RenderMessageBackground(float y0, int height); int getActivity(); virtual void Update(float dt){}; virtual void Render(){}; diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 2f406d3bd..c3abb8dc3 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -1,2981 +1,2857 @@ -#ifndef _CARDS_H_ -#define _CARDS_H_ - -#include "MTGAbility.h" -#include "GroupOfCards.h" -#include "ManaCost.h" -#include "CardDescriptor.h" -#include "AIPlayer.h" -#include "CardDisplay.h" -#include "Subtypes.h" -#include "CardGui.h" - -#include -#include - - -#include -using std::map; - -/* - Generic classes -*/ - - -//Drawer, allows to draw a card for a cost: - -class ADrawer:public ActivatedAbility{ - public: - int nbcards; - ADrawer(int _id, MTGCardInstance * card,ManaCost * _cost, int _nbcards = 1, int _tap = 1):ActivatedAbility(_id, card,_cost,0,_tap),nbcards(_nbcards){ - } - - int resolve(){ - game->mLayers->stackLayer()->addDraw(source->controller(),nbcards); - return 1; - } -}; - - -//Destroyer. TargetAbility -class ADestroyer:public TargetAbility{ - public: - int bury; - ADestroyer(int _id, MTGCardInstance * _source, TargetChooser * _tc = NULL, int _bury = 0):TargetAbility(_id,_source, tc),bury(_bury){ - if (!tc) tc = NEW CreatureTargetChooser(); - } - - int resolve(){ - MTGCardInstance * _target = tc->getNextCardTarget(); - if(_target){ - if (bury){ - _target->controller()->game->putInGraveyard(_target); - }else{ - game->mLayers->stackLayer()->addPutInGraveyard(_target); - } - return 1; - } - return 0; - } - -}; - -//Destroyer. TargetAbility -class ABurier:public ADestroyer{ - public: - ABurier(int _id, MTGCardInstance * _source, TargetChooser * _tc = NULL):ADestroyer(_id,_source, tc,1){ - } -}; - - -/*Changes one of the basic abilities of target - source : spell - target : spell target (creature) - modifier : 1 to add the ability, 0 to remove it - _ability : Id of the ability, as described in mtgdefinitions -*/ -class ABasicAbilityModifier:public MTGAbility{ - public: - int modifier; - int ability; - int value_before_modification; - ABasicAbilityModifier(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _ability, int _modifier = 1): MTGAbility(_id,_source,_target),modifier(_modifier),ability(_ability){ - value_before_modification = ((MTGCardInstance * )target)->basicAbilities[ability]; - ((MTGCardInstance * )target)->basicAbilities[ability]=modifier; - } - - int destroy(){ - if (((MTGCardInstance * )target)->basicAbilities[ability] == modifier){ - ((MTGCardInstance * )target)->basicAbilities[ability] = value_before_modification; - return 1; - }else{ - //BUG !!! - return 0; - } - } -}; - -//Modifies an ability until end of turn. Needs a target -class ABasicAbilityModifierUntilEOT:public TargetAbility{ - public: - MTGCardInstance * mTargets[50]; - int nbTargets; - int modifier; - int stateBeforeActivation[50]; - int ability; - ABasicAbilityModifierUntilEOT(int _id, MTGCardInstance * _source, int _ability, ManaCost * _cost, TargetChooser * _tc = NULL, int _modifier = 1): TargetAbility(_id,_source,_cost),modifier(_modifier), ability(_ability){ - nbTargets = 0; - tc = _tc; - if (!tc) tc = NEW CreatureTargetChooser(_source); - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ - for (int i = 0; i < nbTargets; i++){ - MTGCardInstance * mTarget = mTargets[i]; - if(mTarget && mTarget->basicAbilities[ability]){ - mTarget->basicAbilities[ability] = stateBeforeActivation[i]; - } - } - nbTargets = 0; - } - TargetAbility::Update(dt); - } - - - int resolve(){ - MTGCardInstance * mTarget = tc->getNextCardTarget(); - if (mTarget){ - mTargets[nbTargets] = mTarget; - stateBeforeActivation[nbTargets] = mTarget->basicAbilities[ability]; - mTarget->basicAbilities[ability] = modifier; - nbTargets++; - } - return 1; - } - - -}; - -/*Instants that modifies a basic ability until end of turn */ -class AInstantBasicAbilityModifierUntilEOT: public InstantAbility{ - public: - int stateBeforeActivation; - int ability; - AInstantBasicAbilityModifierUntilEOT(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _ability, int value):InstantAbility(_id, _source, _target),ability(_ability){ - stateBeforeActivation = _target->basicAbilities[ability]; - _target->basicAbilities[ability] = value; - } - - int destroy(){ - ((MTGCardInstance *)target)->basicAbilities[ability] = stateBeforeActivation; - return 1; - } - -}; - -//Alteration of Ability until of turn (Aura) -class ABasicAbilityAuraModifierUntilEOT: public ActivatedAbility{ - public: - int stateBeforeActivation; - int ability; - int value; - ABasicAbilityAuraModifierUntilEOT(int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost, int _ability, int _value = 1):ActivatedAbility(_id,_source, _cost, 0,0), ability(_ability), value(_value){ - target = _target; - stateBeforeActivation = _target->basicAbilities[ability]; - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ - MTGCardInstance * _target = (MTGCardInstance *) target; - _target->basicAbilities[ability] = stateBeforeActivation; - } - ActivatedAbility::Update(dt); - } - - int resolve(){ - MTGCardInstance * _target = (MTGCardInstance *) target; - stateBeforeActivation = _target->basicAbilities[ability]; - _target->basicAbilities[ability] = value; - return 1; - } - -}; - - - -/*Gives life each time a spell matching CardDescriptor's criteria are match . Optionnal manacost*/ -class ASpellCastLife:public MTGAbility{ - public: - CardDescriptor trigger; - ManaCost * cost; - int life; - MTGCardInstance * lastUsedOn; - MTGCardInstance * lastChecked; - ASpellCastLife(int id, MTGCardInstance * _source, CardDescriptor _trigger, ManaCost * _cost, int _life): MTGAbility(id, _source), trigger(_trigger), cost(_cost), life(_life){ - } - ASpellCastLife(int id, MTGCardInstance * _source, int color, ManaCost * _cost, int _life): MTGAbility(id, _source), cost(_cost), life(_life){ - trigger.setColor(color); - } - - int isReactingToClick(MTGCardInstance * _card){ - if (_card == source && game->currentlyActing()->game->inPlay->hasCard(source)){ - if (game->currentlyActing()->getManaPool()->canAfford(cost)){ - Interruptible * laststackitem = game->mLayers->stackLayer()->_(-1); - if (laststackitem && laststackitem->type == ACTION_SPELL){ - Spell * spell = (Spell*)laststackitem; - if (spell->source != lastUsedOn && trigger.match(spell->source)){ - lastChecked = spell->source; - return 1; - } - } - } - } - return 0; - } - - int reactToClick(MTGCardInstance * _card){ - if (!isReactingToClick( _card)) return 0; - game->currentlyActing()->getManaPool()->pay(cost); - game->currentlyActing()->life+=life; - lastUsedOn = lastChecked; - return 1; - } - -}; - -//Allows to untap at any moment for an amount of mana -class AUnBlocker:public MTGAbility{ - public: - ManaCost * cost; - AUnBlocker(int id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost):MTGAbility(id, _source, _target), cost(_cost){ - } - - - int isReactingToClick(MTGCardInstance * _card){ - if (_card == target && game->currentlyActing()->game->inPlay->hasCard(source) && (MTGCardInstance *) _card->isTapped()){ - if (game->currentlyActing()->getManaPool()->canAfford(cost)){ - return 1; - } - } - return 0; - } - - int reactToClick(MTGCardInstance * _card){ - if (!isReactingToClick( _card)) return 0; - game->currentlyActing()->getManaPool()->pay(cost); - _card->untap(); - return 1; - } -}; - -//Allows to untap target card once per turn for a manaCost -class AUntaperOnceDuringTurn:public AUnBlocker{ - public: - int untappedThisTurn; - int onlyPlayerTurn; - AUntaperOnceDuringTurn(int id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost, int _onlyPlayerTurn = 1):AUnBlocker(id, _source, _target, _cost){ - onlyPlayerTurn = _onlyPlayerTurn; - untappedThisTurn = 0; - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP) untappedThisTurn = 0; - AUnBlocker::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card){ - if (onlyPlayerTurn && game->currentPlayer!=source->controller()) return 0; - if (untappedThisTurn) return 0; - return AUnBlocker::isReactingToClick(card); - } - - int reactToClick(MTGCardInstance * card){ - untappedThisTurn = 1; - return AUnBlocker::reactToClick(card); - } -}; - -//Alteration of Power and Toughness (enchantments) -class APowerToughnessModifier: public MTGAbility{ - public: - int power, toughness; - APowerToughnessModifier(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness):MTGAbility(id,_source,_target),power(_power),toughness(_toughness){ - _target->power += power; - _target->addToToughness(toughness); - } - - int destroy(){ - ((MTGCardInstance *)target)->power -= power; - ((MTGCardInstance *)target)->addToToughness(-toughness); - return 1; - } -}; - -// Permanent life alteration evry turn of the target's controller. Useful only for unstable mutation currently -class APowerToughnessModifierRegularCounter:public MTGAbility{ - public: - int power, toughness; - int phase; - APowerToughnessModifierRegularCounter(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _phase, int _power, int _toughness):MTGAbility(id,_source,_target),power(_power),toughness(_toughness), phase(_phase){ - } - - void Update(float dt){ - if (newPhase !=currentPhase && newPhase==phase && game->currentPlayer==((MTGCardInstance *)target)->controller()){ - ((MTGCardInstance *)target)->power += power; - ((MTGCardInstance *)target)->addToToughness(toughness); - } - } - -}; - - -//Alteration of Power and Toughness until end of turn (TargetAbility) -// Gives +n/+m until end of turn to any card that's a target -class ATargetterPowerToughnessModifierUntilEOT: public TargetAbility{ - public: - MTGCardInstance * mTargets[50]; - int nbTargets; - int power, toughness; - - ATargetterPowerToughnessModifierUntilEOT(int _id, MTGCardInstance * _source, int _power, int _toughness, ManaCost * _cost, TargetChooser * _tc = NULL):TargetAbility(_id,_source,_tc,_cost,0),power(_power),toughness(_toughness){ - if (!tc) tc = NEW CreatureTargetChooser(_source); - nbTargets = 0; - } - - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ - for (int i = 0; i < nbTargets; i++){ - MTGCardInstance * mTarget = mTargets[i]; - if(mTarget){ - mTarget->power-=power; - mTarget->addToToughness(-toughness); - } - } - nbTargets = 0; - } - TargetAbility::Update(dt); - } - - - int resolve(){ - MTGCardInstance * mTarget = tc->getNextCardTarget(); - if (mTarget){ - mTargets[nbTargets] = mTarget; - mTarget->power+= power; - mTarget->addToToughness(toughness); - nbTargets++; - } - return 1; - } - -}; - - - -//Alteration of Power and Toughness until end of turn (Aura) -class APowerToughnessModifierUntilEndOfTurn: public MTGAbility{ - public: - int power, toughness; - int counters; - int maxcounters; - ManaCost * cost; - APowerToughnessModifierUntilEndOfTurn(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness, ManaCost * _cost, int _maxcounters = 0):MTGAbility(id,_source,_target),power(_power),toughness(_toughness),maxcounters(_maxcounters), cost(_cost){ - counters = 0; - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ - while(counters){ - ((MTGCardInstance *)target)->power -= power; - ((MTGCardInstance *)target)->addToToughness(-toughness); - counters--; - } - } - } - - int isReactingToClick(MTGCardInstance * _card){ - if (_card == source && (!maxcounters || counters < maxcounters) && game->currentlyActing()->game->inPlay->hasCard(source)){ - if (game->currentlyActing()->getManaPool()->canAfford(cost)){ - return 1; - } - } - return 0; - } - - int reactToClick(MTGCardInstance * _card){ - if (!isReactingToClick( _card)) return 0; - game->currentlyActing()->getManaPool()->pay(cost); - ((MTGCardInstance *)target)->power += power; - ((MTGCardInstance *)target)->addToToughness(toughness); - counters++; - return 1; - } -}; - - -//Alteration of Power and toughness until end of turn (instant) -class AInstantPowerToughnessModifierUntilEOT: public InstantAbility{ - public: - int power, toughness; - AInstantPowerToughnessModifierUntilEOT(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness): InstantAbility(_id, _source, _target), power(_power), toughness(_toughness){ - } - - int resolve(){ - ((MTGCardInstance *)target)->power +=power; - ((MTGCardInstance *)target)->addToToughness(toughness); - return 1; - } - - int destroy(){ - ((MTGCardInstance *)target)->power -=power; - ((MTGCardInstance *)target)->addToToughness(-toughness); - return 1; - } - -}; -//Untap Blockers with simple Mana Mechanism -class AUntapManaBlocker: public Blocker{ - public: - AUntapManaBlocker(int id, MTGCardInstance * card, ManaCost * _cost):Blocker(id, card, _cost){ - } - - AUntapManaBlocker(int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost):Blocker(id, card,_target, _cost){ - } -}; - -/* Spell Counters (Enchantment) for a mana cost */ -//LifeForce -class ASpellCounterEnchantment:public TargetAbility{ - public: - - ASpellCounterEnchantment(int _id, MTGCardInstance * _source, ManaCost * _cost,int color = -1, int _tap = 0):TargetAbility(_id,_source,NEW SpellTargetChooser(_source,color),_cost,0,_tap){ - } - - int resolve(){ - Spell * _target = tc->getNextSpellTarget(); - if(_target){ - game->mLayers->stackLayer()->Fizzle(_target); - return 1; - } - return 0; - } - -}; - -/*Mana Producers (lands) -//These have a reactToClick function, and therefore two manaProducers on the same card conflict with each other -//That means the player has to choose one. although that is perfect for cards such as birds of paradise or badlands, -other solutions need to be provided for abilities that add mana (ex: mana flare) -*/ -/* - Currently the mana is added to the pool AFTER the animation - This is VERY BAD, since we don't have any control on the duration of the animation. This can lead to bugs with - the AI, who is expecting to have the mana in its manapool right after clicking the land card !!! - The sum of "dt" has to be 0.25 for the mana to be in the manapool currently -*/ - -class AManaProducer: public MTGAbility{ - protected: - ManaCost * cost; - ManaCost * output; - string menutext; - float x0,y0,x1,y1,x,y; - float animation; - Player * controller; - - hgeParticleSystem * mParticleSys; - public: - AManaProducer(int id, MTGCardInstance * card, ManaCost * _output, ManaCost * _cost = NULL ):MTGAbility(id, card){ - LOG("==Creating ManaProducer Object"); - cost = _cost; - output=_output; - x1 = 10; - y1 = 220; - Player * player = card->controller(); - if (player == game->players[1]) y1 = 100; - x = x1; - y = y1; - animation = 0.f; - mParticleSys = NULL; - menutext = ""; - - int landColor = output->getMainColor(); - - if (landColor == MTG_COLOR_RED){ - mParticleSys = NEW hgeParticleSystem("graphics/manared.psi",GameApp::CommonRes->GetQuad("particles")); - }else if (landColor == MTG_COLOR_BLUE){ - mParticleSys = NEW hgeParticleSystem("graphics/manablue.psi", GameApp::CommonRes->GetQuad("particles")); - }else if (landColor == MTG_COLOR_GREEN){ - mParticleSys = NEW hgeParticleSystem("graphics/managreen.psi", GameApp::CommonRes->GetQuad("particles")); - }else if (landColor == MTG_COLOR_BLACK){ - mParticleSys = NEW hgeParticleSystem("graphics/manablack.psi", GameApp::CommonRes->GetQuad("particles")); - }else if (landColor == MTG_COLOR_WHITE){ - mParticleSys = NEW hgeParticleSystem("graphics/manawhite.psi", GameApp::CommonRes->GetQuad("particles")); - }else{ - mParticleSys = NEW hgeParticleSystem("graphics/mana.psi", GameApp::CommonRes->GetQuad("particles")); - } - - - - LOG("==ManaProducer Object Creation successful !"); - } - - void Update(float dt){ - if (mParticleSys) mParticleSys->Update(dt); - if (animation){ - x = (1.f - animation)*x1 + animation * x0; - y = (1.f - animation)*y1 + animation * y0; - if (mParticleSys) mParticleSys->MoveTo(x, y); - if (mParticleSys && animation == 1.f) mParticleSys->Fire(); - animation -= 4 *dt; - if (animation < 0){ - animation = 0; - controller->getManaPool()->add(output); - if (mParticleSys) mParticleSys->Stop(); - } - } - - } - - void Render(){ - JRenderer * renderer = JRenderer::GetInstance(); - if (animation){ - renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE); - if (mParticleSys) mParticleSys->Render(); - // set normal blending - renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); - } - - } - - int isReactingToClick(MTGCardInstance * _card){ - int result = 0; - if (_card == source && !source->isTapped() && game->currentlyActing()->game->inPlay->hasCard(source) && (source->hasType("land") || !source->hasSummoningSickness()) ){ - if (!cost || game->currentlyActing()->getManaPool()->canAfford(cost)) result = 1; - } - return result; - } - - int reactToClick(MTGCardInstance * _card){ - if (!isReactingToClick( _card)) return 0; - source->tapped = 1; - if (cost) GameObserver::GetInstance()->currentlyActing()->getManaPool()->pay(cost); - animation = 1.f; - CardGui * cardg = game->mLayers->playLayer()->getByCard(source); - if (cardg){ - x0 = cardg->x + 15; - y0 = cardg->y + 20; - } - controller = source->controller(); - return 1; - } - - const char * getMenuText(){ - if (menutext.size())return menutext.c_str(); - menutext = "Add "; - char buffer[128]; - int alreadyHasOne = 0; - for (int i= 0; i < 6; i++){ - int value = output->getCost(i); - if (value){ - if (alreadyHasOne) menutext.append(","); - sprintf(buffer, "%i ", value); - menutext.append(buffer); - switch (i){ - case MTG_COLOR_RED: - menutext.append("red"); - break; - case MTG_COLOR_BLUE: - menutext.append("blue"); - break; - case MTG_COLOR_GREEN: - menutext.append("green"); - break; - case MTG_COLOR_WHITE: - menutext.append("white"); - break; - case MTG_COLOR_BLACK: - menutext.append("black"); - break; - default: - break; - } - alreadyHasOne = 1; - } - } - menutext.append(" mana"); - return menutext.c_str(); - } - - int testDestroy(){ - if (animation >0) return 0; - return MTGAbility::testDestroy(); - } - - ~AManaProducer(){ - LOG("==Destroying ManaProducer Object"); - if (cost) delete cost; - SAFE_DELETE(output); - if (mParticleSys) delete mParticleSys; - LOG("==Destroying ManaProducer Object Successful!"); - } - -}; - - -/* Lifelink Ability */ -class ALifeLink:public MTGAbility{ - public: - int nbdamagesthisturn; - Damage * lastDamage; - ALifeLink(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ - nbdamagesthisturn = 0; - lastDamage = NULL; - } - - void Update(float dt){ - ActionStack * as = game->mLayers->stackLayer(); - int totaldamages = as->count(ACTION_DAMAGE,RESOLVED_OK); - if ( totaldamages > nbdamagesthisturn){ - Damage * damage = ((Damage * )as->getNext(lastDamage,ACTION_DAMAGE, RESOLVED_OK)); - while(damage){ - lastDamage = damage; - if (damage->source == source){ - source->controller()->life+= damage->damage; - } - damage = ((Damage * )as->getNext(lastDamage,ACTION_DAMAGE, RESOLVED_OK)); - } - }else if (totaldamages ==0){ - lastDamage = NULL; - } - nbdamagesthisturn = totaldamages; - } - -}; - - -//Circle of Protections -class ACircleOfProtection: public TargetAbility{ - public: - ACircleOfProtection(int _id, MTGCardInstance * source, int _color):TargetAbility(_id,source,NEW DamageTargetChooser(source,_color),NEW ManaCost(),0,0){ - cost->add(MTG_COLOR_ARTIFACT,1); - } - - int resolve(){ - Damage * damage = tc->getNextDamageTarget(); - if (!damage) return 0; - game->mLayers->stackLayer()->Fizzle(damage); - return 1; - } -}; - -//Basic regeneration mechanism for a Mana cost -class AStandardRegenerate:public ActivatedAbility{ - public: - AStandardRegenerate(int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost):ActivatedAbility(_id,_source,_cost,0,0){ - target = _target; - } - - int resolve(){ - MTGCardInstance * _target = (MTGCardInstance *)target; - _target->regenerate(); - PutInGraveyard * action = ((PutInGraveyard *) game->mLayers->stackLayer()->getNext(NULL,ACTION_PUTINGRAVEYARD,NOT_RESOLVED)); - while(action){ -#if defined (WIN32) || defined (LINUX) - OutputDebugString("Fizzling due to regenerate! \n"); -#endif - if (action->card == _target){ - game->mLayers->stackLayer()->Fizzle(action); - } - action = ((PutInGraveyard *) game->mLayers->stackLayer()->getNext(action,ACTION_PUTINGRAVEYARD,NOT_RESOLVED)); - } - return 1; - } - -}; - -/*Gives protection to a target */ -class AProtectionFrom:public MTGAbility{ - public: - CardDescriptor * cd; - void initProtection(){ - ((MTGCardInstance *)target)->addProtection(cd); - } - - AProtectionFrom(int _id, MTGCardInstance * _source, MTGCardInstance * _target, CardDescriptor * _cd):MTGAbility(_id, _source, _target),cd(_cd){ - initProtection(); - } - AProtectionFrom(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int color):MTGAbility(_id, _source, _target){ - cd = NEW CardDescriptor(); - cd->colors[color] = 1; - initProtection(); - } - - int destroy(){ - ((MTGCardInstance *)target)->removeProtection(cd); - return 1; - } - -}; - -//Aura Enchantments that provide controller of target life or damages at a given phase of their turn -class ARegularLifeModifierAura:public MTGAbility{ - public: - int life; - int phase; - int onlyIfTargetTapped; - ARegularLifeModifierAura(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _phase, int _life, int _onlyIfTargetTapped=0):MTGAbility(id,_source,_target),life(_life), phase(_phase),onlyIfTargetTapped(_onlyIfTargetTapped){ - } - - void Update(float dt){ - if (newPhase !=currentPhase && newPhase==phase && game->currentPlayer==((MTGCardInstance *)target)->controller()){ - if (!onlyIfTargetTapped || ((MTGCardInstance *)target)->tapped){ - if (life > 0){ - game->currentPlayer->life+=life; - }else{ - game->mLayers->stackLayer()->addDamage(source, game->currentPlayer, -life); - } - } - } - } -}; - - -//ExaltedAbility (Shards of Alara) -class AExalted:public ListMaintainerAbility{ - public: - int power, toughness; - MTGCardInstance * luckyWinner; - AExalted(int _id, MTGCardInstance * _source, int _power = 1, int _toughness = 1):ListMaintainerAbility(_id, _source),power(_power),toughness(_toughness){ - luckyWinner = NULL; - } - - - int canBeInList(MTGCardInstance * card){ - if (card->isAttacker() && game->currentPlayer == source->controller()) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - if(cards.size() == 1){ - luckyWinner = cards.begin()->first; - luckyWinner->addToToughness(toughness); - luckyWinner->power+=power; - }else if (cards.size() == 2){ - luckyWinner->addToToughness(-toughness); - luckyWinner->power-=power; - } - return 1; - } - - int removed(MTGCardInstance * card){ - if(cards.size() == 1){ - luckyWinner = cards.begin()->first; - luckyWinner->addToToughness(toughness); - luckyWinner->power+=power; - }else if (cards.size() == 0){ - luckyWinner->addToToughness(-toughness); - luckyWinner->power-=power; - } - return 1; - } - -}; - - -//ExaltedAbility for basic abilities (Shards of Alara) -class AExaltedAbility:public ListMaintainerAbility{ - public: - int ability; - MTGCardInstance * luckyWinner; - AExaltedAbility(int _id, MTGCardInstance * _source, int _ability):ListMaintainerAbility(_id, _source),ability(_ability){ - luckyWinner = NULL; - } - - - int canBeInList(MTGCardInstance * card){ - if (card->isAttacker() && game->currentPlayer == source->controller()) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - luckyWinner = cards.begin()->first; - if(cards.size() == 1){ - luckyWinner->basicAbilities[ability]+=1; - }else if (cards.size() == 2){ - luckyWinner->basicAbilities[ability]-=1; - } - return 1; - } - - int removed(MTGCardInstance * card){ - if(cards.size() == 1){ - luckyWinner->basicAbilities[ability]+=1; - }else if (cards.size() == 0){ - luckyWinner->basicAbilities[ability]-=1; - } - return 1; - } - -}; - - -//Converts lands to creatures (Kormus bell, Living lands) -class AConvertLandToCreatures:public ListMaintainerAbility{ - public: - int type; - int power, toughness; - AConvertLandToCreatures(int _id, MTGCardInstance * _source, const char * _type, int _power = 1, int _toughness = 1):ListMaintainerAbility(_id, _source),power(_power),toughness(_toughness){ - type = Subtypes::subtypesList->Add(_type); - } - - - int canBeInList(MTGCardInstance * card){ - if (card->hasType(type)) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - card->power = 1; - card->setToughness(1); - card->setSubtype("creature"); - return 1; - } - - int removed(MTGCardInstance * card){ - card->removeType("creature"); - return 1; - } - -}; - -//Lords (Merfolk lord...) give power and toughness to OTHER creatures of their type, they can give them special abilities, regeneration -class ALord:public ListMaintainerAbility{ - public: - string type; - int power, toughness; - int ability; - ManaCost * regenCost; - map regenerations; - ALord(int _id, MTGCardInstance * card, const char * _type, int _power = 0 , int _toughness = 0, int _ability = -1, ManaCost * _regenCost = NULL):ListMaintainerAbility(_id,card){ - type = _type; - power = _power; - toughness = _toughness; - ability = _ability; - regenCost = _regenCost; - } - - int canBeInList(MTGCardInstance * card){ - if (card!=source && card->isACreature() && card->hasSubtype(type)) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - card->power += power; - card->addToToughness(toughness); - if (ability != -1) card->basicAbilities[ability] +=1; - if (regenCost){ - AStandardRegenerate * regen = NEW AStandardRegenerate(0, card, card, regenCost); - regenerations[card] = regen; - game->addObserver(regen); - } - return 1; - } - - int removed(MTGCardInstance * card){ - card->power -= power; - card->addToToughness(-toughness); - if (ability != -1 && card->basicAbilities[ability]) card->basicAbilities[ability] -=1; - if (regenCost){ - if(regenerations.find(card) != regenerations.end()){ - if (game->isInPlay(card)) game->removeObserver(regenerations[card]); - regenerations.erase(card); - } - } - return 1; - } - -}; - -//Lords (Merfolk lord...) give power and toughness to OTHER creatures of a given color, they can give them special abilities, regeneration -class AColorLord:public ListMaintainerAbility{ - public: - int color; - int notcolor; - int power, toughness; - int ability; - ManaCost * regenCost; - map regenerations; - AColorLord(int _id, MTGCardInstance * card, int _color, int _notcolor = -1, int _power = 0 , int _toughness = 0, int _ability = -1, ManaCost * _regenCost = NULL):ListMaintainerAbility(_id,card){ - color = _color; - notcolor = _notcolor; - power = _power; - toughness = _toughness; - ability = _ability; - regenCost = _regenCost; - } - - int canBeInList(MTGCardInstance * card){ - if (notcolor > -1){ - if (card!=source && card->isACreature() && !card->hasColor(color)) return 1; - }else{ - if (card!=source && card->isACreature() && card->hasColor(color)) return 1; - } - return 0; - } - - int added(MTGCardInstance * card){ - card->power += power; - card->addToToughness(toughness); - if (ability != -1) card->basicAbilities[ability] +=1; - if (regenCost){ - AStandardRegenerate * regen = NEW AStandardRegenerate(0, card, card, regenCost); - regenerations[card] = regen; - game->addObserver(regen); - } - return 1; - } - - int removed(MTGCardInstance * card){ - card->power -= power; - card->addToToughness(-toughness); - if (ability != -1 && card->basicAbilities[ability]) card->basicAbilities[ability] -=1; - if (regenCost){ - if(regenerations.find(card) != regenerations.end()){ - game->removeObserver(regenerations[card]); - regenerations.erase(card); - } - } - return 1; - } - -}; - - -/* Standard Damager, can choose a NEW target each time the price is paid */ -class ADamager:public TargetAbility{ - public: - int damage; - ADamager(int id, MTGCardInstance * card, ManaCost * _cost, int _damage, TargetChooser * _tc = NULL, int _tap = 1):TargetAbility(id,card, _tc, _cost,0,_tap),damage(_damage){ - if (!tc) tc = NEW DamageableTargetChooser(card); - } - int resolve(){ - Damageable * _target = tc->getNextDamageableTarget(); - GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,_target, damage); - return 1; - } - - -}; - -/* Can tap a target for a cost */ -class ATapper:public TargetAbility{ - public: - int damage; - ATapper(int id, MTGCardInstance * card, ManaCost * _cost, TargetChooser * _chooser):TargetAbility(id,card, _chooser, _cost){ - } - - int resolve(){ - MTGCardInstance * _target = tc->getNextCardTarget(); - if (_target){ - _target->tapped = true; - } - return 1; - } - -}; - -// Add life of gives damage if a given zone has more or less than [condition] cards at the beginning of [phase] -//Ex : the rack, ivory tower... -class ALifeZoneLink:public MTGAbility{ - public: - int phase; - int condition; - int life; - int controller; - int nbcards; - MTGGameZone * zone; - ALifeZoneLink(int _id ,MTGCardInstance * card, int _phase, int _condition, int _life = -1, int _controller = 0, MTGGameZone * _zone = NULL):MTGAbility(_id, card){ - phase = _phase; - condition = _condition; - controller = _controller; - life = _life; - zone = _zone; - if (zone == NULL){ - if (controller){ - zone = game->currentPlayer->game->hand; - }else{ - zone = game->opponent()->game->hand; - } - } - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == phase){ - if ((controller && game->currentPlayer == source->controller()) ||(!controller && game->currentPlayer != source->controller()) ){ - if ((condition < 0 && zone->nb_cards < - condition) ||(condition >0 && zone->nb_cards > condition)){ - int diff = zone->nb_cards - condition; - if (condition < 0) diff = - condition - zone->nb_cards; - if (life > 0){ - game->currentPlayer->life+=life*diff; - }else{ - game->mLayers->stackLayer()->addDamage(source,game->currentPlayer,-life*diff); - } - } - } - } - } -}; - -//Creatures that cannot attack if opponent has not a given type of land, and die if controller has not this type of land -//Ex : pirate ship... -class AStrongLandLinkCreature: public MTGAbility{ - public: - char land[20]; - AStrongLandLinkCreature(int _id, MTGCardInstance * _source, const char * _land):MTGAbility(_id, _source){ - sprintf(land,"%s",_land); - } - - void Update(float dt){ - if (source->isAttacker()){ - if (!game->opponent()->game->inPlay->hasType(land)){ - source->attacker=0; - source->tapped = 0; - //TODO Improve, there can be race conditions here - } - } - Player * player = source->controller(); - if(!player->game->inPlay->hasType(land)){ - player->game->putInGraveyard(source); - } - } -}; - -//Steal control of a target -class AControlStealAura: public MTGAbility{ - public: - Player * originalController; - AControlStealAura(int _id , MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source, _target){ - originalController = _target->controller(); - _target->changeController(game->currentlyActing()); - } - - int destroy(){ - MTGCardInstance * _target = (MTGCardInstance *) target; - if (_target->controller()->game->inPlay->hasCard(_target)){ //if the target is still in game -> spell was destroyed - _target->changeController(originalController); - } - return 1; - } - //TODO put it back into owners's graveyard if needed... -}; - -//Ability to untap a target -class AUntaper:public TargetAbility{ - public: - AUntaper(int _id, MTGCardInstance * card, ManaCost * _manacost, TargetChooser * _tc):TargetAbility(_id,card,_tc,_manacost){ - } - - int resolve(){ - tc->getNextCardTarget()->tapped = 0; - return 1; - } - -}; - - -//Same as StealControl Aura ???? Obsolete ? -class ATakeControlAura:public MTGAbility{ - public: - Player * previousController; - ATakeControlAura(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source,_target){ - previousController = _target->controller(); - previousController->game->putInZone(_target, previousController->game->inPlay, source->controller()->game->inPlay); - - } - - int destroy(){ - MTGCardInstance * _target = (MTGCardInstance *) target; - if (_target->controller()->game->inPlay->hasCard(_target)){ - _target->controller()->game->putInZone(_target, _target->controller()->game->inPlay, previousController->game->inPlay); - } - return 1; - } - -}; - -//Creatures that kill their blockers -//Ex : Cockatrice -class AOldSchoolDeathtouch:public MTGAbility{ - public: - MTGCardInstance * opponents[20]; - int nbOpponents; - AOldSchoolDeathtouch(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ - nbOpponents = 0; - } - - void Update(float dt){ - if (newPhase != currentPhase){ - if( newPhase == MTG_PHASE_COMBATDAMAGE){ - nbOpponents = 0; - MTGCardInstance * opponent = source->getNextOpponent(); - while (opponent && !opponent->hasSubtype("wall")){ - opponents[nbOpponents] = opponent; - nbOpponents ++; - opponent = source->getNextOpponent(opponent); - } - }else if (newPhase == MTG_PHASE_COMBATEND){ - for (int i = 0; i < nbOpponents ; i++){ - game->mLayers->stackLayer()->addPutInGraveyard(opponents[i]); - } - } - } - } - - int testDestroy(){ - if(!game->isInPlay(source) && currentPhase != MTG_PHASE_UNTAP){ - return 0; - }else{ - return MTGAbility::testDestroy(); - } - } -}; - - -//Converts a card to a creature (Aura) -class AConvertToCreatureAura:public MTGAbility{ - public: - AConvertToCreatureAura(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness):MTGAbility(_id, _source, _target){ - _target->setSubtype("creature"); - _target->power = _power; - _target->toughness = _toughness; - _target->life = _toughness; - //_target->afterDamage(); - _target->doDamageTest = 1; - } - - int destroy(){ - MTGCardInstance * _target = (MTGCardInstance *) target; - _target->removeType("creature"); - return 1; - } -}; - -/* - Specific Classes -*/ - -// 1092 Specific to Aladdin's Lamp -class AAladdinsLamp: public TargetAbility{ - public: - CardDisplay cd; - int nbcards; - int init; - AAladdinsLamp(int _id, MTGCardInstance * card):TargetAbility(_id,card){ - cost = NEW ManaCost(); - cost->x(); - cd = CardDisplay(1,game,SCREEN_WIDTH/2, SCREEN_HEIGHT/2,NULL); - MTGGameZone * zones[] = {game->currentPlayer->game->library}; - tc = NEW TargetZoneChooser(zones,1,source); - nbcards = 0; - init = 0; - } - - void Update(float dt){ - if (waitingForAnswer){ - if (!init){ - cd.resetObjects(); - int wished = game->currentlyActing()->getManaPool()->getConvertedCost(); - game->currentlyActing()->getManaPool()->pay(cost); - nbcards = 0; - MTGGameZone * library = game->currentlyActing()->game->library; - while (nbcards < wished && nbcards < library->nb_cards){ - cd.AddCard(library->cards[library->nb_cards - 1 - nbcards]); - nbcards++; - } - init = 1; - } - cd.Update(dt); - cd.CheckUserInput(dt); - } - } - - void Render(float dt){ - if (waitingForAnswer){ - cd.Render(); - } - } - - - int fireAbility(){ - source->tapped = 1; - MTGLibrary * library = game->currentlyActing()->game->library; - library->removeCard(tc->getNextCardTarget()); - library->shuffleTopToBottom(nbcards - 1 ); - library->addCard(tc->getNextCardTarget()); - init = 0; - return 1; - } - - int resolve(){return 1;}; - - -}; - - - - -//Ankh of Mishra -class AAnkhOfMishra: public MTGAbility{ - public: - int playerLands[2]; - AAnkhOfMishra(int id, MTGCardInstance * _source):MTGAbility(id, _source){ - for (int i=0; i< 2; i++){ - playerLands[i] = GameObserver::GetInstance()->players[i]->game->inPlay->countByType("land"); - } - } - - void Update(float dt){ - for (int i=0; i < 2; i++){ - int lands = GameObserver::GetInstance()->players[i]->game->inPlay->countByType("land"); - while (lands > playerLands[i]){ - GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,GameObserver::GetInstance()->players[i], 2); - playerLands[i]++; - } - } - } -}; - - - -// Armageddon Clock -class AArmageddonClock:public MTGAbility{ - public: - int counters; - ManaCost cost; - AArmageddonClock(int id, MTGCardInstance * _source):MTGAbility(id, _source){ - counters = 0; - int _cost[] = {MTG_COLOR_ARTIFACT, 4}; - cost = ManaCost(_cost,1); - } - - void Update(float dt){ - if (newPhase != currentPhase){ - if (newPhase == MTG_PHASE_UPKEEP && game->currentPlayer->game->inPlay->hasCard(source)){ - counters ++; - }else if (newPhase == MTG_PHASE_DRAW && counters > 0 && game->currentPlayer->game->inPlay->hasCard(source)){ //End of upkeep = beginning of draw - GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,GameObserver::GetInstance()->players[0], counters); - GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,GameObserver::GetInstance()->players[1], counters); - } - } - } - int isReactingToClick(MTGCardInstance * _card){ - if (counters > 0 && _card == source && currentPhase == MTG_PHASE_UPKEEP){ - if (game->currentlyActing()->getManaPool()->canAfford( & cost)){ - return 1; - } - } - return 0; - } - - int reactToClick(MTGCardInstance * _card){ - if (!isReactingToClick( _card)) return 0; - game->currentlyActing()->getManaPool()->pay(& cost); - counters --; - return 1; - } -}; - - -//Black Vise -class ABlackVise: public MTGAbility{ - public: - int nbcards; - ABlackVise(int id, MTGCardInstance * _source):MTGAbility(id, _source){ - nbcards = game->opponent()->game->hand->nb_cards; - } - - void Update(float dt){ - if (newPhase == MTG_PHASE_UPKEEP && GameObserver::GetInstance()->opponent()->game->inPlay->hasCard(source)){ - nbcards = game->currentPlayer->game->hand->nb_cards; - } - if (newPhase != currentPhase && newPhase == MTG_PHASE_DRAW && GameObserver::GetInstance()->opponent()->game->inPlay->hasCard(source)){ - if ( nbcards > 4) game->mLayers->stackLayer()->addDamage(source,game->currentPlayer, nbcards - 4); - } - } -}; - - -//Channel -class AChannel:public ActivatedAbility{ - public: - - AChannel(int _id, MTGCardInstance * card):ActivatedAbility(_id, card,0,0,0){ - } - - int isReactingToClick(PlayGuiObject * object){ - if (object->type == GUI_AVATAR){ - Player * player = ((GuiAvatar *)object)->player; - if (player == source->controller()) return 1; - } - return 0; - } - - int resolve(){ - source->controller()->life--; - source->controller()->getManaPool()->add(MTG_COLOR_ARTIFACT, 1); - return 1; - } - - int testDestroy(){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP) return 1; - currentPhase = newPhase; - return 0; - } -}; - - -// Clockwork Beast -class AClockworkBeast:public MTGAbility{ - public: - int counters; - ManaCost cost; - AClockworkBeast(int id, MTGCardInstance * _source):MTGAbility(id, _source){ - counters = 7; - ((MTGCardInstance *)target)->power+=7; - int _cost[] = {MTG_COLOR_ARTIFACT, 1}; - cost = ManaCost(_cost,1); - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_COMBATEND){ - if (((MTGCardInstance *)source)->isAttacker() || ((MTGCardInstance *)source)->isDefenser()){ - counters--; - ((MTGCardInstance *)target)->power-=1; - } - } - } - int isReactingToClick(MTGCardInstance * _card){ - if (counters < 7 && _card == source && currentPhase == MTG_PHASE_UPKEEP && game->currentPlayer->game->inPlay->hasCard(source)){ - if (game->currentlyActing()->getManaPool()->canAfford( & cost)){ - return 1; - } - } - return 0; - } - - int reactToClick(MTGCardInstance * _card){ - if (!isReactingToClick( _card)) return 0; - game->currentlyActing()->getManaPool()->pay(& cost); - counters ++; - ((MTGCardInstance *)target)->power++; - ((MTGCardInstance *)target)->tapped = 1; - return 1; - } -}; - -//1102: Conservator -class AConservator: public MTGAbility{ - public: - int canprevent; - ManaCost cost; - AConservator(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ - canprevent = 0; - int _cost[] = {MTG_COLOR_ARTIFACT, 2}; - cost = ManaCost(_cost, 1); - } - - int alterDamage(Damage * damage){ - if (canprevent && damage->target == source->controller()){ - if (damage->damage >= canprevent){ - damage->damage-=canprevent; - canprevent = 0; - }else{ - canprevent-=damage->damage; - damage->damage = 0; - } - } - return 1; - } - int alterDamage(){ - if (canprevent){ - ActionStack * stack = game->mLayers->stackLayer(); - for (int i = stack->mCount-1; i>=0; i--){ - if (!canprevent) return 1; - Interruptible * current = ((Interruptible *)stack->mObjects[i]); - if (current->type == ACTION_DAMAGE && current->state==NOT_RESOLVED){ - Damage * damage = (Damage *)current; - alterDamage(damage); - }else if (current->type == ACTION_DAMAGES && current->state == NOT_RESOLVED){ - DamageStack * damages = (DamageStack *)current; - for (int j = damages->mCount-1;j >=0; j--){ - alterDamage(((Damage *)damages->mObjects[j])); - } - } - } - } - return 1; - } - - void Update(float dt){ - alterDamage(); - } - - int isReactingToClick(MTGCardInstance * _card){ - if ( _card == source && game->currentlyActing()->game->inPlay->hasCard(source) && !_card->isTapped()){ - if (game->currentlyActing()->getManaPool()->canAfford( & cost)){ - return 1; - } - } - return 0; - } - - int reactToClick(MTGCardInstance * _card){ - if (!isReactingToClick( _card)) return 0; - game->currentlyActing()->getManaPool()->pay(& cost); - source->tapped = 1; - canprevent = 2; - alterDamage(); - return 1; - } - -}; - - -//Creature bond -class ACreatureBond:public TriggeredAbility{ - public: - int resolved; - ACreatureBond(int _id, MTGCardInstance * _source, MTGCardInstance * _target):TriggeredAbility(_id,_source,_target){ - resolved = 1; - } - - int trigger(){ - MTGCardInstance * _target = (MTGCardInstance *) target; - for (int i = 0; i < 2; i++){ - if (game->players[i]->game->graveyard->hasCard(_target)) return 1; - } - return 0; - } - - int resolve(){ - MTGCardInstance * _target = (MTGCardInstance *) target; - game->mLayers->stackLayer()->addDamage(source,_target->controller(),_target->toughness); - resolved = 1; - return 1; - } - - int testDestroy(){ - MTGCardInstance * _target = (MTGCardInstance *)target; - if(_target->controller()->game->graveyard->hasCard(_target) && !resolved){ - return 0; - }else{ - return TriggeredAbility::testDestroy(); - } - } -}; - -//1105: Dingus Egg -class ADingusEgg: public MTGAbility{ - public: - int playerLands[2]; - ADingusEgg(int id, MTGCardInstance * _source):MTGAbility(id, _source){ - for (int i=0; i< 2; i++){ - playerLands[i] = GameObserver::GetInstance()->players[i]->game->inPlay->countByType("land"); - } - } - - void Update(float dt){ - for (int i=0; i < 2; i++){ - int lands = GameObserver::GetInstance()->players[i]->game->inPlay->countByType("land"); - while (lands < playerLands[i]){ - GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,GameObserver::GetInstance()->players[i], 2); - playerLands[i]--; - } - } - } -}; - - - -//1106 DisruptingScepter -class ADisruptingScepter:public TargetAbility{ - public: - ADisruptingScepter(int id, MTGCardInstance * _source):TargetAbility(id,_source){ - MTGGameZone * zones[] = {GameObserver::GetInstance()->opponent()->game->hand}; - tc = NEW TargetZoneChooser(zones,1,_source); - int _cost[] = {MTG_COLOR_ARTIFACT, 3}; - cost = NEW ManaCost(_cost,1); - } - - void Update(float dt){ - if (game->opponent()->isAI()){ - if(waitingForAnswer){ - MTGCardInstance * card = ((AIPlayer *)game->opponent())->chooseCard(tc, source); - if (card) tc->toggleTarget(card); - if (!card || tc->targetsReadyCheck() == TARGET_OK) waitingForAnswer = 0; - } - TargetAbility::Update(dt); - }else{ - TargetAbility::Update(dt); - } - } - - int resolve(){ - game->opponent()->game->putInGraveyard(tc->getNextCardTarget()); - return 1; - } - - -}; - - -//1108 Ebony Horse -class AEbonyHorse:public TargetAbility{ - public: - - AEbonyHorse(int _id, MTGCardInstance * _source):TargetAbility(_id,_source, NEW CreatureTargetChooser()){ - int _cost[] = {MTG_COLOR_ARTIFACT, 2}; - cost = NEW ManaCost(_cost,1); - } - - int resolve(){ - tc->getNextCardTarget()->attacker = 0; - return 1; - } - -}; - -//1345 Farmstead -class AFarmstead:public ActivatedAbility{ - public: - AFarmstead(int _id, MTGCardInstance * source, MTGCardInstance * _target):ActivatedAbility(_id, source,0,1,0){ - int _cost[] = {MTG_COLOR_WHITE, 2}; - cost = NEW ManaCost(_cost,1); - target = _target; - } - - int isReactingToClick(MTGCardInstance * card){ - if (!ActivatedAbility::isReactingToClick(card)) return 0; - if (currentPhase == MTG_PHASE_UPKEEP) return 1; - return 0; - } - - int resolve(){ - source->controller()->life++; - return 1; - } - -}; - -//1110 Glasses of Urza -class AGlassesOfUrza:public MTGAbility{ - public: - CardDisplay * display; - AGlassesOfUrza(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ - display = NEW CardDisplay(0, game,SCREEN_WIDTH/2, SCREEN_HEIGHT/2,NULL); - } - - void Update(float dt){ - if(modal){ - display->Update(dt); - } - } - - void CheckUserInput(float dt){ - if (modal){ - display->CheckUserInput(dt); - JGE * mEngine = JGE::GetInstance(); - if (mEngine->GetButtonClick(PSP_CTRL_CROSS)){ - modal = 0; - } - } - } - - void Render(float dt){ - if (modal){ - display->Render(); - } - - } - int isReactingToClick(MTGCardInstance * card){ - if ( card == source){ - if (game->currentlyActing()->game->isInPlay(card) && !source->isTapped()){ - return 1; - } - } - return 0; - } - - int reactToClick(MTGCardInstance * card){ - if (!isReactingToClick(card)) return 0; - source->tapped = 1; - modal = 1; - return 1; - } - -}; - -//1112 Howling Mine -class AHowlingMine:public MTGAbility{ - public: - AHowlingMine(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){} - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_DRAW && !source->tapped){ - game->mLayers->stackLayer()->addDraw(game->currentPlayer); - } - } -}; - -//1119 Jayemdae Tome -class AJayemdaeTome:public ActivatedAbility{ - public: - AJayemdaeTome(int _id, MTGCardInstance * card):ActivatedAbility(_id, card){ - int _cost[] = {MTG_COLOR_ARTIFACT, 4}; - cost = NEW ManaCost(_cost,1); - } - - int resolve(){ - game->mLayers->stackLayer()->addDraw(source->controller()); - return 1; - } -}; - - -//Living Artifact -class ALivingArtifact:public MTGAbility{ - public: - int usedThisTurn; - int counters; - Damage * latest; - ALivingArtifact(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id,_source,_target){ - usedThisTurn = 0; - counters = 0; - latest = NULL; - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP) usedThisTurn = 0; - Damage * damage = ((Damage *)game->mLayers->stackLayer()->getNext(latest,ACTION_DAMAGE,RESOLVED_OK)); - while (damage){ - if (damage->target == source->controller()){ - counters += damage->damage; - } - latest = damage; - damage = ((Damage *)game->mLayers->stackLayer()->getNext(damage,ACTION_DAMAGE,RESOLVED_OK)); - } - } - - int isReactingtoclick(MTGCardInstance * card){ - if (currentPhase == MTG_PHASE_UPKEEP && card == source && game->currentPlayer == source->controller() && counters && !usedThisTurn){ - return 1; - } - return 0; - } - - int reactToClick(MTGCardInstance * card){ - source->controller()->life+=1; - counters--; - usedThisTurn = 1; - return 1; - } - -}; - -//Lord of the Pit -class ALordOfThePit: public TargetAbility{ - public: - int paidThisTurn; - ALordOfThePit(int _id, MTGCardInstance * source):TargetAbility(_id, source, NEW CreatureTargetChooser(),0,1,0){ - paidThisTurn = 1; - } - - void Update(float dt){ - if (newPhase != currentPhase && source->controller() == game->currentPlayer){ - if (newPhase == MTG_PHASE_UNTAP){ - paidThisTurn = 0; - }else if( newPhase == MTG_PHASE_UPKEEP + 1 && !paidThisTurn){ - game->mLayers->stackLayer()->addDamage(source,source->controller(), 7); - } - } - TargetAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card){ - if (currentPhase != MTG_PHASE_UPKEEP || paidThisTurn) return 0; - return TargetAbility::isReactingToClick(card); - } - - int resolve(){ - MTGCardInstance * card = tc->getNextCardTarget(); - if (card && card != source && card->controller() == source->controller()){ - card->controller()->game->putInGraveyard(card); - paidThisTurn = 1; - return 1; - } - return 0; - } - -}; -//1143 Animate Dead -class AAnimateDead:public MTGAbility{ - public: - AAnimateDead(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source, _target){ - MTGCardInstance * card = _target; - card->power--; - card->life = card->toughness; - //Put the card in play again, with all its abilities ! - //AbilityFactory af; - Spell * spell = NEW Spell(card); - //af.addAbilities(game->mLayers->actionLayer()->getMaxId(), spell); - source->controller()->game->putInZone(card, _target->controller()->game->graveyard, source->controller()->game->stack); - spell->resolve(); - delete spell; - } - - int destroy(){ - MTGCardInstance * card = (MTGCardInstance *) target; - card->power++; - return 1; - } -}; - -//1144 Bad Moon, 1341 Crusade -class ABadMoon:public ListMaintainerAbility{ - public: - int color; - ABadMoon(int _id, MTGCardInstance * _source, int _color = MTG_COLOR_BLACK):ListMaintainerAbility(_id, _source),color(_color){ - } - - int canBeInList(MTGCardInstance * card){ - if (card->isACreature() && card->hasColor(color)) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - card->power += 1; - card->addToToughness(1); - return 1; - } - - int removed(MTGCardInstance * card){ - card->power -= 1; - card->addToToughness(-1); - return 1; - } - -}; - - -//1159 Erg Raiders -class AErgRaiders:public MTGAbility{ - public: - int init; - int dealDamage; - AErgRaiders(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ - init = 0; - dealDamage = 0; - } - - void Update(float dt){ - if (newPhase != currentPhase){ - Player * controller = source->controller(); - if (newPhase == MTG_PHASE_COMBATDAMAGE && game->currentPlayer == controller){ - if (!source->isAttacker() && init){ - dealDamage = 1; - } - }else if (newPhase == MTG_PHASE_UNTAP && game->currentPlayer != controller){ - if (dealDamage){ - game->mLayers->stackLayer()->addDamage(source, controller,2); - } - init = 1; - dealDamage = 0; - } - } - - } -}; - -//Fastbond -class AFastbond:public TriggeredAbility{ - public: - int alreadyPlayedALand; - AFastbond(int _id, MTGCardInstance * card):TriggeredAbility(_id, card){ - alreadyPlayedALand = 0; - } - - void Update(float dt){ - if (newPhase!=currentPhase && newPhase == MTG_PHASE_UNTAP){ - alreadyPlayedALand = 0; - } - TriggeredAbility::Update(dt); - } - - int trigger(){ - if(source->controller()->canPutLandsIntoPlay==0) return 1; - return 0; - } - - int resolve(){ - source->controller()->canPutLandsIntoPlay = 1; - if (alreadyPlayedALand){ - game->mLayers->stackLayer()->addDamage(source, source->controller(), 1); - } - alreadyPlayedALand = 1; - return 1; - } -}; - - - -//1165 Hypnotic Specter -class AHypnoticSpecter:public MTGAbility{ - public: - int nbdamagesthisturn[2]; - AHypnoticSpecter(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ - currentPhase = -1; - for (int i = 0; i < 2; i++){ - nbdamagesthisturn[i] = 0; - } - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ - for (int i = 0; i < 2; i++){ - nbdamagesthisturn[i] = 0; - } - } - - ActionStack * as = game->mLayers->stackLayer(); - int nbdamages[2]; - for (int i = 0; i < 2; i++){ - nbdamages[i] = 0; - } - - Damage * current = ((Damage *)as->getNext(NULL,ACTION_DAMAGE,RESOLVED_OK)); - while(current){ - if (current->source == source){ - for (int j=0; j < 2; j++){ - if(current->target == game->players[j]) nbdamages[j]++; - } - } - current = ((Damage *)as->getNext(current,ACTION_DAMAGE,RESOLVED_OK)); - - } - - for (int i = 0; i < 2; i++){ - while(nbdamages[i] > nbdamagesthisturn[i]){ - nbdamagesthisturn[i]++; - game->players[i]->game->discardRandom(game->players[i]->game->hand); - } - } - - - } - -}; - -//1117 Jandor's Ring -class AJandorsRing:public ActivatedAbility{ - public: - AJandorsRing(int _id, MTGCardInstance * _source):ActivatedAbility(_id,_source, NEW ManaCost()){ - cost->add(MTG_COLOR_ARTIFACT, 2); - } - - int isReactingToClick(MTGCardInstance * card){ - if (!source->controller()->game->hand->hasCard(source->controller()->game->library->lastCardDrawn)) return 0; - return ActivatedAbility::isReactingToClick(card); - } - - int resolve(){ - source->controller()->game->putInGraveyard(source->controller()->game->library->lastCardDrawn); - game->mLayers->stackLayer()->addDraw(source->controller()); - return 1; - } - -}; - - -//Kudzu. -//What happens when there are no targets ??? -class AKudzu: public TargetAbility{ - public: - int previouslyTapped; - AKudzu(int _id, MTGCardInstance * card, MTGCardInstance * _target):TargetAbility(_id,card, NEW TypeTargetChooser("land",card)){ - tc->toggleTarget(_target); - target = _target; - previouslyTapped = 0; - if (_target->tapped) previouslyTapped = 1; - } - - - void Update(float dt){ - MTGCardInstance * _target = (MTGCardInstance *)target; - if (!_target->tapped){ - previouslyTapped = 0; - }else if (!previouslyTapped){ -#if defined (WIN32) || defined (LINUX) - OutputDebugString("Kudzu Strikes !\n"); -#endif - MTGCardInstance * _target = (MTGCardInstance *)target; - _target->controller()->game->putInGraveyard(_target); - reactToClick(source); // ???? - } - TargetAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card){ - MTGCardInstance * _target = (MTGCardInstance *)target; - if (card == source && (!_target || !_target->isInPlay())){ -#if defined (WIN32) || defined (LINUX) - OutputDebugString("Kudzu Reacts to click !\n"); -#endif - return 1; - } - return 0; - } - - /* - int reactToClick(MTGCardInstance * card){ - if (!waitingForAnswer) { - }else{ - tc->toggleTarget(card); - } - return 1; - } - */ - - int resolve(){ - target = tc->getNextCardTarget(); - source->target = (MTGCardInstance *) target; - previouslyTapped = 0; - if (source->target->tapped) previouslyTapped = 1; - return 1; - } - - int testDestroy(){ - GameObserver * g = GameObserver::GetInstance(); - int stillLandsInPlay = 0; - for (int i = 0; i < 2; i++){ - if (game->players[i]->game->inPlay->hasType("land")) stillLandsInPlay = 1; - } - if (!stillLandsInPlay){ - source->controller()->game->putInGraveyard(source); - return 1; - } - - if (!game->isInPlay(source)){ - return 1; - } - - return 0; - } - - -}; - -//Millstone -class AMillstone:public TargetAbility{ - public: - AMillstone(int _id, MTGCardInstance * card):TargetAbility(_id,card, NEW PlayerTargetChooser(), NEW ManaCost()){ - cost->add(MTG_COLOR_ARTIFACT, 2); - } - - int resolve(){ - Player * player = tc->getNextPlayerTarget(); - if (!player) return 0; - MTGLibrary * library = player->game->library; - for (int i = 0; i < 2; i++){ - if (library->nb_cards) - player->game->putInZone(library->cards[library->nb_cards-1],library, player->game->graveyard); - } - return 1; - } - -}; - -//1170: Nightmare -class ANightmare:public ListMaintainerAbility{ - public: - ANightmare(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ - } - - int canBeInList(MTGCardInstance * card){ - if (source->controller()->game->inPlay->hasCard(card) && card->hasType("swamp") ) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - source->power += 1; - source->addToToughness(1); - return 1; - } - - int removed(MTGCardInstance * card){ - source->power -= 1; - source->addToToughness(-1); - return 1; - } - -}; - - - -//1172 Pestilence -class APestilence: public ActivatedAbility{ - public: - APestilence(int _id, MTGCardInstance * card):ActivatedAbility(_id, card, NEW ManaCost(), 0,0){ - cost->add(MTG_COLOR_BLACK, 1); - } - - void Update(float dt){ - if (newPhase !=currentPhase && newPhase == MTG_PHASE_EOT){ - if (!game->players[0]->game->inPlay->hasType("creature") && !game->players[1]->game->inPlay->hasType("creature")){ - source->controller()->game->putInGraveyard(source); - } - } - } - - int resolve(){ - for (int i = 0; i < 2 ; i++){ - MTGInPlay * inplay = game->players[i]->game->inPlay; - for (int j = inplay->nb_cards - 1 ; j >=0; j--){ - if (inplay->cards[j]->isACreature()) game->mLayers->stackLayer()->addDamage(source,inplay->cards[j],1); - } - game->mLayers->stackLayer()->addDamage(source,game->players[i],1); - } - return 1; - } - -}; - -//Plague Rats and similar. Power and toughness equal to number of cards that share a name -class APlagueRats:public ListMaintainerAbility{ - public: - string name; - APlagueRats(int _id, MTGCardInstance * _source, const char * _name):ListMaintainerAbility(_id,_source){ - name = _name; - std::transform(name.begin(), name.end(), name.begin(),::tolower ); - } - - int canBeInList(MTGCardInstance * card){ - if (card == source) return 0; - string compared = card->name; - std::transform( compared.begin(), compared.end(), compared.begin(),::tolower ); - if (name.compare(compared) == 0) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - source->power += 1; - source->addToToughness(1); - return 1; - } - - int removed(MTGCardInstance * card){ - source->power -= 1; - source->addToToughness(-1); - return 1; - } - -}; - -//Power Leak -class APowerLeak:public TriggeredAbility{ - public: - int damagesToDealThisTurn; - ManaCost cost; - APowerLeak(int _id, MTGCardInstance * _source, MTGCardInstance * _target):TriggeredAbility(_id, _source, _target){ - cost.add(MTG_COLOR_ARTIFACT, 1); - damagesToDealThisTurn = 0; - } - - void Update(float dt){ - MTGCardInstance * _target = (MTGCardInstance *) target; - if (newPhase != currentPhase && newPhase == MTG_PHASE_UPKEEP && _target->controller() == game->currentPlayer){ - damagesToDealThisTurn = 2; - } - TriggeredAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card){ - MTGCardInstance * _target = (MTGCardInstance *) target; - if (damagesToDealThisTurn && currentPhase == MTG_PHASE_UPKEEP && card==source && _target->controller() == game->currentPlayer){ - if (game->currentPlayer->getManaPool()->canAfford(& cost)) return 1; - } - return 0; - } - - int reactToclick(MTGCardInstance * card){ - game->currentPlayer->getManaPool()->pay( & cost); - damagesToDealThisTurn--; - return 1; - } - - int trigger(){ - MTGCardInstance * _target = (MTGCardInstance *) target; - if (newPhase != currentPhase && newPhase == MTG_PHASE_DRAW && _target->controller() == game->currentPlayer){ - if (damagesToDealThisTurn) return 1; - } - return 0; - } - - int resolve(){ - MTGCardInstance * _target = (MTGCardInstance *) target; - game->mLayers->stackLayer()->addDamage(source,_target->controller(), damagesToDealThisTurn); - return 1; - } -}; - -//Power Surge -class APowerSurge:public TriggeredAbility{ - public: - int totalLands; - APowerSurge(int _id, MTGCardInstance * _source):TriggeredAbility(_id,_source){ - totalLands = 0; - } - - int trigger(){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_EOT){ - //That's ugly but untapped land at the beginning of the turn are opponent's untapped lands at the end of the turn - totalLands = 0; - MTGInPlay * inPlay = game->opponent()->game->inPlay; - for (int i = 0; i < inPlay->nb_cards; i++){ - MTGCardInstance * card = inPlay->cards[i]; - if (!card->tapped && card->hasType("land")){ - totalLands++; - } - } - } - if (newPhase != currentPhase && newPhase == MTG_PHASE_UPKEEP && totalLands){ - return 1; - } - return 0; - } - - int resolve(){ - if (totalLands) game->mLayers->stackLayer()->addDamage(source,game->currentPlayer,totalLands); - totalLands = 0; - return 1; - } -}; - -//1175 Royal Assassin -class ARoyalAssassin:public TargetAbility{ - public: - - ARoyalAssassin(int _id, MTGCardInstance * _source):TargetAbility(_id,_source, NEW CreatureTargetChooser()){ - } - - int resolve(){ - MTGCardInstance * _target = tc->getNextCardTarget(); - if(_target && _target->tapped){ - _target->controller()->game->putInGraveyard(_target); - return 1; - } - return 0; - } - -}; - - -//1176 Sacrifice -class ASacrifice:public InstantAbility{ - public: - ASacrifice(int _id, MTGCardInstance * _source, MTGCardInstance * _target):InstantAbility(_id, _source){ - target = _target; - } - - int resolve(){ - MTGCardInstance * _target = (MTGCardInstance *) target; - if (_target->isInPlay()){ - game->currentlyActing()->game->putInGraveyard(_target); - int x = _target->getManaCost()->getConvertedCost(); - game->currentlyActing()->getManaPool()->add(MTG_COLOR_BLACK, x); - } - return 1; - } - -}; - -//1178 Scavenging Ghoul -class AScavengingGhoul:public MTGAbility{ - public: - int counters; - AScavengingGhoul(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source, _target){ - counters = 0; - } - - - void Update(float dt){ - //TODO - } - - int isReactingToClick(MTGCardInstance * _card){ - if (counters > 0 && _card == source && game->currentlyActing()->game->inPlay->hasCard(source)){ - return 1; - } - return 0; - } - - int reactToClick(MTGCardInstance * _card){ - if (!isReactingToClick( _card)) return 0; - counters--; - source->regenerate(); - return 1; - } - -}; - -//1218 Psychic Venom -class APsychicVenom:public MTGAbility{ - public: - int tapped; - APsychicVenom(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source,_target){ - tapped = _target->tapped; - } - - void Update(float dt){ - MTGCardInstance* _target = (MTGCardInstance* )target; - int newState = _target->isTapped(); - if (newState != tapped && newState == 1){ - game->mLayers->stackLayer()->addDamage(source,_target->controller(),2); - } - tapped = newState; - } -}; - - -//1221 Serendib Efreet -class ASerendibEfreet:public MTGAbility{ - public: - ASerendibEfreet(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ - } - - void Update(float dt){ - if (newPhase == MTG_PHASE_UPKEEP && newPhase != currentPhase && game->currentPlayer == source->controller()){ - game->mLayers->stackLayer()->addDamage(source,game->currentPlayer,1); - } - } -}; - - -//1235 Aspect of Wolf -class AAspectOfWolf:public ListMaintainerAbility{ - public: - int color; - AAspectOfWolf(int _id, MTGCardInstance * _source, MTGCardInstance * _target):ListMaintainerAbility(_id, _source, _target){ - } - - int canBeInList(MTGCardInstance * card){ - - if (card->controller() == source->controller() && card->hasType("forest")) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - MTGCardInstance * _target = (MTGCardInstance *) target; - int size = cards.size(); - if (size % 2 == 0){ - _target->power += 1; - }else{ - _target->addToToughness(1); - } - return 1; - } - - int removed(MTGCardInstance * card){ - MTGCardInstance * _target = (MTGCardInstance *) target; - int size = cards.size(); - if (size % 2 == 1){ - _target->power -= 1; - }else{ - _target->addToToughness(-1); - } - return 1; - } - -}; - -//1276 Wanderlust, 1148 Cursed Lands -class AWanderlust:public TriggeredAbility{ - public: - AWanderlust(int _id, MTGCardInstance * _source, MTGCardInstance * _target):TriggeredAbility(_id,_source, _target){} - - int trigger(){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_UPKEEP && ((MTGCardInstance *) target)->controller()==game->currentPlayer){ - return 1; - } - return 0; - } - - int resolve(){ - game->mLayers->stackLayer()->addDamage(source,((MTGCardInstance *) target)->controller(),1); - return 1; - } -}; - -//1280 Atog -class AAtog:public TargetAbility{ - public: - Player * currentController; - int counters; - AAtog(int _id, MTGCardInstance * _source):TargetAbility(_id, _source,NULL, NULL, 0,0){ - currentController = source->controller(); - MTGGameZone * zones[] = {currentController->game->inPlay}; - tc = NEW TypeTargetChooser("artifact", zones, 1, source); - counters = 0; - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ - for (int i = 0; i < counters; i++){ - source->power-=2; - source->addToToughness(-2); - } - counters = 0; - } - TargetAbility::Update(dt); - Player * newController = source->controller(); - if (newController != currentController){ - delete tc; - MTGGameZone * zones[] = {newController->game->inPlay}; //In case Atog's controller changes - tc = NEW TypeTargetChooser("artifact", zones, 1, source); - currentController = newController; - } - } - - int resolve(){ - tc->getNextCardTarget()->controller()->game->putInGraveyard(tc->getNextCardTarget()); - source->power+=2; - source->addToToughness(2); - counters ++; - return 1; - } -}; - - - - -//1284 Dragon Whelp -class ADragonWhelp: public APowerToughnessModifierUntilEndOfTurn{ - public: - ADragonWhelp(int id, MTGCardInstance * card):APowerToughnessModifierUntilEndOfTurn(id, card, card, 1, 0, NEW ManaCost()){ - cost->add(MTG_COLOR_RED, 1); - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP && counters > 3){ - source->controller()->game->putInGraveyard(source); - } - APowerToughnessModifierUntilEndOfTurn::Update(dt); - } - -}; - -//1288 EarthBind -class AEarthbind:public ABasicAbilityModifier{ - public: - AEarthbind(int _id, MTGCardInstance * _source, MTGCardInstance * _target):ABasicAbilityModifier(_id,_source,_target,FLYING,0){ - if (value_before_modification) game->mLayers->stackLayer()->addDamage(source,target,2); - } -}; - -//1291 Fireball -class AFireball:public InstantAbility{ - public: - AFireball(int _id, MTGCardInstance * card, Spell * spell, int x):InstantAbility(_id, card){ - int nbtargets = spell->cursor; - int totaldamage = x+1-nbtargets; - int individualdamage = totaldamage / nbtargets; - Damageable * _target = spell->getNextDamageableTarget(); - while(_target){ - game->mLayers->stackLayer()->addDamage(source,_target,individualdamage); - _target = spell->getNextDamageableTarget(_target); - } - } -}; - -//1245 ForceOfNature -class AForceOfNature:public ActivatedAbility{ - public: - int dealDamageThisTurn; - AForceOfNature(int _id, MTGCardInstance * card):ActivatedAbility(_id,card, NEW ManaCost(),1,0){ - dealDamageThisTurn = 0; - cost->add(MTG_COLOR_GREEN,4); - } - - void Update(float dt){ - if (newPhase !=currentPhase){ - if (newPhase == MTG_PHASE_UNTAP){ - dealDamageThisTurn = 1; - }else if (newPhase == MTG_PHASE_DRAW && dealDamageThisTurn && game->currentPlayer==source->controller() ){ - game->mLayers->stackLayer()->addDamage(source,source->controller(),8); - } - } - ActivatedAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card){ - return (dealDamageThisTurn && currentPhase == MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card)); - } - - int resolve(){ - dealDamageThisTurn = 0; - return 1; - } -}; - -//1301 KeldonWarlord -class AKeldonWarlord:public ListMaintainerAbility{ - public: - AKeldonWarlord(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ - } - - int canBeInList(MTGCardInstance * card){ - if (source->controller()->game->inPlay->hasCard(card) && card->isACreature() && !card->hasType("wall") ) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - source->power += 1; - source->addToToughness(1); - return 1; - } - - int removed(MTGCardInstance * card){ - source->power -= 1; - source->addToToughness(-1); - return 1; - } - -}; - -//1302 : Kird Ape -class AKirdApe:public MTGAbility{ - public: - int init; - AKirdApe(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ - init = 0; - } - - void Update(float dt){ - if (source->controller()->game->inPlay->hasType("forest")){ - if(!init){ - init = 1; - source->power+=1; - source->addToToughness(2); - } - }else{ - if (init){ - init = 0; - source->power-=1; - source->addToToughness(-2); - } - } - } -}; - -//1309 Orcish Artilery -class AOrcishArtillery: public ADamager{ - public: - AOrcishArtillery(int _id,MTGCardInstance * card): ADamager(_id, card, NEW ManaCost(), 2){ - } - - int resolve(){ - ADamager::resolve(); - game->mLayers->stackLayer()->addDamage(source,source->controller(), 3); - return 1; - } - -}; - -//1310 Orcish Oriflame -class AOrcishOriflame:public ListMaintainerAbility{ - public: - int color; - AOrcishOriflame(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ - } - - int canBeInList(MTGCardInstance * card){ - if (source->controller() == game->currentPlayer && game->currentPlayer->game->inPlay->hasCard(card) && card->attacker) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - card->power += 1; - return 1; - } - - int removed(MTGCardInstance * card){ - card->power -= 1; - return 1; - } - -}; - -//1334 Castle -class ACastle:public ListMaintainerAbility{ - public: - ACastle(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ - } - - int canBeInList(MTGCardInstance * card){ - if (source->controller()->game->inPlay->hasCard(card) && card->isACreature() && !card->isAttacker() && !card->tapped) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - card->addToToughness(2); - return 1; - } - - int removed(MTGCardInstance * card){ - card->addToToughness(-2); - return 1; - } -}; - - -//1351 Island Sanctuary -class AIslandSanctuary:public MTGAbility{ - public: - int initThisTurn; - AIslandSanctuary(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ - initThisTurn = 0; - } - - void Update(float dt){ - if (currentPhase == MTG_PHASE_UNTAP && game->currentPlayer == source->controller()) initThisTurn = 0; - - if (initThisTurn && currentPhase == MTG_PHASE_COMBATATTACKERS && game->currentPlayer != source->controller()){ - MTGGameZone * zone = game->currentPlayer->game->inPlay; - for (int i = 0; i < zone->nb_cards; i++){ - MTGCardInstance * card = zone->cards[i]; - if (card->isAttacker() && !card->basicAbilities[FLYING] && !card->basicAbilities[ISLANDWALK]) card->attacker=0; - } - } - } - - int isReactingToClick(MTGCardInstance * card){ - if (card==source && game->currentPlayer == card->controller() && currentPhase == MTG_PHASE_DRAW){ - Interruptible * action = game->mLayers->stackLayer()->_(-1); - if (action->type == ACTION_DRAW) return 1; - } - return 0; - } - - - int reactToClick(MTGCardInstance * card){ - if (!isReactingToClick(card)) return 0; - game->mLayers->stackLayer()->Remove(game->mLayers->stackLayer()->_(-1)); - initThisTurn = 1; - return 1; - } -}; - -//1352 Karma -class AKarma: public TriggeredAbility{ - public: - AKarma(int _id, MTGCardInstance * _source):TriggeredAbility(_id, _source){ - } - - int trigger(){ - if (newPhase != currentPhase && newPhase == MTG_PHASE_UPKEEP) return 1; - return 0; - } - - int resolve(){ - int totaldamage = 0; - MTGGameZone * zone = game->currentPlayer->game->inPlay; - for (int i = 0; i < zone->nb_cards; i++){ - if (zone->cards[i]->hasType("swamp")) totaldamage++;; - } - if (totaldamage) game->mLayers->stackLayer()->addDamage(source,game->currentPlayer, totaldamage); - return 1; - } -}; - -//1355 Norther Paladin -class ANorthernPaladin:public TargetAbility{ - public: - ANorthernPaladin(int _id, MTGCardInstance * card):TargetAbility(_id, card){ - int _cost[] = {MTG_COLOR_WHITE, 2}; - cost = NEW ManaCost(_cost,1); - tc = NEW TargetChooser(); - } - - int resolve(){ - MTGCardInstance * card = tc->getNextCardTarget(); - if (card->hasColor(MTG_COLOR_BLACK)){ - card->controller()->game->putInGraveyard(card); - return 1; - } - return 0; - } - - -}; - -//Sedge Troll -class ASedgeTroll:public MTGAbility{ - public: - int init; - ASedgeTroll(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ - init = 0; - } - - void Update(float dt){ - if (source->controller()->game->inPlay->hasType("swamp")){ - if(!init){ - init = 1; - source->power+=1; - source->addToToughness(1); - } - }else{ - if (init){ - init = 0; - source->power-=1; - source->addToToughness(-1); - } - } - } -}; - -//Soul Net -class ASoulNet:public ActivatedAbility{ - public: - PutInGraveyard * latest; - PutInGraveyard * newDead; - ASoulNet(int _id, MTGCardInstance * card):ActivatedAbility(_id, card,0,0,0){ - int _cost[] = {MTG_COLOR_ARTIFACT, 1}; - cost = NEW ManaCost(_cost,1); - latest = ((PutInGraveyard *) GameObserver::GetInstance()->mLayers->stackLayer()->getPrevious(NULL,ACTION_PUTINGRAVEYARD,RESOLVED_OK)); - newDead = latest; - } - - int isReactingToClick(MTGCardInstance * card){ - newDead = ((PutInGraveyard *) GameObserver::GetInstance()->mLayers->stackLayer()->getPrevious(NULL,ACTION_PUTINGRAVEYARD,RESOLVED_OK)); - if (newDead && newDead != latest && newDead->card->isACreature()) - return ActivatedAbility::isReactingToClick(card); - return 0; - } - int resolve(){ - latest = newDead; - source->controller()->life++; - return 1; - } -}; - - -//Stasis -class AStasis:public ActivatedAbility{ - public: - int paidThisTurn; - AStasis(int _id, MTGCardInstance * card):ActivatedAbility(_id,card, NEW ManaCost(),1,0){ - paidThisTurn = 1; - cost->add(MTG_COLOR_BLUE,1); - } - - void Update(float dt){ - //Upkeep Cost - if (newPhase !=currentPhase){ - if (newPhase == MTG_PHASE_UPKEEP){ - paidThisTurn = 0; - }else if (!paidThisTurn && newPhase > MTG_PHASE_UPKEEP && game->currentPlayer==source->controller() ){ - game->currentPlayer->game->putInGraveyard(source); - paidThisTurn = 1; - } - } - //Stasis Effect - for (int i = 0; i < 2; i++){ - game->phaseRing->removePhase(MTG_PHASE_UNTAP,game->players[i]); - } - - //Parent Class Method Call - ActivatedAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card){ - return (!paidThisTurn && currentPhase == MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card)); - } - - int resolve(){ - paidThisTurn = 1; - return 1; - } - - int destroy(){ - for (int i = 0; i < 2; i++){ - game->phaseRing->addPhaseBefore(MTG_PHASE_UNTAP,game->players[i],MTG_PHASE_UPKEEP,game->players[i]); - } - return 1; - } -}; - - - -//--------------Addon Abra------------------ -//ShieldOfTheAge -class AShieldOfTheAge: public TargetAbility{ - public: - AShieldOfTheAge(int _id, MTGCardInstance * card):TargetAbility(_id,card,NEW DamageTargetChooser(card,_id),NEW ManaCost(),0,0){ - cost->add(MTG_COLOR_ARTIFACT,2); - } - - int resolve(){ - Damage * damage = tc->getNextDamageTarget(); - if (!damage) return 0; - game->mLayers->stackLayer()->Fizzle(damage); - return 1; - } -}; - -// GiveLifeForTappedType -class AGiveLifeForTappedType:public MTGAbility{ - public: - char type[20]; - int nbtypestapped; - - int counttypesTapped(){ - int result = 0; - MTGInPlay * inplay = source->controller()->opponent()->game->inPlay; - for (int i = 0; i < inplay->nb_cards; i++){ - MTGCardInstance * card = inplay->cards[i]; - if (card->tapped && card->hasType(type)) result++; - } - return result; - } - - AGiveLifeForTappedType(int _id, MTGCardInstance * source, const char * _type):MTGAbility(_id, source){ - sprintf(type,"%s",_type);{ - nbtypestapped = counttypesTapped(); - } - } - - void Update(float dt){ - int newcount = counttypesTapped(); - for (int i=0; i < newcount - nbtypestapped; i++){ - source->controller()->life++; - } - nbtypestapped = newcount; - } -}; - -// People of the Woods -class APeopleOfTheWoods:public ListMaintainerAbility{ - public: - APeopleOfTheWoods(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ - } - - int canBeInList(MTGCardInstance * card){ - if (source->controller()->game->inPlay->hasCard(card) && card->hasType("forest") ) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - source->addToToughness(1); - return 1; - } - - int removed(MTGCardInstance * card){ - source->addToToughness(-1); - return 1; - } - -}; - -//Abomination Kill blocking creature if white or green -class AAbomination :public MTGAbility{ - public: - MTGCardInstance * opponents[20]; - int nbOpponents; - AAbomination (int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ - nbOpponents = 0; - } - - void Update(float dt){ - if (newPhase != currentPhase){ - if( newPhase == MTG_PHASE_COMBATDAMAGE){ - nbOpponents = 0; - MTGCardInstance * opponent = source->getNextOpponent(); - while ((opponent && opponent->hasColor(MTG_COLOR_GREEN)) || opponent->hasColor(MTG_COLOR_WHITE)){ - opponents[nbOpponents] = opponent; - nbOpponents ++; - opponent = source->getNextOpponent(opponent); - } - }else if (newPhase == MTG_PHASE_COMBATEND){ - for (int i = 0; i < nbOpponents ; i++){ - game->mLayers->stackLayer()->addPutInGraveyard(opponents[i]); - } - } - } - } - - int testDestroy(){ - if(!game->isInPlay(source) && currentPhase != MTG_PHASE_UNTAP){ - return 0; - }else{ - return MTGAbility::testDestroy(); - } - } -}; - - - -//Minion of Leshrac -class AMinionofLeshrac: public TargetAbility{ - public: - int paidThisTurn; - AMinionofLeshrac(int _id, MTGCardInstance * source):TargetAbility(_id, source, NEW CreatureTargetChooser(),0,1,0){ - paidThisTurn = 1; - } - - void Update(float dt){ - if (newPhase != currentPhase && source->controller() == game->currentPlayer){ - if (newPhase == MTG_PHASE_UNTAP){ - paidThisTurn = 0; - }else if( newPhase == MTG_PHASE_UPKEEP + 1 && !paidThisTurn){ - game->mLayers->stackLayer()->addDamage(source,source->controller(), 5); - source->tapped = 1; - } - } - TargetAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card){ - if (currentPhase != MTG_PHASE_UPKEEP || paidThisTurn) return 0; - return TargetAbility::isReactingToClick(card); - } - - int resolve(){ - MTGCardInstance * card = tc->getNextCardTarget(); - if (card && card != source && card->controller() == source->controller()){ - card->controller()->game->putInGraveyard(card); - paidThisTurn = 1; - return 1; - } - return 0; - } - -}; - -//2703 Lost Order of Jarkeld -class ALostOrderofJarkeld:public ListMaintainerAbility{ - public: - ALostOrderofJarkeld(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ - } - - int canBeInList(MTGCardInstance * card){ - if (card==source || (game->currentPlayer->game->inPlay->hasCard(card) && card->isACreature()) ) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - source->power += 1; - source->addToToughness(1); - return 1; - } - - int removed(MTGCardInstance * card){ - source->power -= 1; - source->addToToughness(-1); - return 1; - } - -}; - -//CreaturePowerToughnessModifierForAllTypeControlled -class ACreaturePowerToughnessModifierForAllTypeControlled:public ListMaintainerAbility{ - public: - char type[20]; - ACreaturePowerToughnessModifierForAllTypeControlled(int _id, MTGCardInstance * _source, const char * _type):ListMaintainerAbility(_id, _source){ - } - - int canBeInList(MTGCardInstance * card){ - if (source->controller()->game->inPlay->hasCard(card) && card->hasType(type) ) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - source->power += 1; - source->addToToughness(1); - return 1; - } - - int removed(MTGCardInstance * card){ - source->power -= 1; - source->addToToughness(-1); - return 1; - } - -}; - -//GenericKirdApe -class AGenericKirdApe:public MTGAbility{ - public: - int init; - char type [20]; - int power; - int toughness; - AGenericKirdApe(int _id, MTGCardInstance * _source, const char * _type, int _power, int _toughness):MTGAbility(_id, _source){ - init = 0; - } - - void Update(float dt){ - if (source->controller()->game->inPlay->hasType(type)){ - if(!init){ - init = 1; - source->power+=power; - source->addToToughness(toughness); - } - }else{ - if (init){ - init = 0; - source->power-=power; - source->addToToughness(-toughness); - } - } - } -}; - - -//Rampage ability Tentative 2 -class ARampageAbility:public MTGAbility{ - public: - int nbOpponents; - int PowerModifier; - int ToughnessModifier; - int modifier; - ARampageAbility(int _id, MTGCardInstance * _source,int _PowerModifier, int _ToughnessModifier):MTGAbility(_id, _source){ - modifier=0; - } - void Update(float dt){ - if (source->isAttacker()){ - MTGInPlay * inPlay = game->opponent()->game->inPlay; - for (int i = 0; i < inPlay->nb_cards; i ++){ - MTGCardInstance * current = inPlay->cards[i]; - if (current->isDefenser()){ - modifier++; - } - } - source->power+= (PowerModifier * modifier); - source->addToToughness(ToughnessModifier * modifier); - } - } -}; - - -//Rampage ability Tentative 1 - Did not work as expected -class A1RampageAbility:public MTGAbility{ - public: - MTGCardInstance * opponents[20]; - int nbOpponents; - int PowerModifier; - int ToughnessModifier; - A1RampageAbility(int _id, MTGCardInstance * _source,int _PowerModifier, int _ToughnessModifier):MTGAbility(_id, _source){ - nbOpponents = 0; - } - - void Update(float dt){ - if (source->isAttacker()){ - if (newPhase != currentPhase){ - if( newPhase == MTG_PHASE_COMBATDAMAGE){ - nbOpponents = 0; - MTGCardInstance * opponent = source->getNextOpponent(); - while (opponent){ - opponents[nbOpponents] = opponent; - nbOpponents ++; - source->power+= PowerModifier; - source->addToToughness(ToughnessModifier); - opponent = source->getNextOpponent(opponent); - } - } - } - } - } -}; -#endif + +#ifndef _CARDS_H_ +#define _CARDS_H_ + +#include "MTGAbility.h" +#include "GroupOfCards.h" +#include "ManaCost.h" +#include "CardDescriptor.h" +#include "AIPlayer.h" +#include "CardDisplay.h" +#include "Subtypes.h" +#include "CardGui.h" + +#include +#include + + +#include +using std::map; + +/* +Generic classes +*/ + + +//Drawer, allows to draw a card for a cost: + +class ADrawer:public ActivatedAbility{ +public: + int nbcards; + ADrawer(int _id, MTGCardInstance * card,ManaCost * _cost, int _nbcards = 1, int _tap = 1):ActivatedAbility(_id, card,_cost,0,_tap),nbcards(_nbcards){ + } + + int resolve(){ + game->mLayers->stackLayer()->addDraw(source->controller(),nbcards); + return 1; + } + + const char * getMenuText(){ + return "Draw"; + } + + +}; + + +//Destroyer. TargetAbility +class ADestroyer:public TargetAbility{ +public: + int bury; + ADestroyer(int _id, MTGCardInstance * _source, TargetChooser * _tc = NULL, int _bury = 0):TargetAbility(_id,_source, tc),bury(_bury){ + if (!tc) tc = NEW CreatureTargetChooser(); + } + + int resolve(){ + MTGCardInstance * _target = tc->getNextCardTarget(); + if(_target){ + if (bury){ + _target->controller()->game->putInGraveyard(_target); + }else{ + game->mLayers->stackLayer()->addPutInGraveyard(_target); + } + return 1; + } + return 0; + } + + const char * getMenuText(){ + return "Destroy"; + } + +}; + +//Destroyer. TargetAbility +class ABurier:public ADestroyer{ +public: + ABurier(int _id, MTGCardInstance * _source, TargetChooser * _tc = NULL):ADestroyer(_id,_source, tc,1){ + } + + const char * getMenuText(){ + return "Bury"; + } +}; + + +/*Changes one of the basic abilities of target +source : spell +target : spell target (creature) +modifier : 1 to add the ability, 0 to remove it +_ability : Id of the ability, as described in mtgdefinitions +*/ +class ABasicAbilityModifier:public MTGAbility{ +public: + int modifier; + int ability; + int value_before_modification; + ABasicAbilityModifier(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _ability, int _modifier = 1): MTGAbility(_id,_source,_target),modifier(_modifier),ability(_ability){ + value_before_modification = ((MTGCardInstance * )target)->basicAbilities[ability]; + ((MTGCardInstance * )target)->basicAbilities[ability]=modifier; + } + + int destroy(){ + if (((MTGCardInstance * )target)->basicAbilities[ability] == modifier){ + ((MTGCardInstance * )target)->basicAbilities[ability] = value_before_modification; + return 1; + }else{ + //BUG !!! + return 0; + } + } +}; + +//Modifies an ability until end of turn. Needs a target +class ABasicAbilityModifierUntilEOT:public TargetAbility{ + public: + MTGCardInstance * mTargets[50]; + int nbTargets; + int modifier; + int stateBeforeActivation[50]; + int ability; + ABasicAbilityModifierUntilEOT(int _id, MTGCardInstance * _source, int _ability, ManaCost * _cost, TargetChooser * _tc = NULL, int _modifier = 1): TargetAbility(_id,_source,_cost),modifier(_modifier), ability(_ability){ + nbTargets = 0; + tc = _tc; + if (!tc) tc = NEW CreatureTargetChooser(_source); + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ + for (int i = 0; i < nbTargets; i++){ + MTGCardInstance * mTarget = mTargets[i]; + if(mTarget && mTarget->basicAbilities[ability]){ + mTarget->basicAbilities[ability] = stateBeforeActivation[i]; + } + } + nbTargets = 0; + } + TargetAbility::Update(dt); + } + + + int resolve(){ + MTGCardInstance * mTarget = tc->getNextCardTarget(); + if (mTarget){ + mTargets[nbTargets] = mTarget; + stateBeforeActivation[nbTargets] = mTarget->basicAbilities[ability]; + mTarget->basicAbilities[ability] = modifier; + nbTargets++; + } + return 1; + } + + const char * getMenuText(){ + return MTGBasicAbilities[ability]; + } + + +}; + +/*Instants that modifies a basic ability until end of turn */ +class AInstantBasicAbilityModifierUntilEOT: public InstantAbility{ +public: + int stateBeforeActivation; + int ability; + AInstantBasicAbilityModifierUntilEOT(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _ability, int value):InstantAbility(_id, _source, _target),ability(_ability){ + stateBeforeActivation = _target->basicAbilities[ability]; + _target->basicAbilities[ability] = value; + } + + int destroy(){ + ((MTGCardInstance *)target)->basicAbilities[ability] = stateBeforeActivation; + return 1; + } + +}; + +//Alteration of Ability until of turn (Aura) +class ABasicAbilityAuraModifierUntilEOT: public ActivatedAbility{ +public: + int stateBeforeActivation; + int ability; + int value; + ABasicAbilityAuraModifierUntilEOT(int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost, int _ability, int _value = 1):ActivatedAbility(_id,_source, _cost, 0,0), ability(_ability), value(_value){ + target = _target; + stateBeforeActivation = _target->basicAbilities[ability]; + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ + MTGCardInstance * _target = (MTGCardInstance *) target; + _target->basicAbilities[ability] = stateBeforeActivation; + } + ActivatedAbility::Update(dt); + } + + int resolve(){ + MTGCardInstance * _target = (MTGCardInstance *) target; + stateBeforeActivation = _target->basicAbilities[ability]; + _target->basicAbilities[ability] = value; + return 1; + } + + const char * getMenuText(){ + return MTGBasicAbilities[ability]; + } + +}; + + + +/*Gives life each time a spell matching CardDescriptor's criteria are match . Optionnal manacost*/ +class ASpellCastLife:public MTGAbility{ +public: + CardDescriptor trigger; + ManaCost * cost; + int life; + MTGCardInstance * lastUsedOn; + MTGCardInstance * lastChecked; + ASpellCastLife(int id, MTGCardInstance * _source, CardDescriptor _trigger, ManaCost * _cost, int _life): MTGAbility(id, _source), trigger(_trigger), cost(_cost), life(_life){ + } + ASpellCastLife(int id, MTGCardInstance * _source, int color, ManaCost * _cost, int _life): MTGAbility(id, _source), cost(_cost), life(_life){ + trigger.setColor(color); + } + + int isReactingToClick(MTGCardInstance * _card){ + if (_card == source && game->currentlyActing()->game->inPlay->hasCard(source)){ + if (game->currentlyActing()->getManaPool()->canAfford(cost)){ + Interruptible * laststackitem = game->mLayers->stackLayer()->_(-1); + if (laststackitem && laststackitem->type == ACTION_SPELL){ + Spell * spell = (Spell*)laststackitem; + if (spell->source != lastUsedOn && trigger.match(spell->source)){ + lastChecked = spell->source; + return 1; + } + } + } + } + return 0; + } + + int reactToClick(MTGCardInstance * _card){ + if (!isReactingToClick( _card)) return 0; + game->currentlyActing()->getManaPool()->pay(cost); + game->currentlyActing()->life+=life; + lastUsedOn = lastChecked; + return 1; + } + +}; + +//Allows to untap at any moment for an amount of mana +class AUnBlocker:public MTGAbility{ +public: + ManaCost * cost; + AUnBlocker(int id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost):MTGAbility(id, _source, _target), cost(_cost){ + } + + + int isReactingToClick(MTGCardInstance * _card){ + if (_card == target && game->currentlyActing()->game->inPlay->hasCard(source) && (MTGCardInstance *) _card->isTapped()){ + if (game->currentlyActing()->getManaPool()->canAfford(cost)){ + return 1; + } + } + return 0; + } + + int reactToClick(MTGCardInstance * _card){ + if (!isReactingToClick( _card)) return 0; + game->currentlyActing()->getManaPool()->pay(cost); + _card->untap(); + return 1; + } +}; + +//Allows to untap target card once per turn for a manaCost +class AUntaperOnceDuringTurn:public AUnBlocker{ +public: + int untappedThisTurn; + int onlyPlayerTurn; + AUntaperOnceDuringTurn(int id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost, int _onlyPlayerTurn = 1):AUnBlocker(id, _source, _target, _cost){ + onlyPlayerTurn = _onlyPlayerTurn; + untappedThisTurn = 0; + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP) untappedThisTurn = 0; + AUnBlocker::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card){ + if (onlyPlayerTurn && game->currentPlayer!=source->controller()) return 0; + if (untappedThisTurn) return 0; + return AUnBlocker::isReactingToClick(card); + } + + int reactToClick(MTGCardInstance * card){ + untappedThisTurn = 1; + return AUnBlocker::reactToClick(card); + } +}; + +//Alteration of Power and Toughness (enchantments) +class APowerToughnessModifier: public MTGAbility{ +public: + int power, toughness; + APowerToughnessModifier(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness):MTGAbility(id,_source,_target),power(_power),toughness(_toughness){ + _target->power += power; + _target->addToToughness(toughness); + } + + int destroy(){ + ((MTGCardInstance *)target)->power -= power; + ((MTGCardInstance *)target)->addToToughness(-toughness); + return 1; + } +}; + +// Permanent life alteration evry turn of the target's controller. Useful only for unstable mutation currently +class APowerToughnessModifierRegularCounter:public MTGAbility{ +public: + int power, toughness; + int phase; + APowerToughnessModifierRegularCounter(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _phase, int _power, int _toughness):MTGAbility(id,_source,_target),power(_power),toughness(_toughness), phase(_phase){ + } + + void Update(float dt){ + if (newPhase !=currentPhase && newPhase==phase && game->currentPlayer==((MTGCardInstance *)target)->controller()){ + ((MTGCardInstance *)target)->power += power; + ((MTGCardInstance *)target)->addToToughness(toughness); + } + } + +}; + + +//Alteration of Power and Toughness until end of turn (TargetAbility) +// Gives +n/+m until end of turn to any card that's a target +class ATargetterPowerToughnessModifierUntilEOT: public TargetAbility{ +public: + MTGCardInstance * mTargets[50]; + int nbTargets; + int power, toughness; + + ATargetterPowerToughnessModifierUntilEOT(int _id, MTGCardInstance * _source, int _power, int _toughness, ManaCost * _cost, TargetChooser * _tc = NULL):TargetAbility(_id,_source,_tc,_cost,0),power(_power),toughness(_toughness){ + if (!tc) tc = NEW CreatureTargetChooser(_source); + nbTargets = 0; + } + + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ + for (int i = 0; i < nbTargets; i++){ + MTGCardInstance * mTarget = mTargets[i]; + if(mTarget){ + mTarget->power-=power; + mTarget->addToToughness(-toughness); + } + } + nbTargets = 0; + } + TargetAbility::Update(dt); + } + + + int resolve(){ + MTGCardInstance * mTarget = tc->getNextCardTarget(); + if (mTarget){ + mTargets[nbTargets] = mTarget; + mTarget->power+= power; + mTarget->addToToughness(toughness); + nbTargets++; + } + return 1; + } + +}; + + + +//Alteration of Power and Toughness until end of turn (Aura) +class APowerToughnessModifierUntilEndOfTurn: public MTGAbility{ +public: + int power, toughness; + int counters; + int maxcounters; + ManaCost * cost; + APowerToughnessModifierUntilEndOfTurn(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness, ManaCost * _cost, int _maxcounters = 0):MTGAbility(id,_source,_target),power(_power),toughness(_toughness),maxcounters(_maxcounters), cost(_cost){ + counters = 0; + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ + while(counters){ + ((MTGCardInstance *)target)->power -= power; + ((MTGCardInstance *)target)->addToToughness(-toughness); + counters--; + } + } + } + + int isReactingToClick(MTGCardInstance * _card){ + if (_card == source && (!maxcounters || counters < maxcounters) && game->currentlyActing()->game->inPlay->hasCard(source)){ + if (game->currentlyActing()->getManaPool()->canAfford(cost)){ + return 1; + } + } + return 0; + } + + int reactToClick(MTGCardInstance * _card){ + if (!isReactingToClick( _card)) return 0; + game->currentlyActing()->getManaPool()->pay(cost); + ((MTGCardInstance *)target)->power += power; + ((MTGCardInstance *)target)->addToToughness(toughness); + counters++; + return 1; + } +}; + + +//Alteration of Power and toughness until end of turn (instant) +class AInstantPowerToughnessModifierUntilEOT: public InstantAbility{ +public: + int power, toughness; + AInstantPowerToughnessModifierUntilEOT(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness): InstantAbility(_id, _source, _target), power(_power), toughness(_toughness){ + } + + int resolve(){ + ((MTGCardInstance *)target)->power +=power; + ((MTGCardInstance *)target)->addToToughness(toughness); + return 1; + } + + int destroy(){ + ((MTGCardInstance *)target)->power -=power; + ((MTGCardInstance *)target)->addToToughness(-toughness); + return 1; + } + +}; +//Untap Blockers with simple Mana Mechanism +class AUntapManaBlocker: public Blocker{ +public: + AUntapManaBlocker(int id, MTGCardInstance * card, ManaCost * _cost):Blocker(id, card, _cost){ + } + + AUntapManaBlocker(int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost):Blocker(id, card,_target, _cost){ + } +}; + +/* Spell Counters (Enchantment) for a mana cost */ +//LifeForce +class ASpellCounterEnchantment:public TargetAbility{ +public: + + ASpellCounterEnchantment(int _id, MTGCardInstance * _source, ManaCost * _cost,int color = -1, int _tap = 0):TargetAbility(_id,_source,NEW SpellTargetChooser(_source,color),_cost,0,_tap){ + } + + int resolve(){ + Spell * _target = tc->getNextSpellTarget(); + if(_target){ + game->mLayers->stackLayer()->Fizzle(_target); + return 1; + } + return 0; + } + +}; + +/*Mana Producers (lands) +//These have a reactToClick function, and therefore two manaProducers on the same card conflict with each other +//That means the player has to choose one. although that is perfect for cards such as birds of paradise or badlands, +other solutions need to be provided for abilities that add mana (ex: mana flare) +*/ +/* +Currently the mana is added to the pool AFTER the animation +This is VERY BAD, since we don't have any control on the duration of the animation. This can lead to bugs with +the AI, who is expecting to have the mana in its manapool right after clicking the land card !!! +The sum of "dt" has to be 0.25 for the mana to be in the manapool currently +*/ + +class AManaProducer: public MTGAbility{ +protected: + ManaCost * cost; + ManaCost * output; + string menutext; + float x0,y0,x1,y1,x,y; + float animation; + Player * controller; + + hgeParticleSystem * mParticleSys; +public: + AManaProducer(int id, MTGCardInstance * card, ManaCost * _output, ManaCost * _cost = NULL ):MTGAbility(id, card){ + LOG("==Creating ManaProducer Object"); + cost = _cost; + output=_output; + x1 = 10; + y1 = 220; + Player * player = card->controller(); + if (player == game->players[1]) y1 = 100; + x = x1; + y = y1; + animation = 0.f; + mParticleSys = NULL; + menutext = ""; + + int landColor = output->getMainColor(); + + if (landColor == MTG_COLOR_RED){ + mParticleSys = NEW hgeParticleSystem("graphics/manared.psi",GameApp::CommonRes->GetQuad("particles")); + }else if (landColor == MTG_COLOR_BLUE){ + mParticleSys = NEW hgeParticleSystem("graphics/manablue.psi", GameApp::CommonRes->GetQuad("particles")); + }else if (landColor == MTG_COLOR_GREEN){ + mParticleSys = NEW hgeParticleSystem("graphics/managreen.psi", GameApp::CommonRes->GetQuad("particles")); + }else if (landColor == MTG_COLOR_BLACK){ + mParticleSys = NEW hgeParticleSystem("graphics/manablack.psi", GameApp::CommonRes->GetQuad("particles")); + }else if (landColor == MTG_COLOR_WHITE){ + mParticleSys = NEW hgeParticleSystem("graphics/manawhite.psi", GameApp::CommonRes->GetQuad("particles")); + }else{ + mParticleSys = NEW hgeParticleSystem("graphics/mana.psi", GameApp::CommonRes->GetQuad("particles")); + } + + + + LOG("==ManaProducer Object Creation successful !"); + } + + void Update(float dt){ + if (mParticleSys) mParticleSys->Update(dt); + if (animation){ + x = (1.f - animation)*x1 + animation * x0; + y = (1.f - animation)*y1 + animation * y0; + if (mParticleSys) mParticleSys->MoveTo(x, y); + if (mParticleSys && animation == 1.f) mParticleSys->Fire(); + animation -= 4 *dt; + if (animation < 0){ + animation = 0; + controller->getManaPool()->add(output); + if (mParticleSys) mParticleSys->Stop(); + } + } + + } + + void Render(){ + JRenderer * renderer = JRenderer::GetInstance(); + if (animation){ + renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE); + if (mParticleSys) mParticleSys->Render(); + // set normal blending + renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); + } + + } + + int isReactingToClick(MTGCardInstance * _card){ + int result = 0; + if (_card == source && !source->isTapped() && game->currentlyActing()->game->inPlay->hasCard(source) && (source->hasType("land") || !source->hasSummoningSickness()) ){ + if (!cost || game->currentlyActing()->getManaPool()->canAfford(cost)) result = 1; + } + return result; + } + + int reactToClick(MTGCardInstance * _card){ + if (!isReactingToClick( _card)) return 0; + source->tapped = 1; + if (cost) GameObserver::GetInstance()->currentlyActing()->getManaPool()->pay(cost); + animation = 1.f; + CardGui * cardg = game->mLayers->playLayer()->getByCard(source); + if (cardg){ + x0 = cardg->x + 15; + y0 = cardg->y + 20; + } + controller = source->controller(); + return 1; + } + + const char * getMenuText(){ + if (menutext.size())return menutext.c_str(); + menutext = "Add "; + char buffer[128]; + int alreadyHasOne = 0; + for (int i= 0; i < 6; i++){ + int value = output->getCost(i); + if (value){ + if (alreadyHasOne) menutext.append(","); + sprintf(buffer, "%i ", value); + menutext.append(buffer); + switch (i){ + case MTG_COLOR_RED: + menutext.append("red"); + break; + case MTG_COLOR_BLUE: + menutext.append("blue"); + break; + case MTG_COLOR_GREEN: + menutext.append("green"); + break; + case MTG_COLOR_WHITE: + menutext.append("white"); + break; + case MTG_COLOR_BLACK: + menutext.append("black"); + break; + default: + break; + } + alreadyHasOne = 1; + } + } + menutext.append(" mana"); + return menutext.c_str(); + } + + int testDestroy(){ + if (animation >0) return 0; + return MTGAbility::testDestroy(); + } + + ~AManaProducer(){ + LOG("==Destroying ManaProducer Object"); + if (cost) delete cost; + SAFE_DELETE(output); + if (mParticleSys) delete mParticleSys; + LOG("==Destroying ManaProducer Object Successful!"); + } + +}; + + +/* Lifelink Ability */ +class ALifeLink:public MTGAbility{ +public: + int nbdamagesthisturn; + Damage * lastDamage; + ALifeLink(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ + nbdamagesthisturn = 0; + lastDamage = NULL; + } + + void Update(float dt){ + ActionStack * as = game->mLayers->stackLayer(); + int totaldamages = as->count(ACTION_DAMAGE,RESOLVED_OK); + if ( totaldamages > nbdamagesthisturn){ + Damage * damage = ((Damage * )as->getNext(lastDamage,ACTION_DAMAGE, RESOLVED_OK)); + while(damage){ + lastDamage = damage; + if (damage->source == source){ + source->controller()->life+= damage->damage; + } + damage = ((Damage * )as->getNext(lastDamage,ACTION_DAMAGE, RESOLVED_OK)); + } + }else if (totaldamages ==0){ + lastDamage = NULL; + } + nbdamagesthisturn = totaldamages; + } + +}; + + +//Circle of Protections +class ACircleOfProtection: public TargetAbility{ +public: + ACircleOfProtection(int _id, MTGCardInstance * source, int _color):TargetAbility(_id,source,NEW DamageTargetChooser(source,_color),NEW ManaCost(),0,0){ + cost->add(MTG_COLOR_ARTIFACT,1); + } + + int resolve(){ + Damage * damage = tc->getNextDamageTarget(); + if (!damage) return 0; + game->mLayers->stackLayer()->Fizzle(damage); + return 1; + } +}; + +//Basic regeneration mechanism for a Mana cost +class AStandardRegenerate:public ActivatedAbility{ +public: + AStandardRegenerate(int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost):ActivatedAbility(_id,_source,_cost,0,0){ + target = _target; + } + + int resolve(){ + MTGCardInstance * _target = (MTGCardInstance *)target; + _target->regenerate(); + PutInGraveyard * action = ((PutInGraveyard *) game->mLayers->stackLayer()->getNext(NULL,ACTION_PUTINGRAVEYARD,NOT_RESOLVED)); + while(action){ +#if defined (WIN32) || defined (LINUX) + OutputDebugString("Fizzling due to regenerate! \n"); +#endif + if (action->card == _target){ + game->mLayers->stackLayer()->Fizzle(action); + } + action = ((PutInGraveyard *) game->mLayers->stackLayer()->getNext(action,ACTION_PUTINGRAVEYARD,NOT_RESOLVED)); + } + return 1; + } + + const char * getMenuText(){ + return "Regenerate"; + } + +}; + +/*Gives protection to a target */ +class AProtectionFrom:public MTGAbility{ +public: + CardDescriptor * cd; + void initProtection(){ + ((MTGCardInstance *)target)->addProtection(cd); + } + + AProtectionFrom(int _id, MTGCardInstance * _source, MTGCardInstance * _target, CardDescriptor * _cd):MTGAbility(_id, _source, _target),cd(_cd){ + initProtection(); + } + AProtectionFrom(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int color):MTGAbility(_id, _source, _target){ + cd = NEW CardDescriptor(); + cd->colors[color] = 1; + initProtection(); + } + + int destroy(){ + ((MTGCardInstance *)target)->removeProtection(cd); + return 1; + } + +}; + +//Aura Enchantments that provide controller of target life or damages at a given phase of their turn +class ARegularLifeModifierAura:public MTGAbility{ +public: + int life; + int phase; + int onlyIfTargetTapped; + ARegularLifeModifierAura(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _phase, int _life, int _onlyIfTargetTapped=0):MTGAbility(id,_source,_target),life(_life), phase(_phase),onlyIfTargetTapped(_onlyIfTargetTapped){ + } + + void Update(float dt){ + if (newPhase !=currentPhase && newPhase==phase && game->currentPlayer==((MTGCardInstance *)target)->controller()){ + if (!onlyIfTargetTapped || ((MTGCardInstance *)target)->tapped){ + if (life > 0){ + game->currentPlayer->life+=life; + }else{ + game->mLayers->stackLayer()->addDamage(source, game->currentPlayer, -life); + } + } + } + } +}; + + +//ExaltedAbility (Shards of Alara) +class AExalted:public ListMaintainerAbility{ +public: + int power, toughness; + MTGCardInstance * luckyWinner; + AExalted(int _id, MTGCardInstance * _source, int _power = 1, int _toughness = 1):ListMaintainerAbility(_id, _source),power(_power),toughness(_toughness){ + luckyWinner = NULL; + } + + + int canBeInList(MTGCardInstance * card){ + if (card->isAttacker() && game->currentPlayer == source->controller()) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + if(cards.size() == 1){ + luckyWinner = cards.begin()->first; + luckyWinner->addToToughness(toughness); + luckyWinner->power+=power; + }else if (cards.size() == 2){ + luckyWinner->addToToughness(-toughness); + luckyWinner->power-=power; + } + return 1; + } + + int removed(MTGCardInstance * card){ + if(cards.size() == 1){ + luckyWinner = cards.begin()->first; + luckyWinner->addToToughness(toughness); + luckyWinner->power+=power; + }else if (cards.size() == 0){ + luckyWinner->addToToughness(-toughness); + luckyWinner->power-=power; + } + return 1; + } + +}; + + +//ExaltedAbility for basic abilities (Shards of Alara) +class AExaltedAbility:public ListMaintainerAbility{ +public: + int ability; + MTGCardInstance * luckyWinner; + AExaltedAbility(int _id, MTGCardInstance * _source, int _ability):ListMaintainerAbility(_id, _source),ability(_ability){ + luckyWinner = NULL; + } + + + int canBeInList(MTGCardInstance * card){ + if (card->isAttacker() && game->currentPlayer == source->controller()) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + luckyWinner = cards.begin()->first; + if(cards.size() == 1){ + luckyWinner->basicAbilities[ability]+=1; + }else if (cards.size() == 2){ + luckyWinner->basicAbilities[ability]-=1; + } + return 1; + } + + int removed(MTGCardInstance * card){ + if(cards.size() == 1){ + luckyWinner->basicAbilities[ability]+=1; + }else if (cards.size() == 0){ + luckyWinner->basicAbilities[ability]-=1; + } + return 1; + } + +}; + + +//Converts lands to creatures (Kormus bell, Living lands) +class AConvertLandToCreatures:public ListMaintainerAbility{ +public: + int type; + int power, toughness; + AConvertLandToCreatures(int _id, MTGCardInstance * _source, const char * _type, int _power = 1, int _toughness = 1):ListMaintainerAbility(_id, _source),power(_power),toughness(_toughness){ + type = Subtypes::subtypesList->Add(_type); + } + + + int canBeInList(MTGCardInstance * card){ + if (card->hasType(type)) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + card->power = 1; + card->setToughness(1); + card->setSubtype("creature"); + return 1; + } + + int removed(MTGCardInstance * card){ + card->removeType("creature"); + return 1; + } + +}; + +//Lords (Merfolk lord...) give power and toughness to OTHER creatures of their type, they can give them special abilities, regeneration +class ALord:public ListMaintainerAbility{ +public: + string type; + int power, toughness; + int ability; + ManaCost * regenCost; + map regenerations; + ALord(int _id, MTGCardInstance * card, const char * _type, int _power = 0 , int _toughness = 0, int _ability = -1, ManaCost * _regenCost = NULL):ListMaintainerAbility(_id,card){ + type = _type; + power = _power; + toughness = _toughness; + ability = _ability; + regenCost = _regenCost; + } + + int canBeInList(MTGCardInstance * card){ + if (card!=source && card->isACreature() && card->hasSubtype(type)) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + card->power += power; + card->addToToughness(toughness); + if (ability != -1) card->basicAbilities[ability] +=1; + if (regenCost){ + AStandardRegenerate * regen = NEW AStandardRegenerate(0, card, card, regenCost); + regenerations[card] = regen; + game->addObserver(regen); + } + return 1; + } + + int removed(MTGCardInstance * card){ + card->power -= power; + card->addToToughness(-toughness); + if (ability != -1 && card->basicAbilities[ability]) card->basicAbilities[ability] -=1; + if (regenCost){ + if(regenerations.find(card) != regenerations.end()){ + if (game->isInPlay(card)) game->removeObserver(regenerations[card]); + regenerations.erase(card); + } + } + return 1; + } + +}; + +//Lords (Merfolk lord...) give power and toughness to OTHER creatures of a given color, they can give them special abilities, regeneration +class AColorLord:public ListMaintainerAbility{ +public: + int color; + int notcolor; + int power, toughness; + int ability; + ManaCost * regenCost; + map regenerations; + AColorLord(int _id, MTGCardInstance * card, int _color, int _notcolor = -1, int _power = 0 , int _toughness = 0, int _ability = -1, ManaCost * _regenCost = NULL):ListMaintainerAbility(_id,card){ + color = _color; + notcolor = _notcolor; + power = _power; + toughness = _toughness; + ability = _ability; + regenCost = _regenCost; + } + + int canBeInList(MTGCardInstance * card){ + if (notcolor > -1){ + if (card!=source && card->isACreature() && !card->hasColor(notcolor)) return 1; + }else{ + if (card!=source && card->isACreature() && card->hasColor(color)) return 1; + } + return 0; + } + + int added(MTGCardInstance * card){ + card->power += power; + card->addToToughness(toughness); + if (ability != -1) card->basicAbilities[ability] +=1; + if (regenCost){ + AStandardRegenerate * regen = NEW AStandardRegenerate(0, card, card, regenCost); + regenerations[card] = regen; + game->addObserver(regen); + } + return 1; + } + + int removed(MTGCardInstance * card){ + card->power -= power; + card->addToToughness(-toughness); + if (ability != -1 && card->basicAbilities[ability]) card->basicAbilities[ability] -=1; + if (regenCost){ + if(regenerations.find(card) != regenerations.end()){ + game->removeObserver(regenerations[card]); + regenerations.erase(card); + } + } + return 1; + } + +}; + + +/* Standard Damager, can choose a NEW target each time the price is paid */ +class ADamager:public TargetAbility{ +public: + int damage; + ADamager(int id, MTGCardInstance * card, ManaCost * _cost, int _damage, TargetChooser * _tc = NULL, int _tap = 1):TargetAbility(id,card, _tc, _cost,0,_tap),damage(_damage){ + if (!tc) tc = NEW DamageableTargetChooser(card); + } + int resolve(){ + Damageable * _target = tc->getNextDamageableTarget(); + GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,_target, damage); + return 1; + } + + const char * getMenuText(){ + return "Damage target"; + } + + +}; + +/* Can tap a target for a cost */ +class ATapper:public TargetAbility{ +public: + int damage; + ATapper(int id, MTGCardInstance * card, ManaCost * _cost, TargetChooser * _chooser):TargetAbility(id,card, _chooser, _cost){ + } + + int resolve(){ + MTGCardInstance * _target = tc->getNextCardTarget(); + if (_target){ + _target->tapped = true; + } + return 1; + } + + const char * getMenuText(){ + return "Tap target"; + } + +}; + +//Ability to untap a target +class AUntaper:public TargetAbility{ +public: + AUntaper(int _id, MTGCardInstance * card, ManaCost * _manacost, TargetChooser * _tc):TargetAbility(_id,card,_tc,_manacost){ + } + + int resolve(){ + MTGCardInstance * _target = tc->getNextCardTarget(); + if (_target){ + _target->tapped = 0; + } + return 1; + } + + const char * getMenuText(){ + return "Untap target"; + } + +}; + + +// Add life of gives damage if a given zone has more or less than [condition] cards at the beginning of [phase] +//Ex : the rack, ivory tower... +class ALifeZoneLink:public MTGAbility{ +public: + int phase; + int condition; + int life; + int controller; + int nbcards; + MTGGameZone * zone; + ALifeZoneLink(int _id ,MTGCardInstance * card, int _phase, int _condition, int _life = -1, int _controller = 0, MTGGameZone * _zone = NULL):MTGAbility(_id, card){ + phase = _phase; + condition = _condition; + controller = _controller; + life = _life; + zone = _zone; + if (zone == NULL){ + if (controller){ + zone = game->currentPlayer->game->hand; + }else{ + zone = game->opponent()->game->hand; + } + } + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == phase){ + if ((controller && game->currentPlayer == source->controller()) ||(!controller && game->currentPlayer != source->controller()) ){ + if ((condition < 0 && zone->nb_cards < - condition) ||(condition >0 && zone->nb_cards > condition)){ + int diff = zone->nb_cards - condition; + if (condition < 0) diff = - condition - zone->nb_cards; + if (life > 0){ + game->currentPlayer->life+=life*diff; + }else{ + game->mLayers->stackLayer()->addDamage(source,game->currentPlayer,-life*diff); + } + } + } + } + } +}; + +//Creatures that cannot attack if opponent has not a given type of land, and die if controller has not this type of land +//Ex : pirate ship... +class AStrongLandLinkCreature: public MTGAbility{ +public: + char land[20]; + AStrongLandLinkCreature(int _id, MTGCardInstance * _source, const char * _land):MTGAbility(_id, _source){ + sprintf(land,"%s",_land); + } + + void Update(float dt){ + if (source->isAttacker()){ + if (!game->opponent()->game->inPlay->hasType(land)){ + source->attacker=0; + source->tapped = 0; + //TODO Improve, there can be race conditions here + } + } + Player * player = source->controller(); + if(!player->game->inPlay->hasType(land)){ + player->game->putInGraveyard(source); + } + } +}; + +//Steal control of a target +class AControlStealAura: public MTGAbility{ +public: + Player * originalController; + AControlStealAura(int _id , MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source, _target){ + originalController = _target->controller(); + _target->changeController(game->currentlyActing()); + } + + int destroy(){ + MTGCardInstance * _target = (MTGCardInstance *) target; + if (_target->controller()->game->inPlay->hasCard(_target)){ //if the target is still in game -> spell was destroyed + _target->changeController(originalController); + } + return 1; + } + //TODO put it back into owners's graveyard if needed... +}; + + + + +//Same as StealControl Aura ???? Obsolete ? +class ATakeControlAura:public MTGAbility{ +public: + Player * previousController; + ATakeControlAura(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source,_target){ + previousController = _target->controller(); + previousController->game->putInZone(_target, previousController->game->inPlay, source->controller()->game->inPlay); + + } + + int destroy(){ + MTGCardInstance * _target = (MTGCardInstance *) target; + if (_target->controller()->game->inPlay->hasCard(_target)){ + _target->controller()->game->putInZone(_target, _target->controller()->game->inPlay, previousController->game->inPlay); + } + return 1; + } + +}; + +//Creatures that kill their blockers +//Ex : Cockatrice +class AOldSchoolDeathtouch:public MTGAbility{ +public: + MTGCardInstance * opponents[20]; + int nbOpponents; + AOldSchoolDeathtouch(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ + nbOpponents = 0; + } + + void Update(float dt){ + if (newPhase != currentPhase){ + if( newPhase == MTG_PHASE_COMBATDAMAGE){ + nbOpponents = 0; + MTGCardInstance * opponent = source->getNextOpponent(); + while (opponent && !opponent->hasSubtype("wall")){ + opponents[nbOpponents] = opponent; + nbOpponents ++; + opponent = source->getNextOpponent(opponent); + } + }else if (newPhase == MTG_PHASE_COMBATEND){ + for (int i = 0; i < nbOpponents ; i++){ + game->mLayers->stackLayer()->addPutInGraveyard(opponents[i]); + } + } + } + } + + int testDestroy(){ + if(!game->isInPlay(source) && currentPhase != MTG_PHASE_UNTAP){ + return 0; + }else{ + return MTGAbility::testDestroy(); + } + } +}; + + +//Converts a card to a creature (Aura) +class AConvertToCreatureAura:public MTGAbility{ +public: + AConvertToCreatureAura(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness):MTGAbility(_id, _source, _target){ + _target->setSubtype("creature"); + _target->power = _power; + _target->toughness = _toughness; + _target->life = _toughness; + //_target->afterDamage(); + _target->doDamageTest = 1; + } + + int destroy(){ + MTGCardInstance * _target = (MTGCardInstance *) target; + _target->removeType("creature"); + return 1; + } +}; + +/* +Specific Classes +*/ + +// 1092 Specific to Aladdin's Lamp +class AAladdinsLamp: public TargetAbility{ + public: + CardDisplay cd; + int nbcards; + int init; + AAladdinsLamp(int _id, MTGCardInstance * card):TargetAbility(_id,card){ + cost = NEW ManaCost(); + cost->x(); + cd = CardDisplay(1,game,SCREEN_WIDTH/2, SCREEN_HEIGHT/2,NULL); + MTGGameZone * zones[] = {game->currentPlayer->game->library}; + tc = NEW TargetZoneChooser(zones,1,source); + nbcards = 0; + init = 0; + } + + void Update(float dt){ + if (waitingForAnswer){ + if (!init){ + cd.resetObjects(); + int wished = game->currentlyActing()->getManaPool()->getConvertedCost(); + game->currentlyActing()->getManaPool()->pay(cost); + nbcards = 0; + MTGGameZone * library = game->currentlyActing()->game->library; + while (nbcards < wished && nbcards < library->nb_cards){ + cd.AddCard(library->cards[library->nb_cards - 1 - nbcards]); + nbcards++; + } + init = 1; + } + cd.Update(dt); + cd.CheckUserInput(dt); + } + } + + void Render(float dt){ + if (waitingForAnswer){ + cd.Render(); + } + } + + + int fireAbility(){ + source->tapped = 1; + MTGLibrary * library = game->currentlyActing()->game->library; + library->removeCard(tc->getNextCardTarget()); + library->shuffleTopToBottom(nbcards - 1 ); + library->addCard(tc->getNextCardTarget()); + init = 0; + return 1; + } + + int resolve(){return 1;}; + + +}; + + + + +//Ankh of Mishra +class AAnkhOfMishra: public MTGAbility{ +public: + int playerLands[2]; + AAnkhOfMishra(int id, MTGCardInstance * _source):MTGAbility(id, _source){ + for (int i=0; i< 2; i++){ + playerLands[i] = GameObserver::GetInstance()->players[i]->game->inPlay->countByType("land"); + } + } + + void Update(float dt){ + for (int i=0; i < 2; i++){ + int lands = GameObserver::GetInstance()->players[i]->game->inPlay->countByType("land"); + while (lands > playerLands[i]){ + GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,GameObserver::GetInstance()->players[i], 2); + playerLands[i]++; + } + } + } +}; + + + +// Armageddon Clock +class AArmageddonClock:public MTGAbility{ +public: + int counters; + ManaCost cost; + AArmageddonClock(int id, MTGCardInstance * _source):MTGAbility(id, _source){ + counters = 0; + int _cost[] = {MTG_COLOR_ARTIFACT, 4}; + cost = ManaCost(_cost,1); + } + + void Update(float dt){ + if (newPhase != currentPhase){ + if (newPhase == MTG_PHASE_UPKEEP && game->currentPlayer->game->inPlay->hasCard(source)){ + counters ++; + }else if (newPhase == MTG_PHASE_DRAW && counters > 0 && game->currentPlayer->game->inPlay->hasCard(source)){ //End of upkeep = beginning of draw + GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,GameObserver::GetInstance()->players[0], counters); + GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,GameObserver::GetInstance()->players[1], counters); + } + } + } + int isReactingToClick(MTGCardInstance * _card){ + if (counters > 0 && _card == source && currentPhase == MTG_PHASE_UPKEEP){ + if (game->currentlyActing()->getManaPool()->canAfford( & cost)){ + return 1; + } + } + return 0; + } + + int reactToClick(MTGCardInstance * _card){ + if (!isReactingToClick( _card)) return 0; + game->currentlyActing()->getManaPool()->pay(& cost); + counters --; + return 1; + } +}; + + +//Black Vise +class ABlackVise: public MTGAbility{ +public: + int nbcards; + ABlackVise(int id, MTGCardInstance * _source):MTGAbility(id, _source){ + nbcards = game->opponent()->game->hand->nb_cards; + } + + void Update(float dt){ + if (newPhase == MTG_PHASE_UPKEEP && GameObserver::GetInstance()->opponent()->game->inPlay->hasCard(source)){ + nbcards = game->currentPlayer->game->hand->nb_cards; + } + if (newPhase != currentPhase && newPhase == MTG_PHASE_DRAW && GameObserver::GetInstance()->opponent()->game->inPlay->hasCard(source)){ + if ( nbcards > 4) game->mLayers->stackLayer()->addDamage(source,game->currentPlayer, nbcards - 4); + } + } +}; + + +//Channel +class AChannel:public ActivatedAbility{ +public: + + AChannel(int _id, MTGCardInstance * card):ActivatedAbility(_id, card,0,0,0){ + } + + int isReactingToClick(PlayGuiObject * object){ + if (object->type == GUI_AVATAR){ + Player * player = ((GuiAvatar *)object)->player; + if (player == source->controller()) return 1; + } + return 0; + } + + int resolve(){ + source->controller()->life--; + source->controller()->getManaPool()->add(MTG_COLOR_ARTIFACT, 1); + return 1; + } + + int testDestroy(){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP) return 1; + currentPhase = newPhase; + return 0; + } +}; + + +// Clockwork Beast +class AClockworkBeast:public MTGAbility{ +public: + int counters; + ManaCost cost; + AClockworkBeast(int id, MTGCardInstance * _source):MTGAbility(id, _source){ + counters = 7; + ((MTGCardInstance *)target)->power+=7; + int _cost[] = {MTG_COLOR_ARTIFACT, 1}; + cost = ManaCost(_cost,1); + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_COMBATEND){ + if (((MTGCardInstance *)source)->isAttacker() || ((MTGCardInstance *)source)->isDefenser()){ + counters--; + ((MTGCardInstance *)target)->power-=1; + } + } + } + int isReactingToClick(MTGCardInstance * _card){ + if (counters < 7 && _card == source && currentPhase == MTG_PHASE_UPKEEP && game->currentPlayer->game->inPlay->hasCard(source)){ + if (game->currentlyActing()->getManaPool()->canAfford( & cost)){ + return 1; + } + } + return 0; + } + + int reactToClick(MTGCardInstance * _card){ + if (!isReactingToClick( _card)) return 0; + game->currentlyActing()->getManaPool()->pay(& cost); + counters ++; + ((MTGCardInstance *)target)->power++; + ((MTGCardInstance *)target)->tapped = 1; + return 1; + } +}; + +//1102: Conservator +class AConservator: public MTGAbility{ +public: + int canprevent; + ManaCost cost; + AConservator(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ + canprevent = 0; + int _cost[] = {MTG_COLOR_ARTIFACT, 2}; + cost = ManaCost(_cost, 1); + } + + int alterDamage(Damage * damage){ + if (canprevent && damage->target == source->controller()){ + if (damage->damage >= canprevent){ + damage->damage-=canprevent; + canprevent = 0; + }else{ + canprevent-=damage->damage; + damage->damage = 0; + } + } + return 1; + } + int alterDamage(){ + if (canprevent){ + ActionStack * stack = game->mLayers->stackLayer(); + for (int i = stack->mCount-1; i>=0; i--){ + if (!canprevent) return 1; + Interruptible * current = ((Interruptible *)stack->mObjects[i]); + if (current->type == ACTION_DAMAGE && current->state==NOT_RESOLVED){ + Damage * damage = (Damage *)current; + alterDamage(damage); + }else if (current->type == ACTION_DAMAGES && current->state == NOT_RESOLVED){ + DamageStack * damages = (DamageStack *)current; + for (int j = damages->mCount-1;j >=0; j--){ + alterDamage(((Damage *)damages->mObjects[j])); + } + } + } + } + return 1; + } + + void Update(float dt){ + alterDamage(); + } + + int isReactingToClick(MTGCardInstance * _card){ + if ( _card == source && game->currentlyActing()->game->inPlay->hasCard(source) && !_card->isTapped()){ + if (game->currentlyActing()->getManaPool()->canAfford( & cost)){ + return 1; + } + } + return 0; + } + + int reactToClick(MTGCardInstance * _card){ + if (!isReactingToClick( _card)) return 0; + game->currentlyActing()->getManaPool()->pay(& cost); + source->tapped = 1; + canprevent = 2; + alterDamage(); + return 1; + } + +}; + + +//Creature bond +class ACreatureBond:public TriggeredAbility{ +public: + int resolved; + ACreatureBond(int _id, MTGCardInstance * _source, MTGCardInstance * _target):TriggeredAbility(_id,_source,_target){ + resolved = 1; + } + + int trigger(){ + MTGCardInstance * _target = (MTGCardInstance *) target; + for (int i = 0; i < 2; i++){ + if (game->players[i]->game->graveyard->hasCard(_target)) return 1; + } + return 0; + } + + int resolve(){ + MTGCardInstance * _target = (MTGCardInstance *) target; + game->mLayers->stackLayer()->addDamage(source,_target->controller(),_target->toughness); + resolved = 1; + return 1; + } + + int testDestroy(){ + MTGCardInstance * _target = (MTGCardInstance *)target; + if(_target->controller()->game->graveyard->hasCard(_target) && !resolved){ + return 0; + }else{ + return TriggeredAbility::testDestroy(); + } + } +}; + +//1105: Dingus Egg +class ADingusEgg: public MTGAbility{ +public: + int playerLands[2]; + ADingusEgg(int id, MTGCardInstance * _source):MTGAbility(id, _source){ + for (int i=0; i< 2; i++){ + playerLands[i] = GameObserver::GetInstance()->players[i]->game->inPlay->countByType("land"); + } + } + + void Update(float dt){ + for (int i=0; i < 2; i++){ + int lands = GameObserver::GetInstance()->players[i]->game->inPlay->countByType("land"); + while (lands < playerLands[i]){ + GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,GameObserver::GetInstance()->players[i], 2); + playerLands[i]--; + } + } + } +}; + + + +//1106 DisruptingScepter +class ADisruptingScepter:public TargetAbility{ +public: + ADisruptingScepter(int id, MTGCardInstance * _source):TargetAbility(id,_source){ + MTGGameZone * zones[] = {GameObserver::GetInstance()->opponent()->game->hand}; + tc = NEW TargetZoneChooser(zones,1,_source); + int _cost[] = {MTG_COLOR_ARTIFACT, 3}; + cost = NEW ManaCost(_cost,1); + } + + void Update(float dt){ + if (game->opponent()->isAI()){ + if(waitingForAnswer){ + MTGCardInstance * card = ((AIPlayer *)game->opponent())->chooseCard(tc, source); + if (card) tc->toggleTarget(card); + if (!card || tc->targetsReadyCheck() == TARGET_OK) waitingForAnswer = 0; + } + TargetAbility::Update(dt); + }else{ + TargetAbility::Update(dt); + } + } + + int resolve(){ + game->opponent()->game->putInGraveyard(tc->getNextCardTarget()); + return 1; + } + + +}; + + +//1108 Ebony Horse +class AEbonyHorse:public TargetAbility{ +public: + + AEbonyHorse(int _id, MTGCardInstance * _source):TargetAbility(_id,_source, NEW CreatureTargetChooser()){ + int _cost[] = {MTG_COLOR_ARTIFACT, 2}; + cost = NEW ManaCost(_cost,1); + } + + int resolve(){ + tc->getNextCardTarget()->attacker = 0; + return 1; + } + +}; + +//1345 Farmstead +class AFarmstead:public ActivatedAbility{ +public: + AFarmstead(int _id, MTGCardInstance * source, MTGCardInstance * _target):ActivatedAbility(_id, source,0,1,0){ + int _cost[] = {MTG_COLOR_WHITE, 2}; + cost = NEW ManaCost(_cost,1); + target = _target; + } + + int isReactingToClick(MTGCardInstance * card){ + if (!ActivatedAbility::isReactingToClick(card)) return 0; + if (currentPhase == MTG_PHASE_UPKEEP) return 1; + return 0; + } + + int resolve(){ + source->controller()->life++; + return 1; + } + +}; + +//1110 Glasses of Urza +class AGlassesOfUrza:public MTGAbility{ +public: + CardDisplay * display; + AGlassesOfUrza(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ + display = NEW CardDisplay(0, game,SCREEN_WIDTH/2, SCREEN_HEIGHT/2,NULL); + } + + void Update(float dt){ + if(modal){ + display->Update(dt); + } + } + + void CheckUserInput(float dt){ + if (modal){ + display->CheckUserInput(dt); + JGE * mEngine = JGE::GetInstance(); + if (mEngine->GetButtonClick(PSP_CTRL_CROSS)){ + modal = 0; + } + } + } + + void Render(float dt){ + if (modal){ + display->Render(); + } + + } + int isReactingToClick(MTGCardInstance * card){ + if ( card == source){ + if (game->currentlyActing()->game->isInPlay(card) && !source->isTapped()){ + return 1; + } + } + return 0; + } + + int reactToClick(MTGCardInstance * card){ + if (!isReactingToClick(card)) return 0; + source->tapped = 1; + modal = 1; + return 1; + } + +}; + +//1112 Howling Mine +class AHowlingMine:public MTGAbility{ +public: + AHowlingMine(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){} + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_DRAW && !source->tapped){ + game->mLayers->stackLayer()->addDraw(game->currentPlayer); + } + } +}; + +//1119 Jayemdae Tome +class AJayemdaeTome:public ActivatedAbility{ +public: + AJayemdaeTome(int _id, MTGCardInstance * card):ActivatedAbility(_id, card){ + int _cost[] = {MTG_COLOR_ARTIFACT, 4}; + cost = NEW ManaCost(_cost,1); + } + + int resolve(){ + game->mLayers->stackLayer()->addDraw(source->controller()); + return 1; + } +}; + + +//Living Artifact +class ALivingArtifact:public MTGAbility{ +public: + int usedThisTurn; + int counters; + Damage * latest; + ALivingArtifact(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id,_source,_target){ + usedThisTurn = 0; + counters = 0; + latest = NULL; + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP) usedThisTurn = 0; + Damage * damage = ((Damage *)game->mLayers->stackLayer()->getNext(latest,ACTION_DAMAGE,RESOLVED_OK)); + while (damage){ + if (damage->target == source->controller()){ + counters += damage->damage; + } + latest = damage; + damage = ((Damage *)game->mLayers->stackLayer()->getNext(damage,ACTION_DAMAGE,RESOLVED_OK)); + } + } + + int isReactingtoclick(MTGCardInstance * card){ + if (currentPhase == MTG_PHASE_UPKEEP && card == source && game->currentPlayer == source->controller() && counters && !usedThisTurn){ + return 1; + } + return 0; + } + + int reactToClick(MTGCardInstance * card){ + source->controller()->life+=1; + counters--; + usedThisTurn = 1; + return 1; + } + +}; + +//Lord of the Pit +class ALordOfThePit: public TargetAbility{ +public: + int paidThisTurn; + ALordOfThePit(int _id, MTGCardInstance * source):TargetAbility(_id, source, NEW CreatureTargetChooser(),0,1,0){ + paidThisTurn = 1; + } + + void Update(float dt){ + if (newPhase != currentPhase && source->controller() == game->currentPlayer){ + if (newPhase == MTG_PHASE_UNTAP){ + paidThisTurn = 0; + }else if( newPhase == MTG_PHASE_UPKEEP + 1 && !paidThisTurn){ + game->mLayers->stackLayer()->addDamage(source,source->controller(), 7); + } + } + TargetAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card){ + if (currentPhase != MTG_PHASE_UPKEEP || paidThisTurn) return 0; + return TargetAbility::isReactingToClick(card); + } + + int resolve(){ + MTGCardInstance * card = tc->getNextCardTarget(); + if (card && card != source && card->controller() == source->controller()){ + card->controller()->game->putInGraveyard(card); + paidThisTurn = 1; + return 1; + } + return 0; + } + +}; +//1143 Animate Dead +class AAnimateDead:public MTGAbility{ +public: + AAnimateDead(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source, _target){ + MTGCardInstance * card = _target; + card->power--; + card->life = card->toughness; + //Put the card in play again, with all its abilities ! + //AbilityFactory af; + Spell * spell = NEW Spell(card); + //af.addAbilities(game->mLayers->actionLayer()->getMaxId(), spell); + source->controller()->game->putInZone(card, _target->controller()->game->graveyard, source->controller()->game->stack); + spell->resolve(); + delete spell; + } + + int destroy(){ + MTGCardInstance * card = (MTGCardInstance *) target; + card->power++; + return 1; + } +}; + +//1144 Bad Moon, 1341 Crusade +class ABadMoon:public ListMaintainerAbility{ +public: + int color; + ABadMoon(int _id, MTGCardInstance * _source, int _color = MTG_COLOR_BLACK):ListMaintainerAbility(_id, _source),color(_color){ + } + + int canBeInList(MTGCardInstance * card){ + if (card->isACreature() && card->hasColor(color)) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + card->power += 1; + card->addToToughness(1); + return 1; + } + + int removed(MTGCardInstance * card){ + card->power -= 1; + card->addToToughness(-1); + return 1; + } + +}; + + +//1159 Erg Raiders +class AErgRaiders:public MTGAbility{ +public: + int init; + int dealDamage; + AErgRaiders(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ + init = 0; + dealDamage = 0; + } + + void Update(float dt){ + if (newPhase != currentPhase){ + Player * controller = source->controller(); + if (newPhase == MTG_PHASE_COMBATDAMAGE && game->currentPlayer == controller){ + if (!source->isAttacker() && init){ + dealDamage = 1; + } + }else if (newPhase == MTG_PHASE_UNTAP && game->currentPlayer != controller){ + if (dealDamage){ + game->mLayers->stackLayer()->addDamage(source, controller,2); + } + init = 1; + dealDamage = 0; + } + } + + } +}; + +//Fastbond +class AFastbond:public TriggeredAbility{ +public: + int alreadyPlayedALand; + AFastbond(int _id, MTGCardInstance * card):TriggeredAbility(_id, card){ + alreadyPlayedALand = 0; + } + + void Update(float dt){ + if (newPhase!=currentPhase && newPhase == MTG_PHASE_UNTAP){ + alreadyPlayedALand = 0; + } + TriggeredAbility::Update(dt); + } + + int trigger(){ + if(source->controller()->canPutLandsIntoPlay==0) return 1; + return 0; + } + + int resolve(){ + source->controller()->canPutLandsIntoPlay = 1; + if (alreadyPlayedALand){ + game->mLayers->stackLayer()->addDamage(source, source->controller(), 1); + } + alreadyPlayedALand = 1; + return 1; + } +}; + + + +//1165 Hypnotic Specter +class AHypnoticSpecter:public MTGAbility{ +public: + int nbdamagesthisturn[2]; + AHypnoticSpecter(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ + currentPhase = -1; + for (int i = 0; i < 2; i++){ + nbdamagesthisturn[i] = 0; + } + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ + for (int i = 0; i < 2; i++){ + nbdamagesthisturn[i] = 0; + } + } + + ActionStack * as = game->mLayers->stackLayer(); + int nbdamages[2]; + for (int i = 0; i < 2; i++){ + nbdamages[i] = 0; + } + + Damage * current = ((Damage *)as->getNext(NULL,ACTION_DAMAGE,RESOLVED_OK)); + while(current){ + if (current->source == source){ + for (int j=0; j < 2; j++){ + if(current->target == game->players[j]) nbdamages[j]++; + } + } + current = ((Damage *)as->getNext(current,ACTION_DAMAGE,RESOLVED_OK)); + + } + + for (int i = 0; i < 2; i++){ + while(nbdamages[i] > nbdamagesthisturn[i]){ + nbdamagesthisturn[i]++; + game->players[i]->game->discardRandom(game->players[i]->game->hand); + } + } + + + } + +}; + +//1117 Jandor's Ring +class AJandorsRing:public ActivatedAbility{ +public: + AJandorsRing(int _id, MTGCardInstance * _source):ActivatedAbility(_id,_source, NEW ManaCost()){ + cost->add(MTG_COLOR_ARTIFACT, 2); + } + + int isReactingToClick(MTGCardInstance * card){ + if (!source->controller()->game->hand->hasCard(source->controller()->game->library->lastCardDrawn)) return 0; + return ActivatedAbility::isReactingToClick(card); + } + + int resolve(){ + source->controller()->game->putInGraveyard(source->controller()->game->library->lastCardDrawn); + game->mLayers->stackLayer()->addDraw(source->controller()); + return 1; + } + +}; + + +//Kudzu. +//What happens when there are no targets ??? +class AKudzu: public TargetAbility{ +public: + int previouslyTapped; + AKudzu(int _id, MTGCardInstance * card, MTGCardInstance * _target):TargetAbility(_id,card, NEW TypeTargetChooser("land",card)){ + tc->toggleTarget(_target); + target = _target; + previouslyTapped = 0; + if (_target->tapped) previouslyTapped = 1; + } + + + void Update(float dt){ + MTGCardInstance * _target = (MTGCardInstance *)target; + if (!_target->tapped){ + previouslyTapped = 0; + }else if (!previouslyTapped){ +#if defined (WIN32) || defined (LINUX) + OutputDebugString("Kudzu Strikes !\n"); +#endif + MTGCardInstance * _target = (MTGCardInstance *)target; + _target->controller()->game->putInGraveyard(_target); + reactToClick(source); // ???? + } + TargetAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card){ + MTGCardInstance * _target = (MTGCardInstance *)target; + if (card == source && (!_target || !_target->isInPlay())){ +#if defined (WIN32) || defined (LINUX) + OutputDebugString("Kudzu Reacts to click !\n"); +#endif + return 1; + } + return 0; + } + +/* + int reactToClick(MTGCardInstance * card){ + if (!waitingForAnswer) { + }else{ + tc->toggleTarget(card); + } + return 1; + } + */ + + int resolve(){ + target = tc->getNextCardTarget(); + source->target = (MTGCardInstance *) target; + previouslyTapped = 0; + if (source->target->tapped) previouslyTapped = 1; + return 1; + } + + int testDestroy(){ + GameObserver * g = GameObserver::GetInstance(); + int stillLandsInPlay = 0; + for (int i = 0; i < 2; i++){ + if (game->players[i]->game->inPlay->hasType("land")) stillLandsInPlay = 1; + } + if (!stillLandsInPlay){ + source->controller()->game->putInGraveyard(source); + return 1; + } + + if (!game->isInPlay(source)){ + return 1; + } + + return 0; + } + + +}; + +//Millstone +class AMillstone:public TargetAbility{ +public: + AMillstone(int _id, MTGCardInstance * card):TargetAbility(_id,card, NEW PlayerTargetChooser(), NEW ManaCost()){ + cost->add(MTG_COLOR_ARTIFACT, 2); + } + + int resolve(){ + Player * player = tc->getNextPlayerTarget(); + if (!player) return 0; + MTGLibrary * library = player->game->library; + for (int i = 0; i < 2; i++){ + if (library->nb_cards) + player->game->putInZone(library->cards[library->nb_cards-1],library, player->game->graveyard); + } + return 1; + } + +}; + +//1170: Nightmare +class ANightmare:public ListMaintainerAbility{ +public: + ANightmare(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ + } + + int canBeInList(MTGCardInstance * card){ + if (source->controller()->game->inPlay->hasCard(card) && card->hasType("swamp") ) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + source->power += 1; + source->addToToughness(1); + return 1; + } + + int removed(MTGCardInstance * card){ + source->power -= 1; + source->addToToughness(-1); + return 1; + } + +}; + + + +//1172 Pestilence +class APestilence: public ActivatedAbility{ +public: + APestilence(int _id, MTGCardInstance * card):ActivatedAbility(_id, card, NEW ManaCost(), 0,0){ + cost->add(MTG_COLOR_BLACK, 1); + } + + void Update(float dt){ + if (newPhase !=currentPhase && newPhase == MTG_PHASE_EOT){ + if (!game->players[0]->game->inPlay->hasType("creature") && !game->players[1]->game->inPlay->hasType("creature")){ + source->controller()->game->putInGraveyard(source); + } + } + } + + int resolve(){ + for (int i = 0; i < 2 ; i++){ + MTGInPlay * inplay = game->players[i]->game->inPlay; + for (int j = inplay->nb_cards - 1 ; j >=0; j--){ + if (inplay->cards[j]->isACreature()) game->mLayers->stackLayer()->addDamage(source,inplay->cards[j],1); + } + game->mLayers->stackLayer()->addDamage(source,game->players[i],1); + } + return 1; + } + +}; + +//Plague Rats and similar. Power and toughness equal to number of cards that share a name +class APlagueRats:public ListMaintainerAbility{ +public: + string name; + APlagueRats(int _id, MTGCardInstance * _source, const char * _name):ListMaintainerAbility(_id,_source){ + name = _name; + std::transform(name.begin(), name.end(), name.begin(),::tolower ); + } + + int canBeInList(MTGCardInstance * card){ + if (card == source) return 0; + string compared = card->name; + std::transform( compared.begin(), compared.end(), compared.begin(),::tolower ); + if (name.compare(compared) == 0) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + source->power += 1; + source->addToToughness(1); + return 1; + } + + int removed(MTGCardInstance * card){ + source->power -= 1; + source->addToToughness(-1); + return 1; + } + +}; + +//Power Leak +class APowerLeak:public TriggeredAbility{ +public: + int damagesToDealThisTurn; + ManaCost cost; + APowerLeak(int _id, MTGCardInstance * _source, MTGCardInstance * _target):TriggeredAbility(_id, _source, _target){ + cost.add(MTG_COLOR_ARTIFACT, 1); + damagesToDealThisTurn = 0; + } + + void Update(float dt){ + MTGCardInstance * _target = (MTGCardInstance *) target; + if (newPhase != currentPhase && newPhase == MTG_PHASE_UPKEEP && _target->controller() == game->currentPlayer){ + damagesToDealThisTurn = 2; + } + TriggeredAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card){ + MTGCardInstance * _target = (MTGCardInstance *) target; + if (damagesToDealThisTurn && currentPhase == MTG_PHASE_UPKEEP && card==source && _target->controller() == game->currentPlayer){ + if (game->currentPlayer->getManaPool()->canAfford(& cost)) return 1; + } + return 0; + } + + int reactToclick(MTGCardInstance * card){ + game->currentPlayer->getManaPool()->pay( & cost); + damagesToDealThisTurn--; + return 1; + } + + int trigger(){ + MTGCardInstance * _target = (MTGCardInstance *) target; + if (newPhase != currentPhase && newPhase == MTG_PHASE_DRAW && _target->controller() == game->currentPlayer){ + if (damagesToDealThisTurn) return 1; + } + return 0; + } + + int resolve(){ + MTGCardInstance * _target = (MTGCardInstance *) target; + game->mLayers->stackLayer()->addDamage(source,_target->controller(), damagesToDealThisTurn); + return 1; + } +}; + +//Power Surge +class APowerSurge:public TriggeredAbility{ +public: + int totalLands; + APowerSurge(int _id, MTGCardInstance * _source):TriggeredAbility(_id,_source){ + totalLands = 0; + } + + int trigger(){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_EOT){ + //That's ugly but untapped land at the beginning of the turn are opponent's untapped lands at the end of the turn + totalLands = 0; + MTGInPlay * inPlay = game->opponent()->game->inPlay; + for (int i = 0; i < inPlay->nb_cards; i++){ + MTGCardInstance * card = inPlay->cards[i]; + if (!card->tapped && card->hasType("land")){ + totalLands++; + } + } + } + if (newPhase != currentPhase && newPhase == MTG_PHASE_UPKEEP && totalLands){ + return 1; + } + return 0; + } + + int resolve(){ + if (totalLands) game->mLayers->stackLayer()->addDamage(source,game->currentPlayer,totalLands); + totalLands = 0; + return 1; + } +}; + +//1175 Royal Assassin +class ARoyalAssassin:public TargetAbility{ +public: + + ARoyalAssassin(int _id, MTGCardInstance * _source):TargetAbility(_id,_source, NEW CreatureTargetChooser()){ + } + + int resolve(){ + MTGCardInstance * _target = tc->getNextCardTarget(); + if(_target && _target->tapped){ + _target->controller()->game->putInGraveyard(_target); + return 1; + } + return 0; + } + +}; + + +//1176 Sacrifice +class ASacrifice:public InstantAbility{ +public: + ASacrifice(int _id, MTGCardInstance * _source, MTGCardInstance * _target):InstantAbility(_id, _source){ + target = _target; + } + + int resolve(){ + MTGCardInstance * _target = (MTGCardInstance *) target; + if (_target->isInPlay()){ + game->currentlyActing()->game->putInGraveyard(_target); + int x = _target->getManaCost()->getConvertedCost(); + game->currentlyActing()->getManaPool()->add(MTG_COLOR_BLACK, x); + } + return 1; + } + +}; + +//1178 Scavenging Ghoul +class AScavengingGhoul:public MTGAbility{ +public: + int counters; + AScavengingGhoul(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source, _target){ + counters = 0; + } + + + void Update(float dt){ + //TODO + } + + int isReactingToClick(MTGCardInstance * _card){ + if (counters > 0 && _card == source && game->currentlyActing()->game->inPlay->hasCard(source)){ + return 1; + } + return 0; + } + + int reactToClick(MTGCardInstance * _card){ + if (!isReactingToClick( _card)) return 0; + counters--; + source->regenerate(); + return 1; + } + +}; + +//1218 Psychic Venom +class APsychicVenom:public MTGAbility{ +public: + int tapped; + APsychicVenom(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source,_target){ + tapped = _target->tapped; + } + + void Update(float dt){ + MTGCardInstance* _target = (MTGCardInstance* )target; + int newState = _target->isTapped(); + if (newState != tapped && newState == 1){ + game->mLayers->stackLayer()->addDamage(source,_target->controller(),2); + } + tapped = newState; + } +}; + + +//1221 Serendib Efreet +class ASerendibEfreet:public MTGAbility{ +public: + ASerendibEfreet(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ + } + + void Update(float dt){ + if (newPhase == MTG_PHASE_UPKEEP && newPhase != currentPhase && game->currentPlayer == source->controller()){ + game->mLayers->stackLayer()->addDamage(source,game->currentPlayer,1); + } + } +}; + + +//1235 Aspect of Wolf +class AAspectOfWolf:public ListMaintainerAbility{ +public: + int color; + AAspectOfWolf(int _id, MTGCardInstance * _source, MTGCardInstance * _target):ListMaintainerAbility(_id, _source, _target){ + } + + int canBeInList(MTGCardInstance * card){ + + if (card->controller() == source->controller() && card->hasType("forest")) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + MTGCardInstance * _target = (MTGCardInstance *) target; + int size = cards.size(); + if (size % 2 == 0){ + _target->power += 1; + }else{ + _target->addToToughness(1); + } + return 1; + } + + int removed(MTGCardInstance * card){ + MTGCardInstance * _target = (MTGCardInstance *) target; + int size = cards.size(); + if (size % 2 == 1){ + _target->power -= 1; + }else{ + _target->addToToughness(-1); + } + return 1; + } + +}; + +//1276 Wanderlust, 1148 Cursed Lands +class AWanderlust:public TriggeredAbility{ +public: + AWanderlust(int _id, MTGCardInstance * _source, MTGCardInstance * _target):TriggeredAbility(_id,_source, _target){} + + int trigger(){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_UPKEEP && ((MTGCardInstance *) target)->controller()==game->currentPlayer){ + return 1; + } + return 0; + } + + int resolve(){ + game->mLayers->stackLayer()->addDamage(source,((MTGCardInstance *) target)->controller(),1); + return 1; + } +}; + +//1280 Atog +class AAtog:public TargetAbility{ +public: + Player * currentController; + int counters; + AAtog(int _id, MTGCardInstance * _source):TargetAbility(_id, _source,NULL, NULL, 0,0){ + currentController = source->controller(); + MTGGameZone * zones[] = {currentController->game->inPlay}; + tc = NEW TypeTargetChooser("artifact", zones, 1, source); + counters = 0; + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ + for (int i = 0; i < counters; i++){ + source->power-=2; + source->addToToughness(-2); + } + counters = 0; + } + TargetAbility::Update(dt); + Player * newController = source->controller(); + if (newController != currentController){ + delete tc; + MTGGameZone * zones[] = {newController->game->inPlay}; //In case Atog's controller changes + tc = NEW TypeTargetChooser("artifact", zones, 1, source); + currentController = newController; + } + } + + int resolve(){ + tc->getNextCardTarget()->controller()->game->putInGraveyard(tc->getNextCardTarget()); + source->power+=2; + source->addToToughness(2); + counters ++; + return 1; + } +}; + + + + +//1284 Dragon Whelp +class ADragonWhelp: public APowerToughnessModifierUntilEndOfTurn{ +public: + ADragonWhelp(int id, MTGCardInstance * card):APowerToughnessModifierUntilEndOfTurn(id, card, card, 1, 0, NEW ManaCost()){ + cost->add(MTG_COLOR_RED, 1); + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP && counters > 3){ + source->controller()->game->putInGraveyard(source); + } + APowerToughnessModifierUntilEndOfTurn::Update(dt); + } + +}; + +//1288 EarthBind +class AEarthbind:public ABasicAbilityModifier{ +public: + AEarthbind(int _id, MTGCardInstance * _source, MTGCardInstance * _target):ABasicAbilityModifier(_id,_source,_target,FLYING,0){ + if (value_before_modification) game->mLayers->stackLayer()->addDamage(source,target,2); + } +}; + +//1291 Fireball +class AFireball:public InstantAbility{ +public: + AFireball(int _id, MTGCardInstance * card, Spell * spell, int x):InstantAbility(_id, card){ + int nbtargets = spell->cursor; + int totaldamage = x+1-nbtargets; + int individualdamage = totaldamage / nbtargets; + Damageable * _target = spell->getNextDamageableTarget(); + while(_target){ + game->mLayers->stackLayer()->addDamage(source,_target,individualdamage); + _target = spell->getNextDamageableTarget(_target); + } + } +}; + +//1245 ForceOfNature +class AForceOfNature:public ActivatedAbility{ +public: + int dealDamageThisTurn; + AForceOfNature(int _id, MTGCardInstance * card):ActivatedAbility(_id,card, NEW ManaCost(),1,0){ + dealDamageThisTurn = 0; + cost->add(MTG_COLOR_GREEN,4); + } + + void Update(float dt){ + if (newPhase !=currentPhase){ + if (newPhase == MTG_PHASE_UNTAP){ + dealDamageThisTurn = 1; + }else if (newPhase == MTG_PHASE_DRAW && dealDamageThisTurn && game->currentPlayer==source->controller() ){ + game->mLayers->stackLayer()->addDamage(source,source->controller(),8); + } + } + ActivatedAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card){ + return (dealDamageThisTurn && currentPhase == MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card)); + } + + int resolve(){ + dealDamageThisTurn = 0; + return 1; + } +}; + +//1301 KeldonWarlord +class AKeldonWarlord:public ListMaintainerAbility{ +public: + AKeldonWarlord(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ + } + + int canBeInList(MTGCardInstance * card){ + if (source->controller()->game->inPlay->hasCard(card) && card->isACreature() && !card->hasType("wall") ) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + source->power += 1; + source->addToToughness(1); + return 1; + } + + int removed(MTGCardInstance * card){ + source->power -= 1; + source->addToToughness(-1); + return 1; + } + +}; + +//1302 : Kird Ape +class AKirdApe:public MTGAbility{ +public: + int init; + AKirdApe(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ + init = 0; + } + + void Update(float dt){ + if (source->controller()->game->inPlay->hasType("forest")){ + if(!init){ + init = 1; + source->power+=1; + source->addToToughness(2); + } + }else{ + if (init){ + init = 0; + source->power-=1; + source->addToToughness(-2); + } + } + } +}; + +//1309 Orcish Artilery +class AOrcishArtillery: public ADamager{ +public: + AOrcishArtillery(int _id,MTGCardInstance * card): ADamager(_id, card, NEW ManaCost(), 2){ + } + + int resolve(){ + ADamager::resolve(); + game->mLayers->stackLayer()->addDamage(source,source->controller(), 3); + return 1; + } + +}; + +//1310 Orcish Oriflame +class AOrcishOriflame:public ListMaintainerAbility{ +public: + int color; + AOrcishOriflame(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ + } + + int canBeInList(MTGCardInstance * card){ + if (source->controller() == game->currentPlayer && game->currentPlayer->game->inPlay->hasCard(card) && card->attacker) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + card->power += 1; + return 1; + } + + int removed(MTGCardInstance * card){ + card->power -= 1; + return 1; + } + +}; + +//1334 Castle +class ACastle:public ListMaintainerAbility{ +public: + ACastle(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ + } + + int canBeInList(MTGCardInstance * card){ + if (source->controller()->game->inPlay->hasCard(card) && card->isACreature() && !card->isAttacker() && !card->tapped) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + card->addToToughness(2); + return 1; + } + + int removed(MTGCardInstance * card){ + card->addToToughness(-2); + return 1; + } +}; + + +//1351 Island Sanctuary +class AIslandSanctuary:public MTGAbility{ +public: + int initThisTurn; + AIslandSanctuary(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ + initThisTurn = 0; + } + + void Update(float dt){ + if (currentPhase == MTG_PHASE_UNTAP && game->currentPlayer == source->controller()) initThisTurn = 0; + + if (initThisTurn && currentPhase == MTG_PHASE_COMBATATTACKERS && game->currentPlayer != source->controller()){ + MTGGameZone * zone = game->currentPlayer->game->inPlay; + for (int i = 0; i < zone->nb_cards; i++){ + MTGCardInstance * card = zone->cards[i]; + if (card->isAttacker() && !card->basicAbilities[FLYING] && !card->basicAbilities[ISLANDWALK]) card->attacker=0; + } + } + } + + int isReactingToClick(MTGCardInstance * card){ + if (card==source && game->currentPlayer == card->controller() && currentPhase == MTG_PHASE_DRAW){ + Interruptible * action = game->mLayers->stackLayer()->_(-1); + if (action->type == ACTION_DRAW) return 1; + } + return 0; + } + + + int reactToClick(MTGCardInstance * card){ + if (!isReactingToClick(card)) return 0; + game->mLayers->stackLayer()->Remove(game->mLayers->stackLayer()->_(-1)); + initThisTurn = 1; + return 1; + } +}; + +//1352 Karma +class AKarma: public TriggeredAbility{ +public: + AKarma(int _id, MTGCardInstance * _source):TriggeredAbility(_id, _source){ + } + + int trigger(){ + if (newPhase != currentPhase && newPhase == MTG_PHASE_UPKEEP) return 1; + return 0; + } + + int resolve(){ + int totaldamage = 0; + MTGGameZone * zone = game->currentPlayer->game->inPlay; + for (int i = 0; i < zone->nb_cards; i++){ + if (zone->cards[i]->hasType("swamp")) totaldamage++;; + } + if (totaldamage) game->mLayers->stackLayer()->addDamage(source,game->currentPlayer, totaldamage); + return 1; + } +}; + +//1355 Norther Paladin +class ANorthernPaladin:public TargetAbility{ +public: + ANorthernPaladin(int _id, MTGCardInstance * card):TargetAbility(_id, card){ + int _cost[] = {MTG_COLOR_WHITE, 2}; + cost = NEW ManaCost(_cost,1); + tc = NEW TargetChooser(); + } + + int resolve(){ + MTGCardInstance * card = tc->getNextCardTarget(); + if (card->hasColor(MTG_COLOR_BLACK)){ + card->controller()->game->putInGraveyard(card); + return 1; + } + return 0; + } + + +}; + +//Sedge Troll +class ASedgeTroll:public MTGAbility{ +public: + int init; + ASedgeTroll(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ + init = 0; + } + + void Update(float dt){ + if (source->controller()->game->inPlay->hasType("swamp")){ + if(!init){ + init = 1; + source->power+=1; + source->addToToughness(1); + } + }else{ + if (init){ + init = 0; + source->power-=1; + source->addToToughness(-1); + } + } + } +}; + +//Soul Net +class ASoulNet:public ActivatedAbility{ +public: + PutInGraveyard * latest; + PutInGraveyard * newDead; + ASoulNet(int _id, MTGCardInstance * card):ActivatedAbility(_id, card,0,0,0){ + int _cost[] = {MTG_COLOR_ARTIFACT, 1}; + cost = NEW ManaCost(_cost,1); + latest = ((PutInGraveyard *) GameObserver::GetInstance()->mLayers->stackLayer()->getPrevious(NULL,ACTION_PUTINGRAVEYARD,RESOLVED_OK)); + newDead = latest; + } + + int isReactingToClick(MTGCardInstance * card){ + newDead = ((PutInGraveyard *) GameObserver::GetInstance()->mLayers->stackLayer()->getPrevious(NULL,ACTION_PUTINGRAVEYARD,RESOLVED_OK)); + if (newDead && newDead != latest && newDead->card->isACreature()) + return ActivatedAbility::isReactingToClick(card); + return 0; + } + int resolve(){ + latest = newDead; + source->controller()->life++; + return 1; + } +}; + + +//Stasis +class AStasis:public ActivatedAbility{ +public: + int paidThisTurn; + AStasis(int _id, MTGCardInstance * card):ActivatedAbility(_id,card, NEW ManaCost(),1,0){ + paidThisTurn = 1; + cost->add(MTG_COLOR_BLUE,1); + } + + void Update(float dt){ + //Upkeep Cost + if (newPhase !=currentPhase){ + if (newPhase == MTG_PHASE_UPKEEP){ + paidThisTurn = 0; + }else if (!paidThisTurn && newPhase > MTG_PHASE_UPKEEP && game->currentPlayer==source->controller() ){ + game->currentPlayer->game->putInGraveyard(source); + paidThisTurn = 1; + } + } + //Stasis Effect + for (int i = 0; i < 2; i++){ + game->phaseRing->removePhase(MTG_PHASE_UNTAP,game->players[i]); + } + + //Parent Class Method Call + ActivatedAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card){ + return (!paidThisTurn && currentPhase == MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card)); + } + + int resolve(){ + paidThisTurn = 1; + return 1; + } + + int destroy(){ + for (int i = 0; i < 2; i++){ + game->phaseRing->addPhaseBefore(MTG_PHASE_UNTAP,game->players[i],MTG_PHASE_UPKEEP,game->players[i]); + } + return 1; + } +}; + + + +//--------------Addon Abra------------------ +//ShieldOfTheAge +class AShieldOfTheAge: public TargetAbility{ +public: + AShieldOfTheAge(int _id, MTGCardInstance * card):TargetAbility(_id,card,NEW DamageTargetChooser(card,_id),NEW ManaCost(),0,0){ + cost->add(MTG_COLOR_ARTIFACT,2); + } + + int resolve(){ + Damage * damage = tc->getNextDamageTarget(); + if (!damage) return 0; + game->mLayers->stackLayer()->Fizzle(damage); + return 1; + } +}; + +// GiveLifeForTappedType + +class AGiveLifeForTappedType:public MTGAbility{ +public: + char type[20]; + int nbtypestapped; + + int counttypesTapped(){ + int result = 0; + MTGInPlay * inplay = source->controller()->opponent()->game->inPlay; + for (int i = 0; i < inplay->nb_cards; i++){ + MTGCardInstance * card = inplay->cards[i]; + if (card->tapped && card->hasType(type)) result++; + } + return result; + } + + AGiveLifeForTappedType(int _id, MTGCardInstance * source, const char * _type):MTGAbility(_id, source){ + sprintf(type,"%s",_type);{ + nbtypestapped = counttypesTapped(); + } + } + + void Update(float dt){ + int newcount = counttypesTapped(); + for (int i=0; i < newcount - nbtypestapped; i++){ + source->controller()->life++; + } + nbtypestapped = newcount; + } +}; + +//Minion of Leshrac +class AMinionofLeshrac: public TargetAbility{ +public: + int paidThisTurn; + AMinionofLeshrac(int _id, MTGCardInstance * source):TargetAbility(_id, source, NEW CreatureTargetChooser(),0,1,0){ + paidThisTurn = 1; + } + + void Update(float dt){ + if (newPhase != currentPhase && source->controller() == game->currentPlayer){ + if (newPhase == MTG_PHASE_UNTAP){ + paidThisTurn = 0; + }else if( newPhase == MTG_PHASE_UPKEEP + 1 && !paidThisTurn){ + game->mLayers->stackLayer()->addDamage(source,source->controller(), 5); + source->tapped = 1; + } + } + TargetAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card){ + if (currentPhase != MTG_PHASE_UPKEEP || paidThisTurn) return 0; + return TargetAbility::isReactingToClick(card); + } + + int resolve(){ + MTGCardInstance * card = tc->getNextCardTarget(); + if (card && card != source && card->controller() == source->controller()){ + card->controller()->game->putInGraveyard(card); + paidThisTurn = 1; + return 1; + } + return 0; + } + +}; + +//2703 Lost Order of Jarkeld +class ALostOrderofJarkeld:public ListMaintainerAbility{ +public: + ALostOrderofJarkeld(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ + } + + int canBeInList(MTGCardInstance * card){ + if (card==source || (game->currentPlayer->game->inPlay->hasCard(card) && card->isACreature()) ) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + source->power += 1; + source->addToToughness(1); + return 1; + } + + int removed(MTGCardInstance * card){ + source->power -= 1; + source->addToToughness(-1); + return 1; + } + +}; + + +#endif diff --git a/projects/mtg/include/MTGAbility.h b/projects/mtg/include/MTGAbility.h index d0d14a7cd..ea2308907 100644 --- a/projects/mtg/include/MTGAbility.h +++ b/projects/mtg/include/MTGAbility.h @@ -1,118 +1,193 @@ -#ifndef _MTGABILITY_H_ -#define _MTGABILITY_H_ - - - -class MTGCardInstance; -class GameObserver; -class Spell; -class Damageable; -class PlayGuiObject; -class TargetChooser; -class ManaCost; -class MTGGameZone; -class Player; - -#include "ActionElement.h" -#include -#include -using std::string; -using std::map; - - -#define BAKA_EFFECT_GOOD 10 -#define BAKA_EFFECT_BAD 11 - -class AbilityFactory{ - private: - int destroyAllFromTypeInPlay(const char * type, MTGCardInstance * source, int bury = 0); - int destroyAllFromColorInPlay(int color, MTGCardInstance * source, int bury = 0); - int putInPlayFromZone(MTGCardInstance * card, MTGGameZone * zone, Player * p); - public: - int magicText(int id, Spell * spell, MTGCardInstance * card = NULL); - void addAbilities(int _id, Spell * spell); -}; - -class MTGAbility: public ActionElement{ - protected: - char menuText[25]; - Damageable * target; - GameObserver * game; - public: - MTGCardInstance * source; - MTGAbility(int id, MTGCardInstance * card); - MTGAbility(int id, MTGCardInstance * _source, Damageable * _target); - virtual int testDestroy(); - virtual ~MTGAbility(); - virtual void Render(){}; - virtual int isReactingToClick(MTGCardInstance * card){return 0;}; - virtual int reactToClick(MTGCardInstance * card){return 0;}; - virtual void Update(float dt){}; - virtual int fireAbility(); - virtual int resolve(){return 0;}; - - -}; - - -class TriggeredAbility:public MTGAbility{ - public: - TriggeredAbility(int id, MTGCardInstance * card); - TriggeredAbility(int id, MTGCardInstance * _source, Damageable * _target); - virtual void Update(float dt); - virtual void Render(){}; - virtual int trigger()=0; - virtual int resolve() = 0; -}; - - -class ActivatedAbility:public MTGAbility{ - public: - ManaCost * cost; - int playerturnonly; - int needsTapping; - ActivatedAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1); - virtual int reactToClick(MTGCardInstance * card); - virtual int isReactingToClick(MTGCardInstance * card); - virtual int reactToTargetClick(Targetable * object); - virtual int resolve() = 0; - virtual ~ActivatedAbility(); -}; - -class TargetAbility:public ActivatedAbility{ - public: - TargetAbility(int id, MTGCardInstance * card, TargetChooser * _tc,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1); - TargetAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1); - virtual void Update(float dt); - virtual int reactToClick(MTGCardInstance * card); - virtual int reactToTargetClick(Targetable * object); - virtual void Render(); -}; - -class InstantAbility:public MTGAbility{ - public: - int init; - virtual void Update(float dt); - virtual int testDestroy(); - InstantAbility(int _id, MTGCardInstance * source); - InstantAbility(int _id, MTGCardInstance * source,Damageable * _target); - virtual int resolve(){return 0;}; -}; - -/* State based effects. This class works ONLY for InPlay and needs to be extended for other areas of the game !!! */ -class ListMaintainerAbility:public MTGAbility{ - public: - map cards; - ListMaintainerAbility(int _id):MTGAbility(_id,NULL){}; - ListMaintainerAbility(int _id, MTGCardInstance *_source):MTGAbility(_id, _source){}; - ListMaintainerAbility(int _id, MTGCardInstance *_source,Damageable * _target):MTGAbility(_id, _source, _target){}; - virtual void Update(float dt); - virtual int canBeInList(MTGCardInstance * card) = 0; - virtual int added(MTGCardInstance * card) = 0; - virtual int removed(MTGCardInstance * card) = 0; - virtual int destroy(); -}; - -#include "MTGCardInstance.h" - -#endif +#ifndef _MTGABILITY_H_ +#define _MTGABILITY_H_ + + + +class MTGCardInstance; +class GameObserver; +class Spell; +class Damageable; +class PlayGuiObject; +class TargetChooser; +class ManaCost; +class MTGGameZone; +class Player; + +#include "ActionElement.h" +#include +#include +using std::string; +using std::map; + + +//Two stupid variables used to give a hint to the AI: +// Should I cast a spell on an ennemy or friendly unit ? +#define BAKA_EFFECT_GOOD 10 +#define BAKA_EFFECT_BAD 11 + + + +class MTGAbility: public ActionElement{ + protected: + char menuText[25]; + Damageable * target; + GameObserver * game; + public: + MTGCardInstance * source; + MTGAbility(int id, MTGCardInstance * card); + MTGAbility(int id, MTGCardInstance * _source, Damageable * _target); + virtual int testDestroy(); + virtual ~MTGAbility(); + virtual void Render(){}; + virtual int isReactingToClick(MTGCardInstance * card){return 0;}; + virtual int reactToClick(MTGCardInstance * card){return 0;}; + virtual void Update(float dt){}; + virtual int fireAbility(); + virtual int resolve(){return 0;}; + + +}; + + +class TriggeredAbility:public MTGAbility{ + public: + TriggeredAbility(int id, MTGCardInstance * card); + TriggeredAbility(int id, MTGCardInstance * _source, Damageable * _target); + virtual void Update(float dt); + virtual void Render(){}; + virtual int trigger()=0; + virtual int resolve() = 0; +}; + + +class ActivatedAbility:public MTGAbility{ +public: + ManaCost * cost; + int playerturnonly; + int needsTapping; + ActivatedAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1); + virtual int reactToClick(MTGCardInstance * card); + virtual int isReactingToClick(MTGCardInstance * card); + virtual int reactToTargetClick(Targetable * object); + virtual int resolve() = 0; + virtual ~ActivatedAbility(); +}; + +class TargetAbility:public ActivatedAbility{ +public: + TargetAbility(int id, MTGCardInstance * card, TargetChooser * _tc,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1); + TargetAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1); + virtual void Update(float dt); + virtual int reactToClick(MTGCardInstance * card); + virtual int reactToTargetClick(Targetable * object); + virtual void Render(); +}; + +class InstantAbility:public MTGAbility{ +public: + int init; + virtual void Update(float dt); + virtual int testDestroy(); + InstantAbility(int _id, MTGCardInstance * source); + InstantAbility(int _id, MTGCardInstance * source,Damageable * _target); + virtual int resolve(){return 0;}; +}; + +/* State based effects. This class works ONLY for InPlay and needs to be extended for other areas of the game !!! */ +class ListMaintainerAbility:public MTGAbility{ +public: + map cards; + ListMaintainerAbility(int _id):MTGAbility(_id,NULL){}; + ListMaintainerAbility(int _id, MTGCardInstance *_source):MTGAbility(_id, _source){}; + ListMaintainerAbility(int _id, MTGCardInstance *_source,Damageable * _target):MTGAbility(_id, _source, _target){}; + virtual void Update(float dt); + virtual int canBeInList(MTGCardInstance * card) = 0; + virtual int added(MTGCardInstance * card) = 0; + virtual int removed(MTGCardInstance * card) = 0; + virtual int destroy(); +}; + +/* An attempt to globalize triggered abilities as much as possible */ +class MTGAbilityBasicFeatures{ + public: + Damageable * target; + GameObserver * game; + MTGCardInstance * source; + MTGAbilityBasicFeatures(); + MTGAbilityBasicFeatures(MTGCardInstance * _source, Damageable * _target = NULL); + void init(MTGCardInstance * _source, Damageable * _target = NULL); +}; + +class Trigger:public MTGAbilityBasicFeatures{ +public: + virtual int trigger()=0; + virtual int testDestroy(){return 0;}; +}; + + +class TriggerAtPhase:public Trigger{ +public: + int currentPhase, newPhase; + int phaseId; + + TriggerAtPhase(int _phaseId); + + virtual int trigger(); +}; + +class TriggerNextPhase:public TriggerAtPhase{ +public: + int destroyActivated; + TriggerNextPhase(int _phaseId); + + virtual int testDestroy(); + +}; + +class TriggeredEvent:public MTGAbilityBasicFeatures{ +public: + virtual int resolve()=0; +}; + +class DrawEvent:public TriggeredEvent{ +public: + Player * player; + int nbcards; + DrawEvent(Player * _player, int _nbcards); + int resolve(); +}; + +class DestroyCondition:public MTGAbilityBasicFeatures{ +public: + virtual int testDestroy(); +}; + + +class GenericTriggeredAbility:public TriggeredAbility{ +public: + Trigger * t; + TriggeredEvent * te; + DestroyCondition * dc; + GenericTriggeredAbility(int id, MTGCardInstance * _source, Trigger * _t, TriggeredEvent * _te, DestroyCondition * _dc = NULL, Damageable * _target = NULL); + virtual int trigger(); + virtual int resolve(); + virtual int testDestroy(); + ~GenericTriggeredAbility(); +}; + +/* Ability Factory */ +class AbilityFactory{ +private: + int destroyAllFromTypeInPlay(const char * type, MTGCardInstance * source, int bury = 0); + int destroyAllFromColorInPlay(int color, MTGCardInstance * source, int bury = 0); + int putInPlayFromZone(MTGCardInstance * card, MTGGameZone * zone, Player * p); + Trigger * parseTrigger(string magicText); + public: + int magicText(int id, Spell * spell, MTGCardInstance * card = NULL); + void addAbilities(int _id, Spell * spell); +}; + + +#include "MTGCardInstance.h" + +#endif \ No newline at end of file diff --git a/projects/mtg/include/MTGDefinitions.h b/projects/mtg/include/MTGDefinitions.h index dd2078aa5..c0939e6ed 100644 --- a/projects/mtg/include/MTGDefinitions.h +++ b/projects/mtg/include/MTGDefinitions.h @@ -1,176 +1,190 @@ -#ifndef _MTGDEFINITION_H_ -#define _MTGDEFINITION_H_ - - -#define TOTAL_NUMBER_OF_CARDS 4000 - -#define MTG_NB_COLORS 7 - -#define MTG_COLOR_ARTIFACT 0 -#define MTG_COLOR_GREEN 1 -#define MTG_COLOR_BLUE 2 -#define MTG_COLOR_RED 3 -#define MTG_COLOR_BLACK 4 -#define MTG_COLOR_WHITE 5 -#define MTG_COLOR_LAND 6 - - -static char MTGColorChars[] = {'x','g','u','r','b','w','l'}; -static const char * MTGColorStrings[] = {"artifact", "green", "blue", "red", "black", "white", "land"}; - -static int _r[7] = {75, 20, 20, 200,50,255,128}; -static int _g[7] = {30, 140, 30, 15, 50,255,128}; -static int _b[7] = {20, 0, 140,15, 50,255,128}; - - -#define MTG_UNCOLORED 0 -#define MTG_FOREST 1 -#define MTG_ISLAND 2 -#define MTG_MOUNTAIN 3 -#define MTG_SWAMP 4 -#define MTG_PLAIN 5 - -#define MTG_TYPE_CREATURE 10 -#define MTG_TYPE_ARTIFACT 11 -#define MTG_TYPE_ENCHANTMENT 12 -#define MTG_TYPE_SORCERY 13 -#define MTG_TYPE_LAND 14 -#define MTG_TYPE_INSTANT 15 - - - -#define MTG_PHASE_BEFORE_BEGIN 0 -#define MTG_PHASE_UNTAP 1 -#define MTG_PHASE_UPKEEP 2 -#define MTG_PHASE_DRAW 3 -#define MTG_PHASE_FIRSTMAIN 4 -#define MTG_PHASE_COMBATBEGIN 5 -#define MTG_PHASE_COMBATATTACKERS 6 -#define MTG_PHASE_COMBATBLOCKERS 7 -#define MTG_PHASE_COMBATDAMAGE 8 -#define MTG_PHASE_COMBATEND 9 -#define MTG_PHASE_SECONDMAIN 10 -#define MTG_PHASE_ENDOFTURN 11 -#define MTG_PHASE_EOT 11 -#define MTG_PHASE_CLEANUP 12 -#define MTG_PHASE_AFTER_EOT 13 -#define NB_MTG_PHASES 14 - -#define TRAMPLE 0 -#define FORESTWALK 1 -#define ISLANDWALK 2 -#define MOUNTAINWALK 3 -#define SWAMPWALK 4 -#define PLAINSWALK 5 -#define FLYING 6 -#define FIRSTSTRIKE 7 -#define DOUBLESTRIKE 8 -#define FEAR 9 -#define FLASH 10 -#define HASTE 11 -#define LIFELINK 12 -#define REACH 13 -#define SHROUD 14 -#define VIGILANCE 15 -#define DEFENSER 16 -#define DEFENDER 16 -#define BANDING 17 -#define PROTECTIONGREEN 18 -#define PROTECTIONBLUE 19 -#define PROTECTIONRED 20 -#define PROTECTIONBLACK 21 -#define PROTECTIONWHITE 22 -#define UNBLOCKABLE 23 -#define WITHER 24 -#define PERSIST 25 -#define RETRACE 26 -#define EXALTED 27 -#define LEGENDARY 28 -#define SHADOW 29 -#define REACHSHADOW 30 -#define FORESTHOME 31 -#define ISLANDHOME 32 -#define MOUNTAINHOME 33 -#define SWAMPHOME 34 -#define PLAINSHOME 35 -#define FLANKING 36 -#define RAMPAGE1 37 - -#define NB_BASIC_ABILITIES 38 - -static const char * MTGBasicAbilities[] = { - "trample", - "forestwalk", - "islandwalk", - "mountainwalk", - "swampwalk", - "plainwalk", - "flying", - "first strike", - "double strike", - "fear", - "flash", - "haste", - "lifelink", - "reach", - "shroud", - "vigilance", - "defender", - "banding", - "protection from green", - "protection from blue", - "protection from red", - "protection from black", - "protection from white", - "unblockable", - "wither", - "persist", - "retrace", - "exalted", - "legendary", - "shadow", - "reachshadow", - "foresthome", - "islandhome", - "moutainhome", - "swamphome", - "plainshome", - "flanking", - "rampage", -}; - - -#define RARITY_M 'M' -#define RARITY_R 'R' -#define RARITY_U 'U' -#define RARITY_C 'C' -#define RARITY_L 'L' - - -#define MAIN_FONT 0 -#define MAGIC_FONT 1 - - -static const char *MTGPhaseNames[] = - { - "---", - "Untap", - "Upkeep", - "Draw", - "Main phase 1", - "Combat begins", - "Attackers", - "Blockers", - "Combat damage", - "Combat ends", - "Main phase 2", - "End of turn", - "cleanup", - "---" - }; - - - - - -#endif +#ifndef _MTGDEFINITION_H_ +#define _MTGDEFINITION_H_ + + +#define TOTAL_NUMBER_OF_CARDS 4000 + +#define MTG_NB_COLORS 7 + +#define MTG_COLOR_ARTIFACT 0 +#define MTG_COLOR_GREEN 1 +#define MTG_COLOR_BLUE 2 +#define MTG_COLOR_RED 3 +#define MTG_COLOR_BLACK 4 +#define MTG_COLOR_WHITE 5 +#define MTG_COLOR_LAND 6 + + +static char MTGColorChars[] = {'x','g','u','r','b','w','l'}; +static const char * MTGColorStrings[] = {"artifact", "green", "blue", "red", "black", "white", "land"}; + +static int _r[7] = {75, 20, 20, 200,50,255,128}; +static int _g[7] = {30, 140, 30, 15, 50,255,128}; +static int _b[7] = {20, 0, 140,15, 50,255,128}; + + +#define MTG_UNCOLORED 0 +#define MTG_FOREST 1 +#define MTG_ISLAND 2 +#define MTG_MOUNTAIN 3 +#define MTG_SWAMP 4 +#define MTG_PLAIN 5 + +#define MTG_TYPE_CREATURE 10 +#define MTG_TYPE_ARTIFACT 11 +#define MTG_TYPE_ENCHANTMENT 12 +#define MTG_TYPE_SORCERY 13 +#define MTG_TYPE_LAND 14 +#define MTG_TYPE_INSTANT 15 + + + +#define MTG_PHASE_BEFORE_BEGIN 0 +#define MTG_PHASE_UNTAP 1 +#define MTG_PHASE_UPKEEP 2 +#define MTG_PHASE_DRAW 3 +#define MTG_PHASE_FIRSTMAIN 4 +#define MTG_PHASE_COMBATBEGIN 5 +#define MTG_PHASE_COMBATATTACKERS 6 +#define MTG_PHASE_COMBATBLOCKERS 7 +#define MTG_PHASE_COMBATDAMAGE 8 +#define MTG_PHASE_COMBATEND 9 +#define MTG_PHASE_SECONDMAIN 10 +#define MTG_PHASE_ENDOFTURN 11 +#define MTG_PHASE_EOT 11 +#define MTG_PHASE_CLEANUP 12 +#define MTG_PHASE_AFTER_EOT 13 +#define NB_MTG_PHASES 14 + +#define TRAMPLE 0 +#define FORESTWALK 1 +#define ISLANDWALK 2 +#define MOUNTAINWALK 3 +#define SWAMPWALK 4 +#define PLAINSWALK 5 +#define FLYING 6 +#define FIRSTSTRIKE 7 +#define DOUBLESTRIKE 8 +#define FEAR 9 +#define FLASH 10 +#define HASTE 11 +#define LIFELINK 12 +#define REACH 13 +#define SHROUD 14 +#define VIGILANCE 15 +#define DEFENSER 16 +#define DEFENDER 16 +#define BANDING 17 +#define PROTECTIONGREEN 18 +#define PROTECTIONBLUE 19 +#define PROTECTIONRED 20 +#define PROTECTIONBLACK 21 +#define PROTECTIONWHITE 22 +#define UNBLOCKABLE 23 +#define WITHER 24 +#define PERSIST 25 +#define RETRACE 26 +#define EXALTED 27 +#define LEGENDARY 28 +#define SHADOW 29 +#define REACHSHADOW 30 +#define FORESTHOME 31 +#define ISLANDHOME 32 +#define MOUNTAINHOME 33 +#define SWAMPHOME 34 +#define PLAINSHOME 35 + +#define NB_BASIC_ABILITIES 36 + +static const char * MTGBasicAbilities[] = { +"trample", +"forestwalk", +"islandwalk", +"mountainwalk", +"swampwalk", +"plainwalk", +"flying", +"first strike", +"double strike", +"fear", +"flash", +"haste", +"lifelink", +"reach", +"shroud", +"vigilance", +"defender", +"banding", +"protection from green", +"protection from blue", +"protection from red", +"protection from black", +"protection from white", +"unblockable", +"wither", +"persist", +"retrace", +"exalted", +"legendary", +"shadow", +"reachshadow", +"foresthome", +"islandhome", +"moutainhome", +"swamphome", +"plainshome" +}; + + +#define RARITY_M 'M' +#define RARITY_R 'R' +#define RARITY_U 'U' +#define RARITY_C 'C' +#define RARITY_L 'L' + + +#define MAIN_FONT 0 +#define MAGIC_FONT 1 + + +static const char *MTGPhaseNames[] = +{ + "---", + "Untap", + "Upkeep", + "Draw", + "Main phase 1", + "Combat begins", + "Attackers", + "Blockers", + "Combat damage", + "Combat ends", + "Main phase 2", + "End of turn", + "cleanup", + "---" +}; + +static const char *MTGPhaseCodeNames[] = +{ + "beginofturn", + "untap", + "upkeep", + "draw", + "firstmain", + "combatbegins", + "attackers", + "blockers", + "combatdamage", + "combatends", + "secondmain", + "endofturn", + "cleanup", + "beforenextturn" +}; + + + + + +#endif diff --git a/projects/mtg/src/ActionElement.cpp b/projects/mtg/src/ActionElement.cpp index 33d4270e2..718d0ad49 100644 --- a/projects/mtg/src/ActionElement.cpp +++ b/projects/mtg/src/ActionElement.cpp @@ -12,31 +12,6 @@ ActionElement::ActionElement(int id):JGuiObject(id){ tc = NULL; } -/* - void ActionElement::RenderMessageBackground(float y0, int _height){ - float height = _height; - PIXEL_TYPE colors_up[] = - { - ARGB(0,255,255,255), - ARGB(0,255,255,255), - ARGB(128,255,255,255), - ARGB(128,255,255,255) - }; - - PIXEL_TYPE colors_down[] = - { - ARGB(128,255,255,255), - ARGB(128,255,255,255), - ARGB(0,255,255,255), - ARGB(0,255,255,255) - }; - - JRenderer * renderer = JRenderer::GetInstance(); - renderer->FillRect(0,y0,SCREEN_WIDTH,height/2,colors_up); - renderer->FillRect(0,y0+height/2,SCREEN_WIDTH,height/2,colors_down); - // mEngine->DrawLine(0,y0,SCREEN_WIDTH,y0,ARGB(128,255,255,255)); - // mEngine->DrawLine(0,y0+height,SCREEN_WIDTH,y0+height,ARGB(128,255,255,255)); - }*/ int ActionElement::getActivity(){ diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index dfcebb80b..e3bef1d38 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -1,1723 +1,1763 @@ -#include "../include/debug.h" -#include "../include/MTGAbility.h" -#include "../include/ManaCost.h" -#include "../include/MTGGameZones.h" -#include "../include/AllAbilities.h" -#include "../include/Damage.h" -#include "../include/TargetChooser.h" -#include "../include/CardGui.h" -#include "../include/MTGDeck.h" - -int AbilityFactory::destroyAllFromTypeInPlay(const char * type, MTGCardInstance * source, int bury){ - GameObserver * game = GameObserver::GetInstance(); - for (int i = 0; i < 2 ; i++){ - for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ - MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; - if (current->hasType(type)){ - if (bury){ - game->players[i]->game->putInGraveyard(current); - }else{ - game->mLayers->stackLayer()->addPutInGraveyard(current); - } - } - } - } - return 1; -} - -int AbilityFactory::destroyAllFromColorInPlay(int color, MTGCardInstance * source, int bury){ - GameObserver * game = GameObserver::GetInstance(); - for (int i = 0; i < 2 ; i++){ - for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ - MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; - if (current->hasColor(color)){ - if (bury){ - game->players[i]->game->putInGraveyard(current); - }else{ - game->mLayers->stackLayer()->addPutInGraveyard(current); - } - } - } - } - return 1; -} - -int AbilityFactory::putInPlayFromZone(MTGCardInstance * card, MTGGameZone * zone, Player * p){ - Spell * spell = NEW Spell(card); - p->game->putInZone(card, zone, p->game->stack); - spell->resolve(); - delete spell; - return 1; -} - -//Some basic functionnalities that can be added automatically in the text file -int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card){ - int dryMode = 0; - if (!spell) dryMode = 1; - GameObserver * game = GameObserver::GetInstance(); - if (!card) card = spell->source; - MTGCardInstance * target = card->target; - if (!target) target = card; - string magicText = card->magicText; - if (card->alias && magicText.size() == 0){ - //An awful way to gat access to the aliasedcard - magicText = GameObserver::GetInstance()->players[0]->game->collection->getCardById(card->alias)->magicText; - } - string s; - int size = magicText.size(); - if (size == 0) return 0; - unsigned int found; - int result = id; - - - while (magicText.size()){ - found = magicText.find("\n"); - if (found != string::npos){ - s = magicText.substr(0,found); - magicText = magicText.substr(found+1); - }else{ - s = magicText; - magicText = ""; - } -#if defined (WIN32) || defined (LINUX) - char buf[4096]; - sprintf(buf, "AUTO ACTION: %s\n", s.c_str()); - OutputDebugString(buf); -#endif - - TargetChooser * tc = NULL; - int doTap = 0; - string lordType = ""; - - //Tap in the cost ? - if (s.find("{t}") != string::npos) doTap = 1; - - //Target Abilities - found = s.find("target("); - if (found != string::npos){ - int end = s.find(")"); - string target = s.substr(found + 7,end - found - 7); - TargetChooserFactory tcf; - tc = tcf.createTargetChooser(target, card); - - } - - //Lord - found = s.find("lord("); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - unsigned int end = s.find(")", found+5); - if (end != string::npos){ - lordType = s.substr(found+5,end-found-5).c_str(); - } - } - - //Champion. Very basic, needs to be improved ! - found = s.find("champion(name:"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - unsigned int end = s.find(")", found+14); - if (end != string::npos){ - string type = s.substr(found+14,end-found-14).c_str(); - game->addObserver(NEW APlagueRats(id,card,type.c_str())); - result++; - continue; - } - } - - //Untapper (Ley Druid...) - found = s.find("untap"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - ManaCost * cost = ManaCost::parseManaCost(s); - if (tc){ - game->addObserver(NEW AUntaper(id, card, cost, tc)); - }else{ - target->tapped = 0; - } - - result++; - continue; - } - - //Tapper (icy manipulator) - found = s.find("tap"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - ManaCost * cost = ManaCost::parseManaCost(s); - if (tc){ - game->addObserver(NEW ATapper(id, card, cost, tc)); - }else{ - target->tapped = 1; - } - - result++; - continue; - } - //Tentative Destroyall not working char is not compatible with string variable - //found = s.find("destroyall("); - //if (found != string::npos){ - // if (dryMode) return BAKA_EFFECT_GOOD; - // unsigned int end = s.find(")", found+11); - // if (end != string::npos){ - // string type = s.substr(found+11,end-found-11).c_str(); - // destroyAllFromTypeInPlay(type.c_str(), card); - // result++; - // continue; - //} - - //Regeneration - found = s.find("}:regenerate"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - ManaCost * cost = ManaCost::parseManaCost(s); - - if (lordType.size() > 0){ - game->addObserver(NEW ALord(id,card,lordType.c_str(),0,0,-1,cost)); - }else{ - - if (tc){ - //TODO - }else{ - game->addObserver(NEW AStandardRegenerate(id, card, target, cost)); - //TODO death ward ! - } - } - result++; - continue; - } - //Bury - found = s.find("bury"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_BAD; - if (tc){ - game->addObserver(NEW ABurier(id, card,tc)); - }else{ - target->controller()->game->putInGraveyard(target); - } - result++; - continue; - } - //Destroy - found = s.find("destroy"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_BAD; - if (tc){ - game->addObserver(NEW ADestroyer(id, card,tc)); - }else{ - game->mLayers->stackLayer()->addPutInGraveyard(target); - } - result++; - continue; - } - - //Summon - - //Reveal Take Target and put in in hand (should be also able to target hand since some card needs you to reveal a card in your hand - - //Damage - found = s.find("damage"); - if (found != string::npos){ - unsigned int start = s.find(":",found); - unsigned int end = s.find(" ",start); - int damage; - ManaCost * cost = ManaCost::parseManaCost(s); - if (end != string::npos){ - damage = atoi(s.substr(start+1,end-start-1).c_str()); - }else{ - damage = atoi(s.substr(start+1).c_str()); - } - if (dryMode) return BAKA_EFFECT_BAD; - if (tc){ - game->addObserver(NEW ADamager(id, card, cost, damage, tc,doTap)); - }else{ - delete cost; - game->mLayers->stackLayer()->addDamage(card,spell->getNextDamageableTarget(), damage); - } - result++; - continue; - } - - //gain/lose life - found = s.find("life"); - if (found != string::npos){ - unsigned int start = s.find(":",found); - unsigned int end = s.find(" ",start); - int life; - ManaCost * cost = ManaCost::parseManaCost(s); - if (end != string::npos){ - life = atoi(s.substr(start+1,end-start-1).c_str()); - }else{ - life = atoi(s.substr(start+1).c_str()); - } - if (dryMode) return BAKA_EFFECT_GOOD; - if (tc){ - //TODO ? - }else{ - if (cost->getConvertedCost() == 0 && !doTap){ - delete cost; - card->controller()->life+=life; - }else{ - //TODO; - } - } - result++; - continue; - } - - //Draw - found = s.find("draw"); - if (found != string::npos){ - unsigned int start = s.find(":",found); - unsigned int end = s.find(" ",start); - int nbcards; - ManaCost * cost = ManaCost::parseManaCost(s); - if (end != string::npos){ - nbcards = atoi(s.substr(start+1,end-start-1).c_str()); - }else{ - nbcards = atoi(s.substr(start+1).c_str()); - } - if (dryMode) return BAKA_EFFECT_GOOD; - if (tc){ - //TODO ? - }else{ - if (cost->getConvertedCost() == 0){ - delete cost; - game->mLayers->stackLayer()->addDraw(card->controller(),nbcards); - }else{ - game->addObserver(NEW ADrawer(id,card,cost,nbcards,doTap)); - } - } - result++; - continue; - } - - //Change Power/Toughness - found = s.find("/"); - if (found != string::npos){ - unsigned int start = s.find(":"); - if (start == string::npos) start = -1; - int power = atoi(s.substr(start+1,size-found).c_str()); - unsigned int end = s.find(" ",start); - int toughness; - if (end != string::npos){ - toughness = atoi(s.substr(found+1,end-found-1).c_str()); - }else{ - toughness = atoi(s.substr(found+1).c_str()); - } - if (dryMode){ - if (power >=0 && toughness >= 0 ) return BAKA_EFFECT_GOOD; - return BAKA_EFFECT_BAD; - } - int limit = 0; - unsigned int limit_str = s.find("limit:"); - if (limit_str != string::npos){ - limit = atoi(s.substr(limit_str+6).c_str()); - } - ManaCost * cost = ManaCost::parseManaCost(s); - - if (lordType.size() > 0){ - game->addObserver(NEW ALord(id,card,lordType.c_str(),power,toughness)); - }else{ - if(tc){ - game->addObserver(NEW ATargetterPowerToughnessModifierUntilEOT(id, card,power,toughness, cost, tc)); - }else{ - if (cost->getConvertedCost() == 0){ - delete cost; - if(card->hasType("enchantment")){ - game->addObserver(NEW APowerToughnessModifier(id, card, target,power,toughness)); - }else{ - game->addObserver(NEW AInstantPowerToughnessModifierUntilEOT(id, card, target,power,toughness)); - } - }else{ - game->addObserver(NEW APowerToughnessModifierUntilEndOfTurn(id, card, target,power,toughness, cost, limit)); - } - } - } - result++; - continue; - } - - //Mana Producer - found = s.find("add"); - if (found != string::npos){ - if (dryMode) return BAKA_EFFECT_GOOD; - ManaCost * cost = ManaCost::parseManaCost(s.substr(0,found)); - ManaCost * output = ManaCost::parseManaCost(s.substr(found)); - if (cost->getConvertedCost()){ - game->addObserver(NEW AManaProducer(id, target, output, cost)); - }else{ - delete cost; - if (doTap){ - game->addObserver(NEW AManaProducer(id, target, output)); - }else{ - card->controller()->getManaPool()->add(output); - delete output; - } - - } - result++; - continue; - } - - //Gain/loose Ability - for (int j = 0; j < NB_BASIC_ABILITIES; j++){ - found = s.find(MTGBasicAbilities[j]); - if (found!= string::npos){ - int modifier = 1; - if (found > 0 && s[found-1] == '-') modifier = 0; - if (dryMode){ - if (j == DEFENDER){ - if (modifier == 1) return BAKA_EFFECT_BAD; - return BAKA_EFFECT_GOOD; - }else{ - if (modifier == 1) return BAKA_EFFECT_GOOD; - return BAKA_EFFECT_BAD; - } - } - ManaCost * cost = ManaCost::parseManaCost(s); - - if (lordType.size() > 0){ - game->addObserver(NEW ALord(id,card,lordType.c_str(),0,0,j)); - }else{ - - if (tc){ - game->addObserver(NEW ABasicAbilityModifierUntilEOT(id, card, j, cost,tc, modifier)); - }else{ - if (cost->getConvertedCost() == 0){ - delete cost; - if(card->hasType("enchantment")){ - game->addObserver(NEW ABasicAbilityModifier(id, card,target, j,modifier)); - }else{ - game->addObserver(NEW AInstantBasicAbilityModifierUntilEOT(id, card,target, j,modifier)); - } - }else{ - game->addObserver(NEW ABasicAbilityAuraModifierUntilEOT(id, card,target, cost,j,modifier)); - } - } - } - result++; - continue; - } - } - } - return result; - - -} - -void AbilityFactory::addAbilities(int _id, Spell * spell){ - MTGCardInstance * card = spell->source; - if (spell->cursor==1) card->target = spell->getNextCardTarget(); - _id = magicText(_id, spell); - int putSourceInGraveyard = 0; //For spells that are not already InstantAbilities; - - - GameObserver * game = GameObserver::GetInstance(); - int id = card->model->getId(); - if (card->alias) id = card->alias; - switch (id){ - case 1092: //Aladdin's lamp - { - AAladdinsLamp * ability = NEW AAladdinsLamp(_id, card); - game->addObserver(ability); - break; - } - case 130550: //Ancestor's chosen - { - int life = card->controller()->game->graveyard->nb_cards; - card->controller()->life+= life; - break; - } - case 1190: //Animate Artifact - { - int x = card->target->getManaCost()->getConvertedCost(); - game->addObserver(NEW AConvertToCreatureAura(_id, card,card->target,x,x)); - break; - } - case 1094: //Ank Of Mishra - { - AAnkhOfMishra * ability = NEW AAnkhOfMishra(_id,card); - game->addObserver(ability); - break; - } - case 1095: //Armageddon clock - { - AArmageddonClock * ability = NEW AArmageddonClock(_id,card); - game->addObserver(ability); - break; - } - case 106525: //Ascendant Evincar - { - game->addObserver(NEW AColorLord(_id, card,MTG_COLOR_BLACK,-1,1,1)); - game->addObserver(NEW AColorLord(_id, card,0,MTG_COLOR_BLACK,-1,-1)); - break; - } - - case 1096: //Basalt Monolith - { - int cost[] = {MTG_COLOR_ARTIFACT, 3}; - AManaProducer * ability = NEW AManaProducer(_id, card, NEW ManaCost(cost,1)); - AUntapManaBlocker * ability2 = NEW AUntapManaBlocker(_id+1, card, NEW ManaCost(cost,1)); - AUnBlocker * ability3 = NEW AUnBlocker(_id+1, card,card, NEW ManaCost(cost,1)); - - game->addObserver(ability); - game->addObserver(ability2); - game->addObserver(ability3); - break; - } - case 1097: //Black Vise - { - game->addObserver( NEW ALifeZoneLink(_id ,card, MTG_PHASE_UPKEEP, 4)); - break; - } - case 1191: //Blue Elemental Blast - { - if (card->target){ - card->target->controller()->game->putInGraveyard(card->target); - }else{ - Spell * starget = spell->getNextSpellTarget(); - game->mLayers->stackLayer()->Fizzle(starget); - } - break; - } - case 1099: //Brass Man - { - int cost[] = {MTG_COLOR_ARTIFACT, 1}; - game->addObserver(NEW AUntapManaBlocker(_id, card, NEW ManaCost(cost,1))); - break; - } - case 1237: //Channel - { - game->addObserver(NEW AChannel(_id, card)); - break; - } - case 1282: //Chaoslace - { - if (card->target){ - card->target->setColor(MTG_COLOR_RED, 1); - }else{ - Spell * starget = spell->getNextSpellTarget(); - starget->source->setColor(MTG_COLOR_RED, 1); - } - break; - } - case 1335: //Circle of protection : black - { - game->addObserver(NEW ACircleOfProtection( _id,card, MTG_COLOR_BLACK)); - break; - } - case 1336: //Circle of protection : blue - { - game->addObserver(NEW ACircleOfProtection( _id,card, MTG_COLOR_BLUE)); - break; - } - case 1337: //Circle of protection : green - { - game->addObserver(NEW ACircleOfProtection( _id,card, MTG_COLOR_GREEN)); - break; - } - case 1338: //Circle of protection : red - { - game->addObserver(NEW ACircleOfProtection( _id,card, MTG_COLOR_RED)); - break; - } - case 1339: //Circle of protection : white - { - game->addObserver(NEW ACircleOfProtection( _id,card, MTG_COLOR_WHITE)); - break; - } - case 1101: //clockwork Beast - { - game->addObserver(NEW AClockworkBeast(_id,card)); - break; - } - case 1102: //Conservator - { - game->addObserver(NEW AConservator(_id,card)); - break; - } - case 1196: //Counterspell - { - Spell * starget = spell->getNextSpellTarget(); - if (starget) game->mLayers->stackLayer()->Fizzle(starget); - break; - } - case 1197: //Creature Bond - { - game->addObserver(NEW ACreatureBond(_id,card, card->target)); - break; - } - case 1103: //Crystal Rod - { - int cost[] = {MTG_COLOR_BLUE, 1}; - ASpellCastLife* ability = NEW ASpellCastLife(_id, card, MTG_COLOR_WHITE,NEW ManaCost(cost,1) , 1); - game->addObserver(ability); - break; - } - case 1151: //Deathgrip - { - int _cost[] = {MTG_COLOR_BLACK, 2}; - game->addObserver(NEW ASpellCounterEnchantment(_id, card, NEW ManaCost(_cost, 1),MTG_COLOR_GREEN)); - break; - } - case 1152: //Deathlace - { - if (card->target){ - card->target->setColor(MTG_COLOR_BLACK, 1); - }else{ - Spell * starget = spell->getNextSpellTarget(); - starget->source->setColor(MTG_COLOR_BLACK, 1); - } - break; - } - case 1105: //dingus Egg - { - ADingusEgg * ability = NEW ADingusEgg(_id,card); - game->addObserver(ability); - break; - } - case 1106: //Disrupting Scepter - { - ADisruptingScepter * ability = NEW ADisruptingScepter(_id,card); - game->addObserver(ability); - break; - } - case 1284: //Dragon Whelp - { - game->addObserver(NEW ADragonWhelp(_id,card)); - break; - } - case 1108: //Ebony Horse - { - AEbonyHorse * ability = NEW AEbonyHorse(_id,card); - game->addObserver(ability); - break; - } - case 1345: //Farmstead - { - game->addObserver(NEW AFarmstead(_id, card,card->target)); - break; - } - case 1291: //Fireball - { - int x = spell->cost->getConvertedCost() - 1; //TODO BETTER - game->addObserver(NEW AFireball(_id, card,spell, x)); - break; - } - case 1245: //Force of Nature - { - game->addObserver(NEW AForceOfNature(_id,card)); - break; - } - case 1110: //Glasses Of Urza - { - AGlassesOfUrza * ability = NEW AGlassesOfUrza(_id,card); - game->addObserver(ability); - break; - } - case 1112: //Howling Mine - { - game->addObserver(NEW AHowlingMine(_id, card)); - break; - } - case 1252: //Instill Energy - { - game->addObserver(NEW AUntaperOnceDuringTurn(_id, card, card->target, NEW ManaCost())); - break; - } - case 1113: //Iron Star - { - int cost[] = {MTG_COLOR_ARTIFACT, 1}; - ASpellCastLife* ability = NEW ASpellCastLife(_id, card, MTG_COLOR_RED,NEW ManaCost(cost,1) , 1); - game->addObserver(ability); - break; - } - case 1351: // Island Sancturay - { - game->addObserver(NEW AIslandSanctuary(_id, card)); - break; - } - case 1114: //Ivory cup - { - int cost[] = {MTG_COLOR_ARTIFACT, 1}; - ASpellCastLife* ability = NEW ASpellCastLife(_id, card, MTG_COLOR_WHITE,NEW ManaCost(cost,1) , 1); - game->addObserver(ability); - break; - } - case 1115: //Ivory Tower - { - game->addObserver(NEW ALifeZoneLink(_id ,card, MTG_PHASE_UPKEEP, 4, 1, 1)); - break; - } - case 1117: //Jandors Ring - { - game->addObserver(NEW AJandorsRing( _id, card)); - break; - } - case 1121: //Kormus Bell - { - game->addObserver(NEW AConvertLandToCreatures(id, card, "swamp")); - break; - } - case 1254: //Kudzu - { - game->addObserver(NEW AKudzu(id, card, card->target)); - break; - } - case 1256: //LifeForce - { - int _cost[] = {MTG_COLOR_GREEN, 2}; - game->addObserver(NEW ASpellCounterEnchantment(_id, card, NEW ManaCost(_cost, 1),MTG_COLOR_BLACK)); - break; - } - case 1257: //Lifelace - { - if (card->target){ - card->target->setColor(MTG_COLOR_GREEN, 1); - }else{ - Spell * starget = spell->getNextSpellTarget(); - starget->source->setColor(MTG_COLOR_GREEN, 1); - } - break; - } - case 1205: //Lifetap - { - game->addObserver(NEW AGiveLifeForTappedType(_id, card, "forest")); - break; - } - case 1259: //Living lands - { - game->addObserver(NEW AConvertLandToCreatures(id, card, "forest")); - break; - } - case 1124: //Mana Vault - { - int output[] = {MTG_COLOR_ARTIFACT, 3}; - game->addObserver(NEW AManaProducer(_id,card,NEW ManaCost(output,1))); - int cost[] = {MTG_COLOR_ARTIFACT, 4}; - game->addObserver(NEW AUntapManaBlocker(_id+1, card, NEW ManaCost(cost,1))); - game->addObserver(NEW ARegularLifeModifierAura(_id+2, card, card, MTG_PHASE_DRAW, -1, 1)); - break; - } - case 1126:// Millstone - { - game->addObserver( NEW AMillstone(_id ,card)); - break; - } - case 1215: //Power Leak - { - game->addObserver( NEW APowerLeak(_id ,card, card->target)); - break; - } - case 1311: //Power Surge - { - game->addObserver( NEW APowerSurge(_id ,card)); - break; - } - case 1358: //Purelace - { - if (card->target){ - card->target->setColor(MTG_COLOR_WHITE, 1); - }else{ - Spell * starget = spell->getNextSpellTarget(); - starget->source->setColor(MTG_COLOR_WHITE, 1); - } - break; - } - case 1312: //Red Elemental Blast - { - if (card->target){ - card->target->controller()->game->putInGraveyard(card->target); - }else{ - Spell * starget = spell->getNextSpellTarget(); - game->mLayers->stackLayer()->Fizzle(starget); - } - break; - } - case 1136: //Soul Net - { - game->addObserver( NEW ASoulNet(_id ,card)); - break; - } - case 1139: //The Rack - { - game->addObserver( NEW ALifeZoneLink(_id ,card, MTG_PHASE_UPKEEP, -3)); - break; - } - case 1140: //Throne of bones - { - int cost[] = {MTG_COLOR_ARTIFACT, 1}; - ASpellCastLife* ability = NEW ASpellCastLife(_id, card, MTG_COLOR_BLACK,NEW ManaCost(cost,1) , 1); - game->addObserver(ability); - break; - } - case 1142: //Wooden Sphere - { - int cost[] = {MTG_COLOR_ARTIFACT, 1}; - ASpellCastLife* ability = NEW ASpellCastLife(_id, card, MTG_COLOR_GREEN,NEW ManaCost(cost,1) , 1); - game->addObserver(ability); - break; - } - case 1143: //Animate Dead - { - game->addObserver(NEW AAnimateDead(_id, card, card->target)); - break; - } - case 1144: //Bad moon - { - game->addObserver(NEW ABadMoon(_id,card)); - break; - } - case 1148 : //Cursed lands - { - game->addObserver(NEW AWanderlust(_id, card, card->target)); - break; - } - case 1156: //Drain Life - { - Damageable * target = spell->getNextDamageableTarget(); - int x = spell->cost->getConvertedCost() - 2; //TODO Fix that !!! + X should be only black mana, that needs to be checked ! - game->mLayers->stackLayer()->addDamage(card, target, x); - if (target->life < x) x = target->life; - game->currentlyActing()->life+=x; - break; - } - case 1159: //Erg Raiders - { - AErgRaiders* ability = NEW AErgRaiders(_id, card); - game->addObserver(ability); - break; - } - case 1164: //Howl from beyond - { - int x = spell->cost->getConvertedCost() - 1; //TODO, this is not enough, Spells shouls have a function like "xCost" because the spell might cost more than expected to launch - AInstantPowerToughnessModifierUntilEOT * ability = NEW AInstantPowerToughnessModifierUntilEOT( _id, card, card->target, x, 0); - game->addObserver(ability); - break; - } - case 1202: //Hurkyl's Recall - { - Player * player = spell->getNextPlayerTarget(); - if (player){ - for (int i = 0; i < 2; i++){ - MTGInPlay * inplay = game->players[i]->game->inPlay; - for (int j= inplay->nb_cards -1 ; j >=0 ; j--){ - MTGCardInstance * card = inplay->cards[j]; - if (card->owner == player && card->hasType("artifact")){ - player->game->putInZone(card, inplay, player->game->hand); - } - } - } - } - break; - } - case 1165: //Hypnotic Specter - { - game->addObserver(NEW AHypnoticSpecter( _id, card)); - break; - } - case 1258: //Living Artifact - { - game->addObserver(NEW ALivingArtifact( _id, card, card->target)); - break; - } - case 1166: //Lord Of The Pit - { - game->addObserver(NEW ALordOfThePit( _id, card)); - break; - } - case 1209: //Mana Short - { - Player * player = spell->getNextPlayerTarget(); - if (player){ - MTGInPlay * inplay = player->game->inPlay; - for (int i = 0; i < inplay->nb_cards; i++){ - MTGCardInstance * current = inplay->cards[i]; - if (current->hasType("land")) current->tapped = 1; - } - player->getManaPool()->init(); - } - break; - } - case 1167: //Mind Twist - { - int xCost = spell->cost->getConvertedCost() - 1; - for (int i = 0; i < xCost; i++){ - game->opponent()->game->discardRandom(game->opponent()->game->hand); - } - break; - } - case 1170: //Nightmare - { - game->addObserver(NEW ANightmare(_id, card)); - break; - } - case 1171: //Paralysis - { - int cost[] = {MTG_COLOR_ARTIFACT, 4}; - game->addObserver(NEW AUntapManaBlocker(_id, card,card->target, NEW ManaCost(cost,1))); - card->target->tapped = 1; - break; - } - case 1172: //Pestilence - { - game->addObserver(NEW APestilence(_id, card)); - break; - } - /*case 1173: //Plague Rats - { - game->addObserver(NEW APlagueRats(_id, card, "Plague Rats")); - break; - } - */ - case 1174: //Raise Dead - { - MTGPlayerCards * zones = game->currentlyActing()->game; - zones->putInZone(card->target,zones->graveyard,zones->hand); - } - case 1176: //Sacrifice - { - ASacrifice * ability = NEW ASacrifice(_id, card, card->target); - game->addObserver(ability); - break; - } - case 1224: //Spell Blast - { - int x = spell->cost->getConvertedCost() - 1; - Spell * starget = spell->getNextSpellTarget(); - if (starget){ - if (starget->cost->getConvertedCost() <= x) game->mLayers->stackLayer()->Fizzle(starget); - } - break; - } - case 1185: //Warp Artifact - { - game->addObserver(NEW ARegularLifeModifierAura(_id, card, card->target, MTG_PHASE_UPKEEP, -1)); - break; - } - case 1192: //BrainGeyser - { - Player * player = ((Player * )spell->targets[0]); - int x = spell->cost->getConvertedCost() - 2; - for (int i = 0; i < x ; i++){ - player->game->drawFromLibrary(); - } - break; - } - case 1194: //Control Magic - { - game->addObserver(NEW ATakeControlAura(_id, card, card->target)); - break; - } - - case 1200 : //Feedback - { - game->addObserver(NEW AWanderlust(_id, card, card->target)); - break; - } - case 129601: //Icy Manipulator - { - int cost[] = {MTG_COLOR_ARTIFACT, 1}; - TypeTargetChooser * tc = new TypeTargetChooser("artifact",card); - tc->addType("land"); - tc->addType("creature"); - game->addObserver(NEW ATapper(_id,card,NEW ManaCost(cost, 1),tc)); - break; - } - - case 1203: //Island Fish - { - int cost[] = {MTG_COLOR_BLUE, 3}; - game->addObserver(NEW AUntapManaBlocker(_id, card, NEW ManaCost(cost,1))); - game->addObserver(NEW AStrongLandLinkCreature(_id, card, "island")); - break; - } - case 1214: //Pirate Ship - { - game->addObserver(NEW AStrongLandLinkCreature(_id, card, "island")); - game->addObserver(NEW ADamager(_id+1, card, NEW ManaCost(), 1)); - break; - } - case 1218: //Psychic Venom - { - game->addObserver(NEW APsychicVenom(_id, card, card->target)); - break; - } - case 1220: //Sea Serpent - { - game->addObserver(NEW AStrongLandLinkCreature(_id, card, "island")); - break; - } - case 1315: //Sedge Troll - { - game->addObserver( NEW ASedgeTroll(_id, card)); - break; - } - case 1221: //Serendib Efreet - { - game->addObserver( NEW ASerendibEfreet(_id, card)); - break; - } - case 1226: //Steal Artifact - { - game->addObserver( NEW AControlStealAura(_id, card, card->target)); - break; - } - case 1228: //Unstable mutation - { - game->addObserver(NEW APowerToughnessModifier(_id, card, card->target, 3, 3)); - game->addObserver(NEW APowerToughnessModifierRegularCounter(_id, card, card->target, MTG_PHASE_UPKEEP, -1, -1)); - break; - } - case 1229: //Unsummon - { - MTGPlayerCards * zones = card->target->controller()->game; - zones->putInZone(card->target,zones->inPlay,zones->hand); - break; - } - case 1235: //Aspect of Wolf - { - game->addObserver(NEW AAspectOfWolf(_id, card, card->target)); - break; - } - case 1236: //Birds of Paradise - { - for (int i = MTG_COLOR_GREEN; i <= MTG_COLOR_WHITE; i++){ - int output[]={i,1}; - game->addObserver(NEW AManaProducer(_id + i, card, NEW ManaCost(output,1))); - } - break; - } - case 1240: //Crumble - { - card->target->controller()->game->putInGraveyard(card->target); - card->target->controller()->life+= card->target->getManaCost()->getConvertedCost(); - break; - } - case 1251: //Hurricane - { - int x = spell->cost->getConvertedCost() - 1; - for (int i = 0; i < 2 ; i++){ - game->mLayers->stackLayer()->addDamage(card, game->players[i], x); - for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ - MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; - if (current->basicAbilities[FLYING] && current->isACreature()){ - game->mLayers->stackLayer()->addDamage(card, current, x); - } - } - } - break; - } - case 1262: //Regeneration - { - int cost[] = {MTG_COLOR_GREEN, 1}; - game->addObserver(NEW AStandardRegenerate(_id,card,card->target,NEW ManaCost(cost,1))); - break; - } - case 1263: //Regrowth - { - MTGPlayerCards * zones = game->currentlyActing()->game; - zones->putInZone(card->target,zones->graveyard,zones->hand); - break; - } - case 1266: //stream of life - { - int x = spell->cost->getConvertedCost() - 1; //TODO Improve that ! - spell->getNextPlayerTarget()->life += x; - break; - } - case 1270: //tranquility - { - destroyAllFromTypeInPlay("enchantment", card); - break; - } - case 1271: //Tsunami - { - destroyAllFromTypeInPlay("island", card); - break; - } - case 1231: //Volcanic Eruption - { - int x = spell->cost->getConvertedCost() - 3; - int _x = x; - MTGCardInstance * target = spell->getNextCardTarget(); - while(target && _x){ - game->mLayers->stackLayer()->addPutInGraveyard(target); - _x--; - target = spell->getNextCardTarget(target); - } - x-=_x; - for (int i = 0; i < 2 ; i++){ - game->mLayers->stackLayer()->addDamage(card, game->players[i], x); - for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ - MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; - if (current->isACreature()){ - game->mLayers->stackLayer()->addDamage(card, current, x); - } - } - } - break; - } - case 1278: //Web - { - game->addObserver(NEW APowerToughnessModifier(_id, card, card->target, 0,2)); - game->addObserver(NEW ABasicAbilityModifier(_id + 1, card, card->target, REACH)); - break; - } - case 1280: //Atog - { - game->addObserver(NEW AAtog(_id, card)); - break; - } - case 1285: //Dwarven Warriors{ - { - CreatureTargetChooser * tc = NEW CreatureTargetChooser(card); - tc->maxpower = 2; - game->addObserver(NEW ABasicAbilityModifierUntilEOT(_id, card, UNBLOCKABLE, NULL,tc)); - break; - } - case 1288: //EarthBind - { - game->addObserver(NEW AEarthbind(_id, card, card->target)); - break; - } - case 1289: //earthquake - { - int x = spell->cost->getConvertedCost() - 1; - for (int i = 0; i < 2 ; i++){ - game->mLayers->stackLayer()->addDamage(card, game->players[i], x); - for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ - MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; - if (!current->basicAbilities[FLYING] && current->isACreature()){ - game->mLayers->stackLayer()->addDamage(card, current, x); - } - } - } - break; - } - case 1344: //Eye for an Eye - { - Damage * damage = spell->getNextDamageTarget(); - if (damage){ - game->mLayers->stackLayer()->addDamage(card,damage->source->controller(),damage->damage); - } - break; - } - case 1243: //Fastbond - { - game->addObserver(NEW AFastbond(_id, card)); - break; - } - case 1293: //FlashFires - { - destroyAllFromTypeInPlay("plains", card); - break; - } - case 1301: // Keldon Warlord - { - game->addObserver(NEW AKeldonWarlord(_id, card)); - break; - } - case 1302: //Kird Ape - { - game->addObserver(NEW AKirdApe(_id, card)); - break; - } - case 1309: //Orcish Artillery - { - game->addObserver(NEW AOrcishArtillery(_id, card)); - break; - } - case 1310: //Orcish Oriflame - { - game->addObserver(NEW AOrcishOriflame(_id, card)); - break; - } - case 1317: //ShatterStorm - { - destroyAllFromTypeInPlay("artifact", card, 1); - break; - } - case 1326: //Wheel of fortune - { - for (int i = 0; i < 2; i++){ - MTGLibrary * library = game->players[i]->game->library; - MTGHand * hand = game->players[i]->game->hand; - for (int j = hand->nb_cards-1; j>=0; j--){ - game->players[i]->game->putInGraveyard(hand->cards[j]); - } - for(int j = 0; j < 7; j++){ - game->players[i]->game->drawFromLibrary(); - } - } - break; - } - case 1328: //Armageddon - { - destroyAllFromTypeInPlay("land", card); - break; - } - case 1331: //Black Ward - { - game->addObserver(NEW AProtectionFrom( _id,card, card->target, MTG_COLOR_BLACK)); - break; - } - case 1333: //Blue Ward - { - game->addObserver(NEW AProtectionFrom( _id,card, card->target, MTG_COLOR_BLUE)); - break; - } - case 1334: //Castle - { - game->addObserver(NEW ACastle(_id,card)); - break; - } - case 1238: //Cockatrice - { - game->addObserver(NEW AOldSchoolDeathtouch(_id,card)); - break; - } - case 1341: //Crusade: - { - game->addObserver(NEW ABadMoon(_id,card, MTG_COLOR_WHITE)); - break; - - } - case 1346: //Green Ward - { - game->addObserver(NEW AProtectionFrom( _id,card, card->target, MTG_COLOR_GREEN)); - break; - } - case 1352: //Karma - { - game->addObserver(NEW AKarma(_id, card)); - break; - } - case 1355: //Northern Paladin - { - game->addObserver(NEW ANorthernPaladin(_id, card)); - break; - } - case 1359: //Red Ward - { - game->addObserver(NEW AProtectionFrom( _id,card, card->target, MTG_COLOR_RED)); - break; - } - case 1360: //Resurrection - { - Player * p = card->controller(); - AbilityFactory af; - af.putInPlayFromZone(card->target, p->game->graveyard, p); - break; - } - case 1362: //Reverse polarity - { - ActionStack * as = game->mLayers->stackLayer(); - Player * controller = card->controller(); - Damage * current = ((Damage *)as->getNext(NULL,ACTION_SPELL, RESOLVED_OK)); - while(current){ - if (current->target == controller && current->source->hasType("artifact")){ - controller->life+= current->damage * 2; - } - current = ((Damage *)as->getNext(current,ACTION_SPELL, RESOLVED_OK)); - } - break; - } - case 1225: //Stasis - { - game->addObserver(NEW AStasis(_id, card)); - break; - } - - case 1367: //Sword to Plowshares - { - card->target->controller()->life+= card->target->power; - card->target->controller()->game->inPlay->removeCard(card->target); - break; - } - case 1182: //Terror - { - if (card->target->hasColor(MTG_COLOR_BLACK) || card->target->hasSubtype("artifact")){ - }else{ - card->target->controller()->game->putInGraveyard(card->target); - } - break; - } - case 1267: //Thicket Basilic - { - game->addObserver(NEW AOldSchoolDeathtouch(_id,card)); - break; - } - case 1227: //Toughtlace - { - if (card->target){ - card->target->setColor(MTG_COLOR_BLUE, 1); - }else{ - Spell * starget = spell->getNextSpellTarget(); - starget->source->setColor(MTG_COLOR_BLUE, 1); - } - break; - } - case 1371: //White Ward - { - game->addObserver(NEW AProtectionFrom( _id,card, card->target, MTG_COLOR_WHITE)); - break; - } - case 1372: //Wrath of God - { - destroyAllFromTypeInPlay("creature", card); //TODO -> bury !!! - break; - } - - - // Addons ALA - - case 175114: // Master of Etherium - { - game->addObserver(NEW ACreaturePowerToughnessModifierForAllTypeControlled(_id,card,"artifact")); - break; - } - - case 174989: // Wild Nacatl - { - game->addObserver(NEW AGenericKirdApe(_id,card,"plains",1,1)); - game->addObserver(NEW AGenericKirdApe(_id,card,"moutain",1,1)); - break; - } - - //Addons The Dark - - case 1797: //Inferno does 6 damage to all players and all creatures. - { - for (int i = 0; i < 2 ; i++){ - game->mLayers->stackLayer()->addDamage(card, game->players[i], 6); - for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ - MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; - if (current->isACreature()){ - game->mLayers->stackLayer()->addDamage(card, current, 6); - } - } - } - break; - } - - case 1773 : //People of the Woods - { - game->addObserver(NEW APeopleOfTheWoods(_id, card)); - break; - } - - case 1818: //Tivadar's Crusade - { - destroyAllFromTypeInPlay("goblin", card); - break; - } - - //Addons Legends - case 1470: //Acid Rain - { - destroyAllFromTypeInPlay("forest", card); - break; - } - case 1427: //Abomination - { - game->addObserver(NEW AAbomination(_id,card)); - break; - } - case 1533: //Livingplane - { - game->addObserver(NEW AConvertLandToCreatures(id, card, "land")); - break; - } - case 1607: //Divine Offering - { - card->target->controller()->game->putInGraveyard(card->target); - game->currentlyActing()->life+= card->target->getManaCost()->getConvertedCost(); - break; - } - case 1625: //Lifeblood - { - game->addObserver(NEW AGiveLifeForTappedType (_id, card, "island")); - break; - } - //Addons ICE-AGE Cards - case 2631: //Jokulhaups - { - destroyAllFromTypeInPlay("artifact", card); - destroyAllFromTypeInPlay("creature", card); - destroyAllFromTypeInPlay("land", card); - break; - } - - case 2650: //Pyroclasm Need to be improved copied from hurricane with does 0 dammage to player and does 2 dammage to each creature - { - int x = 2; - for (int i = 0; i < 2 ; i++){ - game->mLayers->stackLayer()->addDamage(card, game->players[i], 0);// To be removed ? - for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ - MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; - if (current->isACreature()){ - game->mLayers->stackLayer()->addDamage(card, current, x); - } - } - } - break; - } - case 2660: //Word of Blasting - { - card->target->controller()->game->putInGraveyard(card->target); - card->target->controller()->life-= card->target->getManaCost()->getConvertedCost(); - break; - } - case 2443: //Dark Banishing - { - if (card->target->hasColor(MTG_COLOR_BLACK)){ - }else{ - card->target->controller()->game->putInGraveyard(card->target); - } - break; - } - case 2593: //Thoughtleech - { - game->addObserver(NEW AGiveLifeForTappedType (_id, card, "island")); - break; - } - case 2484: //Songs of the Damned - { - int mana = card->controller()->game->graveyard->countByType("creature"); - game->currentlyActing()->getManaPool()->add(MTG_COLOR_BLACK, mana); - break; - } - case 2606: //Anarchy - { - destroyAllFromColorInPlay(MTG_COLOR_WHITE, card); - break; - } - case 2474: //Minion of Leshrac - { - game->addObserver(NEW AMinionofLeshrac( _id, card)); - break; - } - case 2421: //Shield of the Age - { - game->addObserver(NEW AShieldOfTheAge( _id, card)); - break; - } - case 2487: //Spoil of Evil - { - int mana_cr = game->opponent()->game->graveyard->countByType("creature"); - int mana_ar = game->opponent()->game->graveyard->countByType("artifact"); - int spoil = mana_ar + mana_cr; - game->currentlyActing()->getManaPool()->add(MTG_COLOR_ARTIFACT, spoil); - game->currentlyActing()->life+= spoil; - break; - } - case 2435: //Whalebone Glider - { - int cost[] = {MTG_COLOR_ARTIFACT,2}; - CreatureTargetChooser * tc = NEW CreatureTargetChooser(card); - tc->maxpower = 3; - game->addObserver(NEW ABasicAbilityModifierUntilEOT(_id, card, FLYING, NEW ManaCost(cost,1),tc)); - break; - } - case 2393: //Aegis of the Meek work but work also for 0/1 creatures... :D - { - int cost[] = {MTG_COLOR_ARTIFACT,1}; - CreatureTargetChooser * tc = NEW CreatureTargetChooser(card); - tc->maxpower = 1; - tc->maxtoughness =1; - game->addObserver(NEW ATargetterPowerToughnessModifierUntilEOT(id, card, 1,2, NEW ManaCost(cost,1),tc)); - break; - } - case 2703: // Lost Order of Jarkeld - { - game->addObserver(NEW ALostOrderofJarkeld(_id, card)); - break; - } - default: - break; - } - - if (card->basicAbilities[LIFELINK]){ - ALifeLink * ability = NEW ALifeLink(_id, card); - game->addObserver(ability); - } - - for (int i=PROTECTIONGREEN; i <= PROTECTIONWHITE; i++){ - if (card->basicAbilities[i]){ - game->addObserver(NEW AProtectionFrom(_id, card, card, i - PROTECTIONGREEN + MTG_COLOR_GREEN)); - } - } - - if (card->basicAbilities[EXALTED]){ - game->addObserver(NEW AExalted(_id, card)); - } - - // Tested works the first r10 did not function because of the mistake in the array of the definition - if (card->basicAbilities[FORESTHOME]){ - game->addObserver(NEW AStrongLandLinkCreature(_id, card, "forest")); - } - if (card->basicAbilities[ISLANDHOME]){ - game->addObserver(NEW AStrongLandLinkCreature(_id, card, "island")); - } - if (card->basicAbilities[MOUNTAINHOME]){ - game->addObserver(NEW AStrongLandLinkCreature(_id, card,"moutain")); - } - if (card->basicAbilities[SWAMPHOME]){ - game->addObserver(NEW AStrongLandLinkCreature(_id, card,"swamp")); - } - if (card->basicAbilities[PLAINSHOME]){ - game->addObserver(NEW AStrongLandLinkCreature(_id, card,"plains")); - } - // New Abilities Flanking and Rampage - - if (card->basicAbilities [RAMPAGE1]){ - game->addObserver (NEW ARampageAbility(_id, card, 1, 1)); - } - - //Instants are put in the graveyard automatically if that's not already done - if (!putSourceInGraveyard){ - if (card->hasType("instant") || card->hasType("sorcery")){ - putSourceInGraveyard = 1; - } - } - if (putSourceInGraveyard == 1){ - MTGPlayerCards * zones = card->controller()->game; - zones->putInGraveyard(card); - } -} - -MTGAbility::MTGAbility(int id, MTGCardInstance * card):ActionElement(id){ - game = GameObserver::GetInstance();; - source = card; - target = card; -} - -MTGAbility::MTGAbility(int id, MTGCardInstance * _source,Damageable * _target ):ActionElement(id){ - game = GameObserver::GetInstance();; - source = _source; - target = _target; -} - -MTGAbility::~MTGAbility(){ - -} - -//returns 1 if this ability needs to be removed from the list of active abilities -int MTGAbility::testDestroy(){ - if (!game->isInPlay(source)){ - return 1; - } - if (target && !game->isInPlay((MTGCardInstance *)target)){ - source->controller()->game->putInGraveyard(source);//TODO put this in a better place ??? - return 1; - } - return 0; -} - - - -int MTGAbility::fireAbility(){ - game->mLayers->stackLayer()->addAbility(this); - return 1; -} - -// - -ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _cost, int _playerturnonly,int tap):MTGAbility(id,card), cost(_cost), playerturnonly(_playerturnonly), needsTapping(tap){ -} - - -int ActivatedAbility::isReactingToClick(MTGCardInstance * card){ - Player * player = game->currentPlayer; - if (!playerturnonly) player = game->currentlyActing(); - if (card == source && (!cost || player->getManaPool()->canAfford(cost)) && source->controller()==player && (!needsTapping || (!source->isTapped() && !source->hasSummoningSickness())) && player==game->currentlyActing()) - return 1; - return 0; -} - -int ActivatedAbility::reactToClick(MTGCardInstance * card){ - if (!isReactingToClick(card)) return 0; - if (needsTapping) source->tapped = 1; - if (cost) game->currentlyActing()->getManaPool()->pay(cost); - fireAbility(); - return 1; - -} - -int ActivatedAbility::reactToTargetClick(Targetable * object){ - if (!isReactingToTargetClick(object)) return 0; - if (needsTapping) source->tapped = 1; - if (cost) game->currentlyActing()->getManaPool()->pay(cost); - fireAbility(); - return 1; - -} - - -ActivatedAbility::~ActivatedAbility(){ - if (cost) delete cost; -} - -// - -TargetAbility::TargetAbility(int id, MTGCardInstance * card, TargetChooser * _tc,ManaCost * _cost, int _playerturnonly,int tap):ActivatedAbility(id, card,_cost,_playerturnonly, tap){ - tc = _tc; -} - -TargetAbility::TargetAbility(int id, MTGCardInstance * card,ManaCost * _cost, int _playerturnonly,int tap):ActivatedAbility(id, card,_cost,_playerturnonly, tap){ - tc = NULL; -} - -void TargetAbility::Update(float dt){ - JGE * mEngine = JGE::GetInstance(); - if (waitingForAnswer){ - if(mEngine->GetButtonClick(PSP_CTRL_CROSS)){ - waitingForAnswer = 0; - }else if(tc->targetsReadyCheck() == TARGET_OK_FULL){ - waitingForAnswer = 0; - ActivatedAbility::reactToClick(source); - } - } -} - -int TargetAbility::reactToTargetClick(Targetable * object){ - if (object->typeAsTarget() == TARGET_CARD) return reactToClick((MTGCardInstance *)object); - if (waitingForAnswer){ - tc->toggleTarget(object); - return 1; - } - return 0; -} - - -int TargetAbility::reactToClick(MTGCardInstance * card){ - if (!waitingForAnswer) { - if (isReactingToClick(card)){ - waitingForAnswer = 1; - tc->initTargets(); - } - }else{ - if (card == source){ - if (tc->targetsReadyCheck() == TARGET_OK){ - waitingForAnswer = 0; - ActivatedAbility::reactToClick(source); - } - }else{ - tc->toggleTarget(card); - } - } - return 1; -} - -void TargetAbility::Render(){ - //TODO -} - - -// - - -TriggeredAbility::TriggeredAbility(int id, MTGCardInstance * card, Damageable * _target):MTGAbility(id,card, _target){ -} - - -TriggeredAbility::TriggeredAbility(int id, MTGCardInstance * card):MTGAbility(id,card){ -} - -void TriggeredAbility::Update(float dt){ - if (trigger()) fireAbility(); -} - - - -// -InstantAbility::InstantAbility(int _id, MTGCardInstance * source):MTGAbility(_id, source){ - init = 0; - for (int i = 0; i < 2; i++){ - if(game->players[i]->game->inPlay->hasCard(source)){ - game->players[i]->game->putInGraveyard(source); - } - } -} - -void InstantAbility::Update(float dt){ - if (!init){ - init = resolve(); - } -} - -InstantAbility::InstantAbility(int _id, MTGCardInstance * source, Damageable * _target):MTGAbility(_id, source, _target){ - init = 0; - for (int i = 0; i < 2; i++){ - if(game->players[i]->game->inPlay->hasCard(source)){ - game->players[i]->game->putInGraveyard(source); - } - } -} - - - -//Instant abilities last generally until the end of the turn -int InstantAbility::testDestroy(){ - int newPhase = game->getCurrentGamePhase(); - if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP) return 1; - currentPhase = newPhase; - return 0; - -} - - -void ListMaintainerAbility::Update(float dt){ - map::iterator it=cards.begin(); - while(it != cards.end()){ - MTGCardInstance * card = (*it).first; - it++; - int doDelete = 1; - for (int i = 0; i < 2; i++){ - Player * p = game->players[i]; - MTGGameZone * zones[] = {p->game->inPlay}; - for (int k = 0; k < 1; k++){ - MTGGameZone * zone = zones[k]; - if (zone->hasCard(card)){ - doDelete = 0; - break; - } - } - } - if (doDelete || !canBeInList(card)){ -#if defined (WIN32) || defined (LINUX) - OutputDebugString("DELETE FRO LISTMAINTAINER\n"); -#endif - cards.erase(card); - removed(card); - } - } - for (int i = 0; i < 2; i++){ - Player * p = game->players[i]; - MTGGameZone * zones[] = {p->game->inPlay}; - for (int k = 0; k < 1; k++){ - MTGGameZone * zone = zones[k]; - for (int j = 0; j < zone->nb_cards; j++){ - if (canBeInList(zone->cards[j])){ - if(cards.find(zone->cards[j]) == cards.end()){ - cards[zone->cards[j]] = true; - added(zone->cards[j]); - } - } - } - } - } -} - -//Destroy the spell -> remove all targets -int ListMaintainerAbility::destroy(){ - map::iterator it; - - for ( it=cards.begin() ; it != cards.end(); it++ ){ - removed((*it).first); - } - cards.clear(); - return 1; -} +#include "../include/debug.h" +#include "../include/MTGAbility.h" +#include "../include/ManaCost.h" +#include "../include/MTGGameZones.h" +#include "../include/AllAbilities.h" +#include "../include/Damage.h" +#include "../include/TargetChooser.h" +#include "../include/CardGui.h" +#include "../include/MTGDeck.h" + +int AbilityFactory::destroyAllFromTypeInPlay(const char * type, MTGCardInstance * source, int bury){ + GameObserver * game = GameObserver::GetInstance(); + for (int i = 0; i < 2 ; i++){ + for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ + MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; + if (current->hasType(type)){ + if (bury){ + game->players[i]->game->putInGraveyard(current); + }else{ + game->mLayers->stackLayer()->addPutInGraveyard(current); + } + } + } + } + return 1; +} + +int AbilityFactory::destroyAllFromColorInPlay(int color, MTGCardInstance * source, int bury){ + GameObserver * game = GameObserver::GetInstance(); + for (int i = 0; i < 2 ; i++){ + for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ + MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; + if (current->hasColor(color)){ + if (bury){ + game->players[i]->game->putInGraveyard(current); + }else{ + game->mLayers->stackLayer()->addPutInGraveyard(current); + } + } + } + } + return 1; +} + +int AbilityFactory::putInPlayFromZone(MTGCardInstance * card, MTGGameZone * zone, Player * p){ + Spell * spell = NEW Spell(card); + p->game->putInZone(card, zone, p->game->stack); + spell->resolve(); + delete spell; + return 1; +} + + +Trigger * AbilityFactory::parseTrigger(string magicText){ + int found = magicText.find("@"); + if (found == string::npos) return NULL; + + //Next Time... + found = magicText.find("next"); + if (found != string::npos){ + for (int i = 0; i < NB_MTG_PHASES; i++){ + found = magicText.find(MTGPhaseCodeNames[i]); + if (found != string::npos){ + return NEW TriggerNextPhase(i); + } + } + } + + return NULL; +} + +//Some basic functionalities that can be added automatically in the text file +int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card){ + int dryMode = 0; + if (!spell) dryMode = 1; + GameObserver * game = GameObserver::GetInstance(); + if (!card) card = spell->source; + MTGCardInstance * target = card->target; + if (!target) target = card; + string magicText = card->magicText; + if (card->alias && magicText.size() == 0){ + //An awful way to get access to the aliasedcard + magicText = GameObserver::GetInstance()->players[0]->game->collection->getCardById(card->alias)->magicText; + } + string s; + int size = magicText.size(); + if (size == 0) return 0; + unsigned int found; + int result = id; + + + while (magicText.size()){ + found = magicText.find("\n"); + if (found != string::npos){ + s = magicText.substr(0,found); + magicText = magicText.substr(found+1); + }else{ + s = magicText; + magicText = ""; + } +#if defined (WIN32) || defined (LINUX) + char buf[4096]; + sprintf(buf, "AUTO ACTION: %s\n", s.c_str()); + OutputDebugString(buf); +#endif + + TargetChooser * tc = NULL; + int doTap = 0; + string lordType = ""; + + Trigger * trigger = parseTrigger(s); + //Dirty way to remove the trigger text (could get in the way) + if (trigger){ + found = s.find(":"); + s = s.substr(found+1); + } + + //Tap in the cost ? + if (s.find("{t}") != string::npos) doTap = 1; + + //Target Abilities + found = s.find("target("); + if (found != string::npos){ + int end = s.find(")"); + string target = s.substr(found + 7,end - found - 7); + TargetChooserFactory tcf; + tc = tcf.createTargetChooser(target, card); + + } + + //Lord + found = s.find("lord("); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + unsigned int end = s.find(")", found+5); + if (end != string::npos){ + lordType = s.substr(found+5,end-found-5).c_str(); + } + } + + //Champion. Very basic, needs to be improved ! + found = s.find("champion(name:"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + unsigned int end = s.find(")", found+14); + if (end != string::npos){ + string type = s.substr(found+14,end-found-14).c_str(); + game->addObserver(NEW APlagueRats(id,card,type.c_str())); + result++; + continue; + } + } + + //Untapper (Ley Druid...) + found = s.find("untap"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + ManaCost * cost = ManaCost::parseManaCost(s); + if (tc){ + game->addObserver(NEW AUntaper(id, card, cost, tc)); + }else{ + target->tapped = 0; + } + + result++; + continue; + } + + //Tapper (icy manipulator) + found = s.find("tap"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + ManaCost * cost = ManaCost::parseManaCost(s); + if (tc){ + game->addObserver(NEW ATapper(id, card, cost, tc)); + }else{ + target->tapped = 1; + } + + result++; + continue; + } + + //Regeneration + found = s.find("}:regenerate"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + ManaCost * cost = ManaCost::parseManaCost(s); + + if (lordType.size() > 0){ + game->addObserver(NEW ALord(id,card,lordType.c_str(),0,0,-1,cost)); + }else{ + + if (tc){ + //TODO + }else{ + game->addObserver(NEW AStandardRegenerate(id, card, target, cost)); + //TODO death ward ! + } + } + result++; + continue; + } + //Bury + found = s.find("bury"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_BAD; + if (tc){ + game->addObserver(NEW ABurier(id, card,tc)); + }else{ + target->controller()->game->putInGraveyard(target); + } + result++; + continue; + } + //Destroy + found = s.find("destroy"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_BAD; + if (tc){ + game->addObserver(NEW ADestroyer(id, card,tc)); + }else{ + game->mLayers->stackLayer()->addPutInGraveyard(target); + } + result++; + continue; + } + + //Damage + found = s.find("damage"); + if (found != string::npos){ + unsigned int start = s.find(":",found); + unsigned int end = s.find(" ",start); + int damage; + ManaCost * cost = ManaCost::parseManaCost(s); + if (end != string::npos){ + damage = atoi(s.substr(start+1,end-start-1).c_str()); + }else{ + damage = atoi(s.substr(start+1).c_str()); + } + if (dryMode) return BAKA_EFFECT_BAD; + if (tc){ + game->addObserver(NEW ADamager(id, card, cost, damage, tc,doTap)); + }else{ + delete cost; + game->mLayers->stackLayer()->addDamage(card,spell->getNextDamageableTarget(), damage); + } + result++; + continue; + } + + //gain/lose life + found = s.find("life"); + if (found != string::npos){ + unsigned int start = s.find(":",found); + unsigned int end = s.find(" ",start); + int life; + ManaCost * cost = ManaCost::parseManaCost(s); + if (end != string::npos){ + life = atoi(s.substr(start+1,end-start-1).c_str()); + }else{ + life = atoi(s.substr(start+1).c_str()); + } + if (dryMode) return BAKA_EFFECT_GOOD; + if (tc){ + //TODO ? + }else{ + if (cost->getConvertedCost() == 0 && !doTap){ + delete cost; + card->controller()->life+=life; + }else{ + //TODO; + } + } + result++; + continue; + } + + //Draw + found = s.find("draw:"); + if (found != string::npos){ + unsigned int start = s.find(":",found); + unsigned int end = s.find(" ",start); + int nbcards; + ManaCost * cost = ManaCost::parseManaCost(s); + if (end != string::npos){ + nbcards = atoi(s.substr(start+1,end-start-1).c_str()); + }else{ + nbcards = atoi(s.substr(start+1).c_str()); + } + if (dryMode) return BAKA_EFFECT_GOOD; + if (trigger){ + DrawEvent * action = NEW DrawEvent(card->controller(),nbcards); + game->addObserver(NEW GenericTriggeredAbility(id, card,trigger,action)); + }else{ + if (tc){ + //TODO ? + }else{ + if (cost->getConvertedCost() == 0){ + delete cost; + game->mLayers->stackLayer()->addDraw(card->controller(),nbcards); + }else{ + game->addObserver(NEW ADrawer(id,card,cost,nbcards,doTap)); + } + } + } + result++; + continue; + } + + //Change Power/Toughness + found = s.find("/"); + if (found != string::npos){ + unsigned int start = s.find(":"); + if (start == string::npos) start = -1; + int power = atoi(s.substr(start+1,size-found).c_str()); + unsigned int end = s.find(" ",start); + int toughness; + if (end != string::npos){ + toughness = atoi(s.substr(found+1,end-found-1).c_str()); + }else{ + toughness = atoi(s.substr(found+1).c_str()); + } + if (dryMode){ + if (power >=0 && toughness >= 0 ) return BAKA_EFFECT_GOOD; + return BAKA_EFFECT_BAD; + } + int limit = 0; + unsigned int limit_str = s.find("limit:"); + if (limit_str != string::npos){ + limit = atoi(s.substr(limit_str+6).c_str()); + } + ManaCost * cost = ManaCost::parseManaCost(s); + + if (lordType.size() > 0){ + game->addObserver(NEW ALord(id,card,lordType.c_str(),power,toughness)); + }else{ + if(tc){ + game->addObserver(NEW ATargetterPowerToughnessModifierUntilEOT(id, card,power,toughness, cost, tc)); + }else{ + if (cost->getConvertedCost() == 0){ + delete cost; + if(card->hasType("enchantment")){ + game->addObserver(NEW APowerToughnessModifier(id, card, target,power,toughness)); + }else{ + game->addObserver(NEW AInstantPowerToughnessModifierUntilEOT(id, card, target,power,toughness)); + } + }else{ + game->addObserver(NEW APowerToughnessModifierUntilEndOfTurn(id, card, target,power,toughness, cost, limit)); + } + } + } + result++; + continue; + } + + //Mana Producer + found = s.find("add"); + if (found != string::npos){ + if (dryMode) return BAKA_EFFECT_GOOD; + ManaCost * cost = ManaCost::parseManaCost(s.substr(0,found)); + ManaCost * output = ManaCost::parseManaCost(s.substr(found)); + if (cost->getConvertedCost()){ + game->addObserver(NEW AManaProducer(id, target, output, cost)); + }else{ + delete cost; + if (doTap){ + game->addObserver(NEW AManaProducer(id, target, output)); + }else{ + card->controller()->getManaPool()->add(output); + delete output; + } + + } + result++; + continue; + } + + //Gain/loose Ability + for (int j = 0; j < NB_BASIC_ABILITIES; j++){ + found = s.find(MTGBasicAbilities[j]); + if (found!= string::npos){ + int modifier = 1; + if (found > 0 && s[found-1] == '-') modifier = 0; + if (dryMode){ + if (j == DEFENDER){ + if (modifier == 1) return BAKA_EFFECT_BAD; + return BAKA_EFFECT_GOOD; + }else{ + if (modifier == 1) return BAKA_EFFECT_GOOD; + return BAKA_EFFECT_BAD; + } + } + ManaCost * cost = ManaCost::parseManaCost(s); + + if (lordType.size() > 0){ + game->addObserver(NEW ALord(id,card,lordType.c_str(),0,0,j)); + }else{ + + if (tc){ + game->addObserver(NEW ABasicAbilityModifierUntilEOT(id, card, j, cost,tc, modifier)); + }else{ + if (cost->getConvertedCost() == 0){ + delete cost; + if(card->hasType("enchantment")){ + game->addObserver(NEW ABasicAbilityModifier(id, card,target, j,modifier)); + }else{ + game->addObserver(NEW AInstantBasicAbilityModifierUntilEOT(id, card,target, j,modifier)); + } + }else{ + game->addObserver(NEW ABasicAbilityAuraModifierUntilEOT(id, card,target, cost,j,modifier)); + } + } + } + result++; + continue; + } + } + } + return result; + + +} + +void AbilityFactory::addAbilities(int _id, Spell * spell){ + MTGCardInstance * card = spell->source; + if (spell->cursor==1) card->target = spell->getNextCardTarget(); + _id = magicText(_id, spell); + int putSourceInGraveyard = 0; //For spells that are not already InstantAbilities; + + + GameObserver * game = GameObserver::GetInstance(); + int id = card->model->getId(); + if (card->alias) id = card->alias; + switch (id){ + case 1092: //Aladdin's lamp + { + AAladdinsLamp * ability = NEW AAladdinsLamp(_id, card); + game->addObserver(ability); + break; + } + case 130550: //Ancestor's chosen + { + int life = card->controller()->game->graveyard->nb_cards; + card->controller()->life+= life; + break; + } + case 1190: //Animate Artifact + { + int x = card->target->getManaCost()->getConvertedCost(); + game->addObserver(NEW AConvertToCreatureAura(_id, card,card->target,x,x)); + break; + } + case 1094: //Ank Of Mishra + { + AAnkhOfMishra * ability = NEW AAnkhOfMishra(_id,card); + game->addObserver(ability); + break; + } + case 1095: //Armageddon clock + { + AArmageddonClock * ability = NEW AArmageddonClock(_id,card); + game->addObserver(ability); + break; + } + case 106525: //Ascendant Evincar + { + game->addObserver(NEW AColorLord(_id, card,MTG_COLOR_BLACK,-1,1,1)); + game->addObserver(NEW AColorLord(_id + 1, card,0,MTG_COLOR_BLACK,-1,-1)); + break; + } + + case 1096: //Basalt Monolith + { + int cost[] = {MTG_COLOR_ARTIFACT, 3}; + AManaProducer * ability = NEW AManaProducer(_id, card, NEW ManaCost(cost,1)); + AUntapManaBlocker * ability2 = NEW AUntapManaBlocker(_id+1, card, NEW ManaCost(cost,1)); + AUnBlocker * ability3 = NEW AUnBlocker(_id+1, card,card, NEW ManaCost(cost,1)); + + game->addObserver(ability); + game->addObserver(ability2); + game->addObserver(ability3); + break; + } + case 1097: //Black Vise + { + game->addObserver( NEW ALifeZoneLink(_id ,card, MTG_PHASE_UPKEEP, 4)); + break; + } + case 1191: //Blue Elemental Blast + { + if (card->target){ + card->target->controller()->game->putInGraveyard(card->target); + }else{ + Spell * starget = spell->getNextSpellTarget(); + game->mLayers->stackLayer()->Fizzle(starget); + } + break; + } + case 1099: //Brass Man + { + int cost[] = {MTG_COLOR_ARTIFACT, 1}; + game->addObserver(NEW AUntapManaBlocker(_id, card, NEW ManaCost(cost,1))); + break; + } + case 1237: //Channel + { + game->addObserver(NEW AChannel(_id, card)); + break; + } + case 1282: //Chaoslace + { + if (card->target){ + card->target->setColor(MTG_COLOR_RED, 1); + }else{ + Spell * starget = spell->getNextSpellTarget(); + starget->source->setColor(MTG_COLOR_RED, 1); + } + break; + } + case 1335: //Circle of protection : black + { + game->addObserver(NEW ACircleOfProtection( _id,card, MTG_COLOR_BLACK)); + break; + } + case 1336: //Circle of protection : blue + { + game->addObserver(NEW ACircleOfProtection( _id,card, MTG_COLOR_BLUE)); + break; + } + case 1337: //Circle of protection : green + { + game->addObserver(NEW ACircleOfProtection( _id,card, MTG_COLOR_GREEN)); + break; + } + case 1338: //Circle of protection : red + { + game->addObserver(NEW ACircleOfProtection( _id,card, MTG_COLOR_RED)); + break; + } + case 1339: //Circle of protection : white + { + game->addObserver(NEW ACircleOfProtection( _id,card, MTG_COLOR_WHITE)); + break; + } + case 1101: //clockwork Beast + { + game->addObserver(NEW AClockworkBeast(_id,card)); + break; + } + case 1102: //Conservator + { + game->addObserver(NEW AConservator(_id,card)); + break; + } + case 1196: //Counterspell + { + Spell * starget = spell->getNextSpellTarget(); + if (starget) game->mLayers->stackLayer()->Fizzle(starget); + break; + } + case 1197: //Creature Bond + { + game->addObserver(NEW ACreatureBond(_id,card, card->target)); + break; + } + case 1103: //Crystal Rod + { + int cost[] = {MTG_COLOR_BLUE, 1}; + ASpellCastLife* ability = NEW ASpellCastLife(_id, card, MTG_COLOR_WHITE,NEW ManaCost(cost,1) , 1); + game->addObserver(ability); + break; + } + case 1151: //Deathgrip + { + int _cost[] = {MTG_COLOR_BLACK, 2}; + game->addObserver(NEW ASpellCounterEnchantment(_id, card, NEW ManaCost(_cost, 1),MTG_COLOR_GREEN)); + break; + } + case 1152: //Deathlace + { + if (card->target){ + card->target->setColor(MTG_COLOR_BLACK, 1); + }else{ + Spell * starget = spell->getNextSpellTarget(); + starget->source->setColor(MTG_COLOR_BLACK, 1); + } + break; + } + case 1105: //dingus Egg + { + ADingusEgg * ability = NEW ADingusEgg(_id,card); + game->addObserver(ability); + break; + } + case 1106: //Disrupting Scepter + { + ADisruptingScepter * ability = NEW ADisruptingScepter(_id,card); + game->addObserver(ability); + break; + } + case 1284: //Dragon Whelp + { + game->addObserver(NEW ADragonWhelp(_id,card)); + break; + } + case 1108: //Ebony Horse + { + AEbonyHorse * ability = NEW AEbonyHorse(_id,card); + game->addObserver(ability); + break; + } + case 1345: //Farmstead + { + game->addObserver(NEW AFarmstead(_id, card,card->target)); + break; + } + case 1291: //Fireball + { + int x = spell->cost->getConvertedCost() - 1; //TODO BETTER + game->addObserver(NEW AFireball(_id, card,spell, x)); + break; + } + case 1245: //Force of Nature + { + game->addObserver(NEW AForceOfNature(_id,card)); + break; + } + case 1110: //Glasses Of Urza + { + AGlassesOfUrza * ability = NEW AGlassesOfUrza(_id,card); + game->addObserver(ability); + break; + } + case 1112: //Howling Mine + { + game->addObserver(NEW AHowlingMine(_id, card)); + break; + } + case 1252: //Instill Energy + { + game->addObserver(NEW AUntaperOnceDuringTurn(_id, card, card->target, NEW ManaCost())); + break; + } + case 1113: //Iron Star + { + int cost[] = {MTG_COLOR_ARTIFACT, 1}; + ASpellCastLife* ability = NEW ASpellCastLife(_id, card, MTG_COLOR_RED,NEW ManaCost(cost,1) , 1); + game->addObserver(ability); + break; + } + case 1351: // Island Sancturay + { + game->addObserver(NEW AIslandSanctuary(_id, card)); + break; + } + case 1114: //Ivory cup + { + int cost[] = {MTG_COLOR_ARTIFACT, 1}; + ASpellCastLife* ability = NEW ASpellCastLife(_id, card, MTG_COLOR_WHITE,NEW ManaCost(cost,1) , 1); + game->addObserver(ability); + break; + } + case 1115: //Ivory Tower + { + game->addObserver(NEW ALifeZoneLink(_id ,card, MTG_PHASE_UPKEEP, 4, 1, 1)); + break; + } + case 1117: //Jandors Ring + { + game->addObserver(NEW AJandorsRing( _id, card)); + break; + } + case 1121: //Kormus Bell + { + game->addObserver(NEW AConvertLandToCreatures(id, card, "swamp")); + break; + } + case 1254: //Kudzu + { + game->addObserver(NEW AKudzu(id, card, card->target)); + break; + } + case 1256: //LifeForce + { + int _cost[] = {MTG_COLOR_GREEN, 2}; + game->addObserver(NEW ASpellCounterEnchantment(_id, card, NEW ManaCost(_cost, 1),MTG_COLOR_BLACK)); + break; + } + case 1257: //Lifelace + { + if (card->target){ + card->target->setColor(MTG_COLOR_GREEN, 1); + }else{ + Spell * starget = spell->getNextSpellTarget(); + starget->source->setColor(MTG_COLOR_GREEN, 1); + } + break; + } + case 1205: //Lifetap + { + game->addObserver(NEW AGiveLifeForTappedType(_id, card, "forest")); + break; + } + case 1259: //Living lands + { + game->addObserver(NEW AConvertLandToCreatures(id, card, "forest")); + break; + } + case 1124: //Mana Vault + { + int output[] = {MTG_COLOR_ARTIFACT, 3}; + game->addObserver(NEW AManaProducer(_id,card,NEW ManaCost(output,1))); + int cost[] = {MTG_COLOR_ARTIFACT, 4}; + game->addObserver(NEW AUntapManaBlocker(_id+1, card, NEW ManaCost(cost,1))); + game->addObserver(NEW ARegularLifeModifierAura(_id+2, card, card, MTG_PHASE_DRAW, -1, 1)); + break; + } + case 1126:// Millstone + { + game->addObserver( NEW AMillstone(_id ,card)); + break; + } + case 1215: //Power Leak + { + game->addObserver( NEW APowerLeak(_id ,card, card->target)); + break; + } + case 1311: //Power Surge + { + game->addObserver( NEW APowerSurge(_id ,card)); + break; + } + case 1358: //Purelace + { + if (card->target){ + card->target->setColor(MTG_COLOR_WHITE, 1); + }else{ + Spell * starget = spell->getNextSpellTarget(); + starget->source->setColor(MTG_COLOR_WHITE, 1); + } + break; + } + case 1312: //Red Elemental Blast + { + if (card->target){ + card->target->controller()->game->putInGraveyard(card->target); + }else{ + Spell * starget = spell->getNextSpellTarget(); + game->mLayers->stackLayer()->Fizzle(starget); + } + break; + } + case 1136: //Soul Net + { + game->addObserver( NEW ASoulNet(_id ,card)); + break; + } + case 1139: //The Rack + { + game->addObserver( NEW ALifeZoneLink(_id ,card, MTG_PHASE_UPKEEP, -3)); + break; + } + case 1140: //Throne of bones + { + int cost[] = {MTG_COLOR_ARTIFACT, 1}; + ASpellCastLife* ability = NEW ASpellCastLife(_id, card, MTG_COLOR_BLACK,NEW ManaCost(cost,1) , 1); + game->addObserver(ability); + break; + } + case 1142: //Wooden Sphere + { + int cost[] = {MTG_COLOR_ARTIFACT, 1}; + ASpellCastLife* ability = NEW ASpellCastLife(_id, card, MTG_COLOR_GREEN,NEW ManaCost(cost,1) , 1); + game->addObserver(ability); + break; + } + case 1143: //Animate Dead + { + game->addObserver(NEW AAnimateDead(_id, card, card->target)); + break; + } + case 1144: //Bad moon + { + game->addObserver(NEW ABadMoon(_id,card)); + break; + } + case 1148 : //Cursed lands + { + game->addObserver(NEW AWanderlust(_id, card, card->target)); + break; + } + case 1156: //Drain Life + { + Damageable * target = spell->getNextDamageableTarget(); + int x = spell->cost->getConvertedCost() - 2; //TODO Fix that !!! + X should be only black mana, that needs to be checked ! + game->mLayers->stackLayer()->addDamage(card, target, x); + if (target->life < x) x = target->life; + game->currentlyActing()->life+=x; + break; + } + case 1159: //Erg Raiders + { + AErgRaiders* ability = NEW AErgRaiders(_id, card); + game->addObserver(ability); + break; + } + case 1164: //Howl from beyond + { + int x = spell->cost->getConvertedCost() - 1; //TODO, this is not enough, Spells shouls have a function like "xCost" because the spell might cost more than expected to launch + AInstantPowerToughnessModifierUntilEOT * ability = NEW AInstantPowerToughnessModifierUntilEOT( _id, card, card->target, x, 0); + game->addObserver(ability); + break; + } + case 1202: //Hurkyl's Recall + { + Player * player = spell->getNextPlayerTarget(); + if (player){ + for (int i = 0; i < 2; i++){ + MTGInPlay * inplay = game->players[i]->game->inPlay; + for (int j= inplay->nb_cards -1 ; j >=0 ; j--){ + MTGCardInstance * card = inplay->cards[j]; + if (card->owner == player && card->hasType("artifact")){ + player->game->putInZone(card, inplay, player->game->hand); + } + } + } + } + break; + } + case 1165: //Hypnotic Specter + { + game->addObserver(NEW AHypnoticSpecter( _id, card)); + break; + } + case 1258: //Living Artifact + { + game->addObserver(NEW ALivingArtifact( _id, card, card->target)); + break; + } + case 1166: //Lord Of The Pit + { + game->addObserver(NEW ALordOfThePit( _id, card)); + break; + } + case 1209: //Mana Short + { + Player * player = spell->getNextPlayerTarget(); + if (player){ + MTGInPlay * inplay = player->game->inPlay; + for (int i = 0; i < inplay->nb_cards; i++){ + MTGCardInstance * current = inplay->cards[i]; + if (current->hasType("land")) current->tapped = 1; + } + player->getManaPool()->init(); + } + break; + } + case 1167: //Mind Twist + { + int xCost = spell->cost->getConvertedCost() - 1; + for (int i = 0; i < xCost; i++){ + game->opponent()->game->discardRandom(game->opponent()->game->hand); + } + break; + } + case 1170: //Nightmare + { + game->addObserver(NEW ANightmare(_id, card)); + break; + } + case 1171: //Paralysis + { + int cost[] = {MTG_COLOR_ARTIFACT, 4}; + game->addObserver(NEW AUntapManaBlocker(_id, card,card->target, NEW ManaCost(cost,1))); + card->target->tapped = 1; + break; + } + case 1172: //Pestilence + { + game->addObserver(NEW APestilence(_id, card)); + break; + } + /*case 1173: //Plague Rats + { + game->addObserver(NEW APlagueRats(_id, card, "Plague Rats")); + break; + } + */ + case 1174: //Raise Dead + { + MTGPlayerCards * zones = game->currentlyActing()->game; + zones->putInZone(card->target,zones->graveyard,zones->hand); + } + case 1176: //Sacrifice + { + ASacrifice * ability = NEW ASacrifice(_id, card, card->target); + game->addObserver(ability); + break; + } + case 1224: //Spell Blast + { + int x = spell->cost->getConvertedCost() - 1; + Spell * starget = spell->getNextSpellTarget(); + if (starget){ + if (starget->cost->getConvertedCost() <= x) game->mLayers->stackLayer()->Fizzle(starget); + } + break; + } + case 1185: //Warp Artifact + { + game->addObserver(NEW ARegularLifeModifierAura(_id, card, card->target, MTG_PHASE_UPKEEP, -1)); + break; + } + case 1192: //BrainGeyser + { + Player * player = ((Player * )spell->targets[0]); + int x = spell->cost->getConvertedCost() - 2; + for (int i = 0; i < x ; i++){ + player->game->drawFromLibrary(); + } + break; + } + case 1194: //Control Magic + { + game->addObserver(NEW ATakeControlAura(_id, card, card->target)); + break; + } + + case 1200 : //Feedback + { + game->addObserver(NEW AWanderlust(_id, card, card->target)); + break; + } + case 129601: //Icy Manipulator + { + int cost[] = {MTG_COLOR_ARTIFACT, 1}; + TypeTargetChooser * tc = new TypeTargetChooser("artifact",card); + tc->addType("land"); + tc->addType("creature"); + game->addObserver(NEW ATapper(_id,card,NEW ManaCost(cost, 1),tc)); + break; + } + + case 1203: //Island Fish + { + int cost[] = {MTG_COLOR_BLUE, 3}; + game->addObserver(NEW AUntapManaBlocker(_id, card, NEW ManaCost(cost,1))); + game->addObserver(NEW AStrongLandLinkCreature(_id, card, "island")); + break; + } + case 1214: //Pirate Ship + { + game->addObserver(NEW AStrongLandLinkCreature(_id, card, "island")); + game->addObserver(NEW ADamager(_id+1, card, NEW ManaCost(), 1)); + break; + } + case 1218: //Psychic Venom + { + game->addObserver(NEW APsychicVenom(_id, card, card->target)); + break; + } + case 1220: //Sea Serpent + { + game->addObserver(NEW AStrongLandLinkCreature(_id, card, "island")); + break; + } + case 1315: //Sedge Troll + { + game->addObserver( NEW ASedgeTroll(_id, card)); + break; + } + case 1221: //Serendib Efreet + { + game->addObserver( NEW ASerendibEfreet(_id, card)); + break; + } + case 1226: //Steal Artifact + { + game->addObserver( NEW AControlStealAura(_id, card, card->target)); + break; + } + case 1228: //Unstable mutation + { + game->addObserver(NEW APowerToughnessModifier(_id, card, card->target, 3, 3)); + game->addObserver(NEW APowerToughnessModifierRegularCounter(_id, card, card->target, MTG_PHASE_UPKEEP, -1, -1)); + break; + } + case 1229: //Unsummon + { + MTGPlayerCards * zones = card->target->controller()->game; + zones->putInZone(card->target,zones->inPlay,zones->hand); + break; + + } + case 1235: //Aspect of Wolf + { + game->addObserver(NEW AAspectOfWolf(_id, card, card->target)); + break; + } + case 1236: //Birds of Paradise + { + for (int i = MTG_COLOR_GREEN; i <= MTG_COLOR_WHITE; i++){ + int output[]={i,1}; + game->addObserver(NEW AManaProducer(_id + i, card, NEW ManaCost(output,1))); + } + break; + } + case 1240: //Crumble + { + card->target->controller()->game->putInGraveyard(card->target); + card->target->controller()->life+= card->target->getManaCost()->getConvertedCost(); + break; + } + case 1251: //Hurricane + { + int x = spell->cost->getConvertedCost() - 1; + for (int i = 0; i < 2 ; i++){ + game->mLayers->stackLayer()->addDamage(card, game->players[i], x); + for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ + MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; + if (current->basicAbilities[FLYING] && current->isACreature()){ + game->mLayers->stackLayer()->addDamage(card, current, x); + } + } + } + break; + } + case 1262: //Regeneration + { + int cost[] = {MTG_COLOR_GREEN, 1}; + game->addObserver(NEW AStandardRegenerate(_id,card,card->target,NEW ManaCost(cost,1))); + break; + } + case 1263: //Regrowth + { + MTGPlayerCards * zones = game->currentlyActing()->game; + zones->putInZone(card->target,zones->graveyard,zones->hand); + break; + } + case 1266: //stream of life + { + int x = spell->cost->getConvertedCost() - 1; //TODO Improve that ! + spell->getNextPlayerTarget()->life += x; + break; + } + case 1270: //tranquility + { + destroyAllFromTypeInPlay("enchantment", card); + break; + } + case 1271: //Tsunami + { + destroyAllFromTypeInPlay("island", card); + break; + } + case 1231: //Volcanic Eruption + { + int x = spell->cost->getConvertedCost() - 3; + int _x = x; + MTGCardInstance * target = spell->getNextCardTarget(); + while(target && _x){ + game->mLayers->stackLayer()->addPutInGraveyard(target); + _x--; + target = spell->getNextCardTarget(target); + } + x-=_x; + for (int i = 0; i < 2 ; i++){ + game->mLayers->stackLayer()->addDamage(card, game->players[i], x); + for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ + MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; + if (current->isACreature()){ + game->mLayers->stackLayer()->addDamage(card, current, x); + } + } + } + break; + } + case 1278: //Web + { + game->addObserver(NEW APowerToughnessModifier(_id, card, card->target, 0,2)); + game->addObserver(NEW ABasicAbilityModifier(_id + 1, card, card->target, REACH)); + break; + } + case 1280: //Atog + { + game->addObserver(NEW AAtog(_id, card)); + break; + } + case 1285: //Dwarven Warriors{ + { + CreatureTargetChooser * tc = NEW CreatureTargetChooser(card); + tc->maxpower = 2; + game->addObserver(NEW ABasicAbilityModifierUntilEOT(_id, card, UNBLOCKABLE, NULL,tc)); + break; + } + case 1288: //EarthBind + { + game->addObserver(NEW AEarthbind(_id, card, card->target)); + break; + } + case 1289: //earthquake + { + int x = spell->cost->getConvertedCost() - 1; + for (int i = 0; i < 2 ; i++){ + game->mLayers->stackLayer()->addDamage(card, game->players[i], x); + for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ + MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; + if (!current->basicAbilities[FLYING] && current->isACreature()){ + game->mLayers->stackLayer()->addDamage(card, current, x); + } + } + } + break; + } + case 1344: //Eye for an Eye + { + Damage * damage = spell->getNextDamageTarget(); + if (damage){ + game->mLayers->stackLayer()->addDamage(card,damage->source->controller(),damage->damage); + } + break; + } + case 1243: //Fastbond + { + game->addObserver(NEW AFastbond(_id, card)); + break; + } + case 1293: //FlashFires + { + destroyAllFromTypeInPlay("plains", card); + break; + } + case 1301: // Keldon Warlord + { + game->addObserver(NEW AKeldonWarlord(_id, card)); + break; + } + case 1302: //Kird Ape + { + game->addObserver(NEW AKirdApe(_id, card)); + break; + } + case 1309: //Orcish Artillery + { + game->addObserver(NEW AOrcishArtillery(_id, card)); + break; + } + case 1310: //Orcish Oriflame + { + game->addObserver(NEW AOrcishOriflame(_id, card)); + break; + } + case 1317: //ShatterStorm + { + destroyAllFromTypeInPlay("artifact", card, 1); + break; + } + case 1326: //Wheel of fortune + { + for (int i = 0; i < 2; i++){ + MTGLibrary * library = game->players[i]->game->library; + MTGHand * hand = game->players[i]->game->hand; + for (int j = hand->nb_cards-1; j>=0; j--){ + game->players[i]->game->putInGraveyard(hand->cards[j]); + } + for(int j = 0; j < 7; j++){ + game->players[i]->game->drawFromLibrary(); + } + } + break; + } + case 1328: //Armageddon + { + destroyAllFromTypeInPlay("land", card); + break; + } + case 1331: //Black Ward + { + game->addObserver(NEW AProtectionFrom( _id,card, card->target, MTG_COLOR_BLACK)); + break; + } + case 1333: //Blue Ward + { + game->addObserver(NEW AProtectionFrom( _id,card, card->target, MTG_COLOR_BLUE)); + break; + } + case 1334: //Castle + { + game->addObserver(NEW ACastle(_id,card)); + break; + } + case 1238: //Cockatrice + { + game->addObserver(NEW AOldSchoolDeathtouch(_id,card)); + break; + } + case 1341: //Crusade: + { + game->addObserver(NEW ABadMoon(_id,card, MTG_COLOR_WHITE)); + break; + + } + case 1346: //Green Ward + { + game->addObserver(NEW AProtectionFrom( _id,card, card->target, MTG_COLOR_GREEN)); + break; + } + case 1352: //Karma + { + game->addObserver(NEW AKarma(_id, card)); + break; + } + case 1355: //Northern Paladin + { + game->addObserver(NEW ANorthernPaladin(_id, card)); + break; + } + case 1359: //Red Ward + { + game->addObserver(NEW AProtectionFrom( _id,card, card->target, MTG_COLOR_RED)); + break; + } + case 1360: //Resurrection + { + Player * p = card->controller(); + AbilityFactory af; + af.putInPlayFromZone(card->target, p->game->graveyard, p); + break; + } + case 1362: //Reverse polarity + { + ActionStack * as = game->mLayers->stackLayer(); + Player * controller = card->controller(); + Damage * current = ((Damage *)as->getNext(NULL,ACTION_SPELL, RESOLVED_OK)); + while(current){ + if (current->target == controller && current->source->hasType("artifact")){ + controller->life+= current->damage * 2; + } + current = ((Damage *)as->getNext(current,ACTION_SPELL, RESOLVED_OK)); + } + break; + } + case 1225: //Stasis + { + game->addObserver(NEW AStasis(_id, card)); + break; + } + + case 1367: //Sword to Plowshares + { + card->target->controller()->life+= card->target->power; + card->target->controller()->game->inPlay->removeCard(card->target); + break; + } + case 1182: //Terror + { + if (card->target->hasColor(MTG_COLOR_BLACK) || card->target->hasSubtype("artifact")){ + }else{ + card->target->controller()->game->putInGraveyard(card->target); + } + break; + } + case 1267: //Thicket Basilic + { + game->addObserver(NEW AOldSchoolDeathtouch(_id,card)); + break; + } + case 1227: //Toughtlace + { + if (card->target){ + card->target->setColor(MTG_COLOR_BLUE, 1); + }else{ + Spell * starget = spell->getNextSpellTarget(); + starget->source->setColor(MTG_COLOR_BLUE, 1); + } + break; + } + case 1371: //White Ward + { + game->addObserver(NEW AProtectionFrom( _id,card, card->target, MTG_COLOR_WHITE)); + break; + } + case 1372: //Wrath of God + { + destroyAllFromTypeInPlay("creature", card); //TODO -> bury !!! + break; + } + +//Addons ICE-AGE Cards + case 2631: //Jokulhaups + { + destroyAllFromTypeInPlay("artifact", card); + destroyAllFromTypeInPlay("creature", card); + destroyAllFromTypeInPlay("land", card); + break; + } + + case 2650: //Pyroclasm Need to be improved copied from hurricane with does 0 dammage to player and does 2 dammage to each creature + { + int x = 2; + for (int i = 0; i < 2 ; i++){ + game->mLayers->stackLayer()->addDamage(card, game->players[i], 0);// To be removed ? + for (int j = 0; j < game->players[i]->game->inPlay->nb_cards; j++){ + MTGCardInstance * current = game->players[i]->game->inPlay->cards[j]; + if (current->isACreature()){ + game->mLayers->stackLayer()->addDamage(card, current, x); + } + } + } + break; + } + case 2660: //Word of Blasting + { + card->target->controller()->game->putInGraveyard(card->target); + card->target->controller()->life-= card->target->getManaCost()->getConvertedCost(); + break; + } + case 2443: //Dark Banishing + { + if (card->target->hasColor(MTG_COLOR_BLACK)){ + }else{ + card->target->controller()->game->putInGraveyard(card->target); + } + break; + } + case 2593: //Thoughtleech + { + game->addObserver(NEW AGiveLifeForTappedType (_id, card, "island")); + break; + } + case 2484: //Songs of the Damned + { + int mana = card->controller()->game->graveyard->countByType("creature"); + game->currentlyActing()->getManaPool()->add(MTG_COLOR_BLACK, mana); + break; + } + case 2606: //Anarchy + { + destroyAllFromColorInPlay(MTG_COLOR_WHITE, card); + break; + } + case 2474: //Minion of Leshrac + { + game->addObserver(NEW AMinionofLeshrac( _id, card)); + break; + } + case 2421: //Shield of the Age + { + game->addObserver(NEW AShieldOfTheAge( _id, card)); + break; + } + case 2487: //Spoil of Evil + { + int mana_cr = game->opponent()->game->graveyard->countByType("creature"); + int mana_ar = game->opponent()->game->graveyard->countByType("artifact"); + int spoil = mana_ar + mana_cr; + game->currentlyActing()->getManaPool()->add(MTG_COLOR_ARTIFACT, spoil); + game->currentlyActing()->life+= spoil; + break; + } + case 2435: //Whalebone Glider + { + int cost[] = {MTG_COLOR_ARTIFACT,2}; + CreatureTargetChooser * tc = NEW CreatureTargetChooser(card); + tc->maxpower = 3; + game->addObserver(NEW ABasicAbilityModifierUntilEOT(_id, card, FLYING, NEW ManaCost(cost,1),tc)); + break; + } + case 2393: //Aegis of the Meek work but work also for 0/1 creatures... :D + { + int cost[] = {MTG_COLOR_ARTIFACT,1}; + CreatureTargetChooser * tc = NEW CreatureTargetChooser(card); + tc->maxpower = 1; + tc->maxtoughness =1; + game->addObserver(NEW ATargetterPowerToughnessModifierUntilEOT(id, card, 1,2, NEW ManaCost(cost,1),tc)); + break; + } + case 2703: // Lost Order of Jarkeld + { + game->addObserver(NEW ALostOrderofJarkeld(_id, card)); + break; + } + default: + break; + } + + if (card->basicAbilities[LIFELINK]){ + ALifeLink * ability = NEW ALifeLink(_id, card); + game->addObserver(ability); + } + + for (int i=PROTECTIONGREEN; i <= PROTECTIONWHITE; i++){ + if (card->basicAbilities[i]){ + game->addObserver(NEW AProtectionFrom(_id, card, card, i - PROTECTIONGREEN + MTG_COLOR_GREEN)); + } + } + + if (card->basicAbilities[EXALTED]){ + game->addObserver(NEW AExalted(_id, card)); + } + + // Tested works the first r10 did not function because of the mistake in the array of the definition + if (card->basicAbilities[FORESTHOME]){ + game->addObserver(NEW AStrongLandLinkCreature(_id, card, "forest")); + } + if (card->basicAbilities[ISLANDHOME]){ + game->addObserver(NEW AStrongLandLinkCreature(_id, card, "island")); + } + if (card->basicAbilities[MOUNTAINHOME]){ + game->addObserver(NEW AStrongLandLinkCreature(_id, card,"moutain")); + } + if (card->basicAbilities[SWAMPHOME]){ + game->addObserver(NEW AStrongLandLinkCreature(_id, card,"swamp")); + } + if (card->basicAbilities[PLAINSHOME]){ + game->addObserver(NEW AStrongLandLinkCreature(_id, card,"plains")); + } + //Instants are put in the graveyard automatically if that's not already done + if (!putSourceInGraveyard){ + if (card->hasType("instant") || card->hasType("sorcery")){ + putSourceInGraveyard = 1; + } + } + if (putSourceInGraveyard == 1){ + MTGPlayerCards * zones = card->controller()->game; + zones->putInGraveyard(card); + } +} + +MTGAbility::MTGAbility(int id, MTGCardInstance * card):ActionElement(id){ + game = GameObserver::GetInstance(); + source = card; + target = card; +} + +MTGAbility::MTGAbility(int id, MTGCardInstance * _source,Damageable * _target ):ActionElement(id){ + game = GameObserver::GetInstance(); + source = _source; + target = _target; +} + +MTGAbility::~MTGAbility(){ + +} + +//returns 1 if this ability needs to be removed from the list of active abilities +int MTGAbility::testDestroy(){ + if (!game->isInPlay(source)){ + return 1; + } + if (target && !game->isInPlay((MTGCardInstance *)target)){ + source->controller()->game->putInGraveyard(source);//TODO put this in a better place ??? + return 1; + } + return 0; +} + + + +int MTGAbility::fireAbility(){ + game->mLayers->stackLayer()->addAbility(this); + return 1; +} + +// + +ActivatedAbility::ActivatedAbility(int id, MTGCardInstance * card, ManaCost * _cost, int _playerturnonly,int tap):MTGAbility(id,card), cost(_cost), playerturnonly(_playerturnonly), needsTapping(tap){ +} + + +int ActivatedAbility::isReactingToClick(MTGCardInstance * card){ + Player * player = game->currentPlayer; + if (!playerturnonly) player = game->currentlyActing(); + if (card == source && (!cost || player->getManaPool()->canAfford(cost)) && source->controller()==player && (!needsTapping || (!source->isTapped() && !source->hasSummoningSickness())) && player==game->currentlyActing()) + return 1; + return 0; +} + +int ActivatedAbility::reactToClick(MTGCardInstance * card){ + if (!isReactingToClick(card)) return 0; + if (needsTapping) source->tapped = 1; + if (cost) game->currentlyActing()->getManaPool()->pay(cost); + fireAbility(); + return 1; + +} + +int ActivatedAbility::reactToTargetClick(Targetable * object){ + if (!isReactingToTargetClick(object)) return 0; + if (needsTapping) source->tapped = 1; + if (cost) game->currentlyActing()->getManaPool()->pay(cost); + fireAbility(); + return 1; + +} + + +ActivatedAbility::~ActivatedAbility(){ + if (cost) delete cost; +} + +// + +TargetAbility::TargetAbility(int id, MTGCardInstance * card, TargetChooser * _tc,ManaCost * _cost, int _playerturnonly,int tap):ActivatedAbility(id, card,_cost,_playerturnonly, tap){ + tc = _tc; +} + +TargetAbility::TargetAbility(int id, MTGCardInstance * card,ManaCost * _cost, int _playerturnonly,int tap):ActivatedAbility(id, card,_cost,_playerturnonly, tap){ + tc = NULL; +} + +void TargetAbility::Update(float dt){ + JGE * mEngine = JGE::GetInstance(); + if (waitingForAnswer){ + if(mEngine->GetButtonClick(PSP_CTRL_CROSS)){ + waitingForAnswer = 0; + }else if(tc->targetsReadyCheck() == TARGET_OK_FULL){ + waitingForAnswer = 0; + ActivatedAbility::reactToClick(source); + } + } +} + +int TargetAbility::reactToTargetClick(Targetable * object){ + if (object->typeAsTarget() == TARGET_CARD) return reactToClick((MTGCardInstance *)object); + if (waitingForAnswer){ + tc->toggleTarget(object); + return 1; + } + return 0; +} + + +int TargetAbility::reactToClick(MTGCardInstance * card){ + if (!waitingForAnswer) { + if (isReactingToClick(card)){ + waitingForAnswer = 1; + tc->initTargets(); + } + }else{ + if (card == source){ + if (tc->targetsReadyCheck() == TARGET_OK){ + waitingForAnswer = 0; + ActivatedAbility::reactToClick(source); + } + }else{ + tc->toggleTarget(card); + } + } + return 1; +} + +void TargetAbility::Render(){ + //TODO +} + + +// + + +TriggeredAbility::TriggeredAbility(int id, MTGCardInstance * card, Damageable * _target):MTGAbility(id,card, _target){ +} + + +TriggeredAbility::TriggeredAbility(int id, MTGCardInstance * card):MTGAbility(id,card){ +} + +void TriggeredAbility::Update(float dt){ + if (trigger()) fireAbility(); +} + + + + // + InstantAbility::InstantAbility(int _id, MTGCardInstance * source):MTGAbility(_id, source){ + init = 0; + for (int i = 0; i < 2; i++){ + if(game->players[i]->game->inPlay->hasCard(source)){ + game->players[i]->game->putInGraveyard(source); + } + } + } + + void InstantAbility::Update(float dt){ + if (!init){ + init = resolve(); + } + } + + InstantAbility::InstantAbility(int _id, MTGCardInstance * source, Damageable * _target):MTGAbility(_id, source, _target){ + init = 0; + for (int i = 0; i < 2; i++){ + if(game->players[i]->game->inPlay->hasCard(source)){ + game->players[i]->game->putInGraveyard(source); + } + } + } + + + + //Instant abilities last generally until the end of the turn + int InstantAbility::testDestroy(){ + int newPhase = game->getCurrentGamePhase(); + if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP) return 1; + currentPhase = newPhase; + return 0; + + } + + + void ListMaintainerAbility::Update(float dt){ + map::iterator it=cards.begin(); + while(it != cards.end()){ + MTGCardInstance * card = (*it).first; + it++; + int doDelete = 1; + for (int i = 0; i < 2; i++){ + Player * p = game->players[i]; + MTGGameZone * zones[] = {p->game->inPlay}; + for (int k = 0; k < 1; k++){ + MTGGameZone * zone = zones[k]; + if (zone->hasCard(card)){ + doDelete = 0; + break; + } + } + } + if (doDelete || !canBeInList(card)){ +#if defined (WIN32) || defined (LINUX) +OutputDebugString("DELETE FRO LISTMAINTAINER\n"); +#endif + cards.erase(card); + removed(card); + } + } + for (int i = 0; i < 2; i++){ + Player * p = game->players[i]; + MTGGameZone * zones[] = {p->game->inPlay}; + for (int k = 0; k < 1; k++){ + MTGGameZone * zone = zones[k]; + for (int j = 0; j < zone->nb_cards; j++){ + if (canBeInList(zone->cards[j])){ + if(cards.find(zone->cards[j]) == cards.end()){ + cards[zone->cards[j]] = true; + added(zone->cards[j]); + } + } + } + } + } + } + + //Destroy the spell -> remove all targets + int ListMaintainerAbility::destroy(){ + map::iterator it; + + for ( it=cards.begin() ; it != cards.end(); it++ ){ + removed((*it).first); + } + cards.clear(); + return 1; + } + + + /* An attempt to globalize triggered abilities as much as possible */ + + MTGAbilityBasicFeatures::MTGAbilityBasicFeatures(){ + game = GameObserver::GetInstance(); + } + MTGAbilityBasicFeatures::MTGAbilityBasicFeatures(MTGCardInstance * _source, Damageable * _target):source(_source),target(_target){ + if (!target) target = source; + game = GameObserver::GetInstance(); + } + void MTGAbilityBasicFeatures::init(MTGCardInstance * _source, Damageable * _target){ + source = source; + target=_target; + if (!target) target = source; + } + + + + TriggerAtPhase::TriggerAtPhase(int _phaseId):Trigger(),phaseId(_phaseId){ + currentPhase = game->getCurrentGamePhase(); + newPhase = -1; + } + + int TriggerAtPhase::trigger(){ + int result = 0; + newPhase = game->getCurrentGamePhase(); + if (currentPhase != newPhase && newPhase == phaseId){ + result = 1; + } + currentPhase = newPhase; + return result; + } + + TriggerNextPhase::TriggerNextPhase(int _phaseId):TriggerAtPhase(_phaseId){ + destroyActivated = 0; + } + + int TriggerNextPhase::testDestroy(){ + if (newPhase <= phaseId) destroyActivated = 1; + if ( newPhase > phaseId && destroyActivated){ + return 1; + } + return 0; + } + + + + + DrawEvent::DrawEvent(Player * _player, int _nbcards):TriggeredEvent(),player(_player),nbcards(_nbcards){ + } + + int DrawEvent::resolve(){ + game->mLayers->stackLayer()->addDraw(player,nbcards); + return nbcards; + } + + + int DestroyCondition::testDestroy(){ + if (!game->isInPlay(source)){ + return 1; + } + if (target && !game->isInPlay((MTGCardInstance *)target)){ + source->controller()->game->putInGraveyard(source);//TODO put this in a better place ??? + return 1; + } + return 0; + } + + + + GenericTriggeredAbility::GenericTriggeredAbility(int id, MTGCardInstance * _source, Trigger * _t, TriggeredEvent * _te, DestroyCondition * _dc , Damageable * _target ): TriggeredAbility(id, _source,_target){ + if (!target) target = source; + t = _t; + te = _te; + dc = _dc; + + t->init(_source,_target); + te->init(_source,_target); + if (dc) dc->init(_source,_target); + } + + int GenericTriggeredAbility::trigger(){ + return t->trigger(); + } + + int GenericTriggeredAbility::resolve(){ + return te->resolve(); + } + + int GenericTriggeredAbility::testDestroy(){ + if (dc) return dc->testDestroy(); + return t->testDestroy(); + } + + GenericTriggeredAbility::~GenericTriggeredAbility(){ + delete t; + delete te; + SAFE_DELETE(dc); + }