From e86e73af2f65b5a144b177e93a3de1908143ab82 Mon Sep 17 00:00:00 2001 From: "jean.chalard" Date: Sun, 16 Nov 2008 05:17:57 +0000 Subject: [PATCH] J : * Remove useless whitespace & carriage returns, reindent. --- projects/mtg/include/AllAbilities.h | 6053 +++++++++++++-------------- projects/mtg/include/MTGAbility.h | 394 +- 2 files changed, 3223 insertions(+), 3224 deletions(-) diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 14b7c0c3c..632e5603e 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -1,3027 +1,3026 @@ - -#ifndef _CARDS_H_ -#define _CARDS_H_ - -#include "MTGAbility.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; - } -}; - -// 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(); - } - } -}; - -// 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; - } - -}; - - - -//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 -//Erwan 2008/11/15 : this cannot work as type is never initialized... -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 "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; + } +}; + +// 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(); + } + } +}; + +// 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; + } + +}; + + + +//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 +//Erwan 2008/11/15 : this cannot work as type is never initialized... +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 diff --git a/projects/mtg/include/MTGAbility.h b/projects/mtg/include/MTGAbility.h index d63064685..ebb1096bc 100644 --- a/projects/mtg/include/MTGAbility.h +++ b/projects/mtg/include/MTGAbility.h @@ -1,197 +1,197 @@ -#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 BuryEvent: public TriggeredEvent{ -public: - 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 destroyAllInPlay(TargetChooser * tc, 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 +#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 enemy 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 BuryEvent: public TriggeredEvent{ + public: + 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 destroyAllInPlay(TargetChooser * tc, 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