#ifndef _CARDS_H_ #define _CARDS_H_ #include "MTGAbility.h" #include "GroupOfCards.h" #include "ManaCost.h" #include "CardDescriptor.h" #include "AIPlayer.h" #include "CardDisplay.h" #include "Subtypes.h" #include "CardGui.h" #include #include #include using std::map; /* Generic classes */ //Drawer, allows to draw a card for a cost: class ADrawer:public ActivatedAbility{ public: int nbcards; ADrawer(int _id, MTGCardInstance * card,ManaCost * _cost, int _nbcards = 1, int _tap = 1):ActivatedAbility(_id, card,_cost,0,_tap),nbcards(_nbcards){ } int resolve(){ game->mLayers->stackLayer()->addDraw(source->controller(),nbcards); return 1; } }; //Destroyer. TargetAbility class ADestroyer:public TargetAbility{ public: int bury; ADestroyer(int _id, MTGCardInstance * _source, TargetChooser * _tc = NULL, int _bury = 0):TargetAbility(_id,_source, tc),bury(_bury){ if (!tc) tc = NEW CreatureTargetChooser(); } int resolve(){ MTGCardInstance * _target = tc->getNextCardTarget(); if(_target){ if (bury){ _target->controller()->game->putInGraveyard(_target); }else{ game->mLayers->stackLayer()->addPutInGraveyard(_target); } return 1; } return 0; } }; //Destroyer. TargetAbility class ABurier:public ADestroyer{ public: ABurier(int _id, MTGCardInstance * _source, TargetChooser * _tc = NULL):ADestroyer(_id,_source, tc,1){ } }; /*Changes one of the basic abilities of target source : spell target : spell target (creature) modifier : 1 to add the ability, 0 to remove it _ability : Id of the ability, as described in mtgdefinitions */ class ABasicAbilityModifier:public MTGAbility{ public: int modifier; int ability; int value_before_modification; ABasicAbilityModifier(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _ability, int _modifier = 1): MTGAbility(_id,_source,_target),modifier(_modifier),ability(_ability){ value_before_modification = ((MTGCardInstance * )target)->basicAbilities[ability]; ((MTGCardInstance * )target)->basicAbilities[ability]=modifier; } int destroy(){ if (((MTGCardInstance * )target)->basicAbilities[ability] == modifier){ ((MTGCardInstance * )target)->basicAbilities[ability] = value_before_modification; return 1; }else{ //BUG !!! return 0; } } }; //Modifies an ability until end of turn. Needs a target class ABasicAbilityModifierUntilEOT:public TargetAbility{ public: MTGCardInstance * mTargets[50]; int nbTargets; int modifier; int stateBeforeActivation[50]; int ability; ABasicAbilityModifierUntilEOT(int _id, MTGCardInstance * _source, int _ability, ManaCost * _cost, TargetChooser * _tc = NULL, int _modifier = 1): TargetAbility(_id,_source,_cost),modifier(_modifier), ability(_ability){ nbTargets = 0; tc = _tc; if (!tc) tc = NEW CreatureTargetChooser(_source); } void Update(float dt){ if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ for (int i = 0; i < nbTargets; i++){ MTGCardInstance * mTarget = mTargets[i]; if(mTarget && mTarget->basicAbilities[ability]){ mTarget->basicAbilities[ability] = stateBeforeActivation[i]; } } nbTargets = 0; } TargetAbility::Update(dt); } int resolve(){ MTGCardInstance * mTarget = tc->getNextCardTarget(); if (mTarget){ mTargets[nbTargets] = mTarget; stateBeforeActivation[nbTargets] = mTarget->basicAbilities[ability]; mTarget->basicAbilities[ability] = modifier; nbTargets++; } return 1; } }; /*Instants that modifies a basic ability until end of turn */ class AInstantBasicAbilityModifierUntilEOT: public InstantAbility{ public: int stateBeforeActivation; int ability; AInstantBasicAbilityModifierUntilEOT(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _ability, int value):InstantAbility(_id, _source, _target),ability(_ability){ stateBeforeActivation = _target->basicAbilities[ability]; _target->basicAbilities[ability] = value; } int destroy(){ ((MTGCardInstance *)target)->basicAbilities[ability] = stateBeforeActivation; return 1; } }; //Alteration of Ability until of turn (Aura) class ABasicAbilityAuraModifierUntilEOT: public ActivatedAbility{ public: int stateBeforeActivation; int ability; int value; ABasicAbilityAuraModifierUntilEOT(int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost, int _ability, int _value = 1):ActivatedAbility(_id,_source, _cost, 0,0), ability(_ability), value(_value){ target = _target; stateBeforeActivation = _target->basicAbilities[ability]; } void Update(float dt){ if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ MTGCardInstance * _target = (MTGCardInstance *) target; _target->basicAbilities[ability] = stateBeforeActivation; } ActivatedAbility::Update(dt); } int resolve(){ MTGCardInstance * _target = (MTGCardInstance *) target; stateBeforeActivation = _target->basicAbilities[ability]; _target->basicAbilities[ability] = value; return 1; } }; /*Gives life each time a spell matching CardDescriptor's criteria are match . Optionnal manacost*/ class ASpellCastLife:public MTGAbility{ public: CardDescriptor trigger; ManaCost * cost; int life; MTGCardInstance * lastUsedOn; MTGCardInstance * lastChecked; ASpellCastLife(int id, MTGCardInstance * _source, CardDescriptor _trigger, ManaCost * _cost, int _life): MTGAbility(id, _source), trigger(_trigger), cost(_cost), life(_life){ } ASpellCastLife(int id, MTGCardInstance * _source, int color, ManaCost * _cost, int _life): MTGAbility(id, _source), cost(_cost), life(_life){ trigger.setColor(color); } int isReactingToClick(MTGCardInstance * _card){ if (_card == source && game->currentlyActing()->game->inPlay->hasCard(source)){ if (game->currentlyActing()->getManaPool()->canAfford(cost)){ Interruptible * laststackitem = game->mLayers->stackLayer()->_(-1); if (laststackitem && laststackitem->type == ACTION_SPELL){ Spell * spell = (Spell*)laststackitem; if (spell->source != lastUsedOn && trigger.match(spell->source)){ lastChecked = spell->source; return 1; } } } } return 0; } int reactToClick(MTGCardInstance * _card){ if (!isReactingToClick( _card)) return 0; game->currentlyActing()->getManaPool()->pay(cost); game->currentlyActing()->life+=life; lastUsedOn = lastChecked; return 1; } }; //Allows to untap at any moment for an amount of mana class AUnBlocker:public MTGAbility{ public: ManaCost * cost; AUnBlocker(int id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost):MTGAbility(id, _source, _target), cost(_cost){ } int isReactingToClick(MTGCardInstance * _card){ if (_card == target && game->currentlyActing()->game->inPlay->hasCard(source) && (MTGCardInstance *) _card->isTapped()){ if (game->currentlyActing()->getManaPool()->canAfford(cost)){ return 1; } } return 0; } int reactToClick(MTGCardInstance * _card){ if (!isReactingToClick( _card)) return 0; game->currentlyActing()->getManaPool()->pay(cost); _card->untap(); return 1; } }; //Allows to untap target card once per turn for a manaCost class AUntaperOnceDuringTurn:public AUnBlocker{ public: int untappedThisTurn; int onlyPlayerTurn; AUntaperOnceDuringTurn(int id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost, int _onlyPlayerTurn = 1):AUnBlocker(id, _source, _target, _cost){ onlyPlayerTurn = _onlyPlayerTurn; untappedThisTurn = 0; } void Update(float dt){ if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP) untappedThisTurn = 0; AUnBlocker::Update(dt); } int isReactingToClick(MTGCardInstance * card){ if (onlyPlayerTurn && game->currentPlayer!=source->controller()) return 0; if (untappedThisTurn) return 0; return AUnBlocker::isReactingToClick(card); } int reactToClick(MTGCardInstance * card){ untappedThisTurn = 1; return AUnBlocker::reactToClick(card); } }; //Alteration of Power and Toughness (enchantments) class APowerToughnessModifier: public MTGAbility{ public: int power, toughness; APowerToughnessModifier(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness):MTGAbility(id,_source,_target),power(_power),toughness(_toughness){ _target->power += power; _target->addToToughness(toughness); } int destroy(){ ((MTGCardInstance *)target)->power -= power; ((MTGCardInstance *)target)->addToToughness(-toughness); return 1; } }; // Permanent life alteration evry turn of the target's controller. Useful only for unstable mutation currently class APowerToughnessModifierRegularCounter:public MTGAbility{ public: int power, toughness; int phase; APowerToughnessModifierRegularCounter(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _phase, int _power, int _toughness):MTGAbility(id,_source,_target),power(_power),toughness(_toughness), phase(_phase){ } void Update(float dt){ if (newPhase !=currentPhase && newPhase==phase && game->currentPlayer==((MTGCardInstance *)target)->controller()){ ((MTGCardInstance *)target)->power += power; ((MTGCardInstance *)target)->addToToughness(toughness); } } }; //Alteration of Power and Toughness until end of turn (TargetAbility) // Gives +n/+m until end of turn to any card that's a target class ATargetterPowerToughnessModifierUntilEOT: public TargetAbility{ public: MTGCardInstance * mTargets[50]; int nbTargets; int power, toughness; ATargetterPowerToughnessModifierUntilEOT(int _id, MTGCardInstance * _source, int _power, int _toughness, ManaCost * _cost, TargetChooser * _tc = NULL):TargetAbility(_id,_source,_tc,_cost,0),power(_power),toughness(_toughness){ if (!tc) tc = NEW CreatureTargetChooser(_source); nbTargets = 0; } void Update(float dt){ if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ for (int i = 0; i < nbTargets; i++){ MTGCardInstance * mTarget = mTargets[i]; if(mTarget){ mTarget->power-=power; mTarget->addToToughness(-toughness); } } nbTargets = 0; } TargetAbility::Update(dt); } int resolve(){ MTGCardInstance * mTarget = tc->getNextCardTarget(); if (mTarget){ mTargets[nbTargets] = mTarget; mTarget->power+= power; mTarget->addToToughness(toughness); nbTargets++; } return 1; } }; //Alteration of Power and Toughness until end of turn (Aura) class APowerToughnessModifierUntilEndOfTurn: public MTGAbility{ public: int power, toughness; int counters; int maxcounters; ManaCost * cost; APowerToughnessModifierUntilEndOfTurn(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness, ManaCost * _cost, int _maxcounters = 0):MTGAbility(id,_source,_target),power(_power),toughness(_toughness),maxcounters(_maxcounters), cost(_cost){ counters = 0; } void Update(float dt){ if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ while(counters){ ((MTGCardInstance *)target)->power -= power; ((MTGCardInstance *)target)->addToToughness(-toughness); counters--; } } } int isReactingToClick(MTGCardInstance * _card){ if (_card == source && (!maxcounters || counters < maxcounters) && game->currentlyActing()->game->inPlay->hasCard(source)){ if (game->currentlyActing()->getManaPool()->canAfford(cost)){ return 1; } } return 0; } int reactToClick(MTGCardInstance * _card){ if (!isReactingToClick( _card)) return 0; game->currentlyActing()->getManaPool()->pay(cost); ((MTGCardInstance *)target)->power += power; ((MTGCardInstance *)target)->addToToughness(toughness); counters++; return 1; } }; //Alteration of Power and toughness until end of turn (instant) class AInstantPowerToughnessModifierUntilEOT: public InstantAbility{ public: int power, toughness; AInstantPowerToughnessModifierUntilEOT(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness): InstantAbility(_id, _source, _target), power(_power), toughness(_toughness){ } int resolve(){ ((MTGCardInstance *)target)->power +=power; ((MTGCardInstance *)target)->addToToughness(toughness); return 1; } int destroy(){ ((MTGCardInstance *)target)->power -=power; ((MTGCardInstance *)target)->addToToughness(-toughness); return 1; } }; //Untap Blockers with simple Mana Mechanism class AUntapManaBlocker: public Blocker{ public: AUntapManaBlocker(int id, MTGCardInstance * card, ManaCost * _cost):Blocker(id, card, _cost){ } AUntapManaBlocker(int id, MTGCardInstance * card, MTGCardInstance * _target, ManaCost * _cost):Blocker(id, card,_target, _cost){ } }; /* Spell Counters (Enchantment) for a mana cost */ //LifeForce class ASpellCounterEnchantment:public TargetAbility{ public: ASpellCounterEnchantment(int _id, MTGCardInstance * _source, ManaCost * _cost,int color = -1, int _tap = 0):TargetAbility(_id,_source,NEW SpellTargetChooser(_source,color),_cost,0,_tap){ } int resolve(){ Spell * _target = tc->getNextSpellTarget(); if(_target){ game->mLayers->stackLayer()->Fizzle(_target); return 1; } return 0; } }; /*Mana Producers (lands) //These have a reactToClick function, and therefore two manaProducers on the same card conflict with each other //That means the player has to choose one. although that is perfect for cards such as birds of paradise or badlands, other solutions need to be provided for abilities that add mana (ex: mana flare) */ /* Currently the mana is added to the pool AFTER the animation This is VERY BAD, since we don't have any control on the duration of the animation. This can lead to bugs with the AI, who is expecting to have the mana in its manapool right after clicking the land card !!! The sum of "dt" has to be 0.25 for the mana to be in the manapool currently */ class AManaProducer: public MTGAbility{ protected: ManaCost * cost; ManaCost * output; string menutext; float x0,y0,x1,y1,x,y; float animation; Player * controller; hgeParticleSystem * mParticleSys; public: AManaProducer(int id, MTGCardInstance * card, ManaCost * _output, ManaCost * _cost = NULL ):MTGAbility(id, card){ LOG("==Creating ManaProducer Object"); cost = _cost; output=_output; x1 = 10; y1 = 220; Player * player = card->controller(); if (player == game->players[1]) y1 = 100; x = x1; y = y1; animation = 0.f; mParticleSys = NULL; menutext = ""; int landColor = output->getMainColor(); if (landColor == MTG_COLOR_RED){ mParticleSys = NEW hgeParticleSystem("graphics/manared.psi",GameApp::CommonRes->GetQuad("particles")); }else if (landColor == MTG_COLOR_BLUE){ mParticleSys = NEW hgeParticleSystem("graphics/manablue.psi", GameApp::CommonRes->GetQuad("particles")); }else if (landColor == MTG_COLOR_GREEN){ mParticleSys = NEW hgeParticleSystem("graphics/managreen.psi", GameApp::CommonRes->GetQuad("particles")); }else if (landColor == MTG_COLOR_BLACK){ mParticleSys = NEW hgeParticleSystem("graphics/manablack.psi", GameApp::CommonRes->GetQuad("particles")); }else if (landColor == MTG_COLOR_WHITE){ mParticleSys = NEW hgeParticleSystem("graphics/manawhite.psi", GameApp::CommonRes->GetQuad("particles")); }else{ mParticleSys = NEW hgeParticleSystem("graphics/mana.psi", GameApp::CommonRes->GetQuad("particles")); } LOG("==ManaProducer Object Creation successful !"); } void Update(float dt){ if (mParticleSys) mParticleSys->Update(dt); if (animation){ x = (1.f - animation)*x1 + animation * x0; y = (1.f - animation)*y1 + animation * y0; if (mParticleSys) mParticleSys->MoveTo(x, y); if (mParticleSys && animation == 1.f) mParticleSys->Fire(); animation -= 4 *dt; if (animation < 0){ animation = 0; controller->getManaPool()->add(output); if (mParticleSys) mParticleSys->Stop(); } } } void Render(){ JRenderer * renderer = JRenderer::GetInstance(); if (animation){ renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE); if (mParticleSys) mParticleSys->Render(); // set normal blending renderer->SetTexBlend(BLEND_SRC_ALPHA, BLEND_ONE_MINUS_SRC_ALPHA); } } int isReactingToClick(MTGCardInstance * _card){ int result = 0; if (_card == source && !source->isTapped() && game->currentlyActing()->game->inPlay->hasCard(source) && (source->hasType("land") || !source->hasSummoningSickness()) ){ if (!cost || game->currentlyActing()->getManaPool()->canAfford(cost)) result = 1; } return result; } int reactToClick(MTGCardInstance * _card){ if (!isReactingToClick( _card)) return 0; source->tapped = 1; if (cost) GameObserver::GetInstance()->currentlyActing()->getManaPool()->pay(cost); animation = 1.f; CardGui * cardg = game->mLayers->playLayer()->getByCard(source); if (cardg){ x0 = cardg->x + 15; y0 = cardg->y + 20; } controller = source->controller(); return 1; } const char * getMenuText(){ if (menutext.size())return menutext.c_str(); menutext = "Add "; char buffer[128]; int alreadyHasOne = 0; for (int i= 0; i < 6; i++){ int value = output->getCost(i); if (value){ if (alreadyHasOne) menutext.append(","); sprintf(buffer, "%i ", value); menutext.append(buffer); switch (i){ case MTG_COLOR_RED: menutext.append("red"); break; case MTG_COLOR_BLUE: menutext.append("blue"); break; case MTG_COLOR_GREEN: menutext.append("green"); break; case MTG_COLOR_WHITE: menutext.append("white"); break; case MTG_COLOR_BLACK: menutext.append("black"); break; default: break; } alreadyHasOne = 1; } } menutext.append(" mana"); return menutext.c_str(); } int testDestroy(){ if (animation >0) return 0; return MTGAbility::testDestroy(); } ~AManaProducer(){ LOG("==Destroying ManaProducer Object"); if (cost) delete cost; SAFE_DELETE(output); if (mParticleSys) delete mParticleSys; LOG("==Destroying ManaProducer Object Successful!"); } }; /* Lifelink Ability */ class ALifeLink:public MTGAbility{ public: int nbdamagesthisturn; Damage * lastDamage; ALifeLink(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ nbdamagesthisturn = 0; lastDamage = NULL; } void Update(float dt){ ActionStack * as = game->mLayers->stackLayer(); int totaldamages = as->count(ACTION_DAMAGE,RESOLVED_OK); if ( totaldamages > nbdamagesthisturn){ Damage * damage = ((Damage * )as->getNext(lastDamage,ACTION_DAMAGE, RESOLVED_OK)); while(damage){ lastDamage = damage; if (damage->source == source){ source->controller()->life+= damage->damage; } damage = ((Damage * )as->getNext(lastDamage,ACTION_DAMAGE, RESOLVED_OK)); } }else if (totaldamages ==0){ lastDamage = NULL; } nbdamagesthisturn = totaldamages; } }; //Circle of Protections class ACircleOfProtection: public TargetAbility{ public: ACircleOfProtection(int _id, MTGCardInstance * source, int _color):TargetAbility(_id,source,NEW DamageTargetChooser(source,_color),NEW ManaCost(),0,0){ cost->add(MTG_COLOR_ARTIFACT,1); } int resolve(){ Damage * damage = tc->getNextDamageTarget(); if (!damage) return 0; game->mLayers->stackLayer()->Fizzle(damage); return 1; } }; //Basic regeneration mechanism for a Mana cost class AStandardRegenerate:public ActivatedAbility{ public: AStandardRegenerate(int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost):ActivatedAbility(_id,_source,_cost,0,0){ target = _target; } int resolve(){ MTGCardInstance * _target = (MTGCardInstance *)target; _target->regenerate(); PutInGraveyard * action = ((PutInGraveyard *) game->mLayers->stackLayer()->getNext(NULL,ACTION_PUTINGRAVEYARD,NOT_RESOLVED)); while(action){ #if defined (WIN32) || defined (LINUX) OutputDebugString("Fizzling due to regenerate! \n"); #endif if (action->card == _target){ game->mLayers->stackLayer()->Fizzle(action); } action = ((PutInGraveyard *) game->mLayers->stackLayer()->getNext(action,ACTION_PUTINGRAVEYARD,NOT_RESOLVED)); } return 1; } }; /*Gives protection to a target */ class AProtectionFrom:public MTGAbility{ public: CardDescriptor * cd; void initProtection(){ ((MTGCardInstance *)target)->addProtection(cd); } AProtectionFrom(int _id, MTGCardInstance * _source, MTGCardInstance * _target, CardDescriptor * _cd):MTGAbility(_id, _source, _target),cd(_cd){ initProtection(); } AProtectionFrom(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int color):MTGAbility(_id, _source, _target){ cd = NEW CardDescriptor(); cd->colors[color] = 1; initProtection(); } int destroy(){ ((MTGCardInstance *)target)->removeProtection(cd); return 1; } }; //Aura Enchantments that provide controller of target life or damages at a given phase of their turn class ARegularLifeModifierAura:public MTGAbility{ public: int life; int phase; int onlyIfTargetTapped; ARegularLifeModifierAura(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _phase, int _life, int _onlyIfTargetTapped=0):MTGAbility(id,_source,_target),life(_life), phase(_phase),onlyIfTargetTapped(_onlyIfTargetTapped){ } void Update(float dt){ if (newPhase !=currentPhase && newPhase==phase && game->currentPlayer==((MTGCardInstance *)target)->controller()){ if (!onlyIfTargetTapped || ((MTGCardInstance *)target)->tapped){ if (life > 0){ game->currentPlayer->life+=life; }else{ game->mLayers->stackLayer()->addDamage(source, game->currentPlayer, -life); } } } } }; //ExaltedAbility (Shards of Alara) class AExalted:public ListMaintainerAbility{ public: int power, toughness; MTGCardInstance * luckyWinner; AExalted(int _id, MTGCardInstance * _source, int _power = 1, int _toughness = 1):ListMaintainerAbility(_id, _source),power(_power),toughness(_toughness){ luckyWinner = NULL; } int canBeInList(MTGCardInstance * card){ if (card->isAttacker() && game->currentPlayer == source->controller()) return 1; return 0; } int added(MTGCardInstance * card){ if(cards.size() == 1){ luckyWinner = cards.begin()->first; luckyWinner->addToToughness(toughness); luckyWinner->power+=power; }else if (cards.size() == 2){ luckyWinner->addToToughness(-toughness); luckyWinner->power-=power; } return 1; } int removed(MTGCardInstance * card){ if(cards.size() == 1){ luckyWinner = cards.begin()->first; luckyWinner->addToToughness(toughness); luckyWinner->power+=power; }else if (cards.size() == 0){ luckyWinner->addToToughness(-toughness); luckyWinner->power-=power; } return 1; } }; //ExaltedAbility for basic abilities (Shards of Alara) class AExaltedAbility:public ListMaintainerAbility{ public: int ability; MTGCardInstance * luckyWinner; AExaltedAbility(int _id, MTGCardInstance * _source, int _ability):ListMaintainerAbility(_id, _source),ability(_ability){ luckyWinner = NULL; } int canBeInList(MTGCardInstance * card){ if (card->isAttacker() && game->currentPlayer == source->controller()) return 1; return 0; } int added(MTGCardInstance * card){ luckyWinner = cards.begin()->first; if(cards.size() == 1){ luckyWinner->basicAbilities[ability]+=1; }else if (cards.size() == 2){ luckyWinner->basicAbilities[ability]-=1; } return 1; } int removed(MTGCardInstance * card){ if(cards.size() == 1){ luckyWinner->basicAbilities[ability]+=1; }else if (cards.size() == 0){ luckyWinner->basicAbilities[ability]-=1; } return 1; } }; //Converts lands to creatures (Kormus bell, Living lands) class AConvertLandToCreatures:public ListMaintainerAbility{ public: int type; int power, toughness; AConvertLandToCreatures(int _id, MTGCardInstance * _source, const char * _type, int _power = 1, int _toughness = 1):ListMaintainerAbility(_id, _source),power(_power),toughness(_toughness){ type = Subtypes::subtypesList->Add(_type); } int canBeInList(MTGCardInstance * card){ if (card->hasType(type)) return 1; return 0; } int added(MTGCardInstance * card){ card->power = 1; card->setToughness(1); card->setSubtype("creature"); return 1; } int removed(MTGCardInstance * card){ card->removeType("creature"); return 1; } }; //Lords (Merfolk lord...) give power and toughness to OTHER creatures of their type, they can give them special abilities, regeneration class ALord:public ListMaintainerAbility{ public: string type; int power, toughness; int ability; ManaCost * regenCost; map regenerations; ALord(int _id, MTGCardInstance * card, const char * _type, int _power = 0 , int _toughness = 0, int _ability = -1, ManaCost * _regenCost = NULL):ListMaintainerAbility(_id,card){ type = _type; power = _power; toughness = _toughness; ability = _ability; regenCost = _regenCost; } int canBeInList(MTGCardInstance * card){ if (card!=source && card->isACreature() && card->hasSubtype(type)) return 1; return 0; } int added(MTGCardInstance * card){ card->power += power; card->addToToughness(toughness); if (ability != -1) card->basicAbilities[ability] +=1; if (regenCost){ AStandardRegenerate * regen = NEW AStandardRegenerate(0, card, card, regenCost); regenerations[card] = regen; game->addObserver(regen); } return 1; } int removed(MTGCardInstance * card){ card->power -= power; card->addToToughness(-toughness); if (ability != -1 && card->basicAbilities[ability]) card->basicAbilities[ability] -=1; if (regenCost){ if(regenerations.find(card) != regenerations.end()){ if (game->isInPlay(card)) game->removeObserver(regenerations[card]); regenerations.erase(card); } } return 1; } }; //Lords (Merfolk lord...) give power and toughness to OTHER creatures of a given color, they can give them special abilities, regeneration class AColorLord:public ListMaintainerAbility{ public: int color; int notcolor; int power, toughness; int ability; ManaCost * regenCost; map regenerations; AColorLord(int _id, MTGCardInstance * card, int _color, int _notcolor = -1, int _power = 0 , int _toughness = 0, int _ability = -1, ManaCost * _regenCost = NULL):ListMaintainerAbility(_id,card){ color = _color; notcolor = _notcolor; power = _power; toughness = _toughness; ability = _ability; regenCost = _regenCost; } int canBeInList(MTGCardInstance * card){ if (notcolor > -1){ if (card!=source && card->isACreature() && !card->hasColor(color)) return 1; }else{ if (card!=source && card->isACreature() && card->hasColor(color)) return 1; } return 0; } int added(MTGCardInstance * card){ card->power += power; card->addToToughness(toughness); if (ability != -1) card->basicAbilities[ability] +=1; if (regenCost){ AStandardRegenerate * regen = NEW AStandardRegenerate(0, card, card, regenCost); regenerations[card] = regen; game->addObserver(regen); } return 1; } int removed(MTGCardInstance * card){ card->power -= power; card->addToToughness(-toughness); if (ability != -1 && card->basicAbilities[ability]) card->basicAbilities[ability] -=1; if (regenCost){ if(regenerations.find(card) != regenerations.end()){ game->removeObserver(regenerations[card]); regenerations.erase(card); } } return 1; } }; /* Standard Damager, can choose a NEW target each time the price is paid */ class ADamager:public TargetAbility{ public: int damage; ADamager(int id, MTGCardInstance * card, ManaCost * _cost, int _damage, TargetChooser * _tc = NULL, int _tap = 1):TargetAbility(id,card, _tc, _cost,0,_tap),damage(_damage){ if (!tc) tc = NEW DamageableTargetChooser(card); } int resolve(){ Damageable * _target = tc->getNextDamageableTarget(); GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,_target, damage); return 1; } }; /* Can tap a target for a cost */ class ATapper:public TargetAbility{ public: int damage; ATapper(int id, MTGCardInstance * card, ManaCost * _cost, TargetChooser * _chooser):TargetAbility(id,card, _chooser, _cost){ } int resolve(){ MTGCardInstance * _target = tc->getNextCardTarget(); if (_target){ _target->tapped = true; } return 1; } }; // Add life of gives damage if a given zone has more or less than [condition] cards at the beginning of [phase] //Ex : the rack, ivory tower... class ALifeZoneLink:public MTGAbility{ public: int phase; int condition; int life; int controller; int nbcards; MTGGameZone * zone; ALifeZoneLink(int _id ,MTGCardInstance * card, int _phase, int _condition, int _life = -1, int _controller = 0, MTGGameZone * _zone = NULL):MTGAbility(_id, card){ phase = _phase; condition = _condition; controller = _controller; life = _life; zone = _zone; if (zone == NULL){ if (controller){ zone = game->currentPlayer->game->hand; }else{ zone = game->opponent()->game->hand; } } } void Update(float dt){ if (newPhase != currentPhase && newPhase == phase){ if ((controller && game->currentPlayer == source->controller()) ||(!controller && game->currentPlayer != source->controller()) ){ if ((condition < 0 && zone->nb_cards < - condition) ||(condition >0 && zone->nb_cards > condition)){ int diff = zone->nb_cards - condition; if (condition < 0) diff = - condition - zone->nb_cards; if (life > 0){ game->currentPlayer->life+=life*diff; }else{ game->mLayers->stackLayer()->addDamage(source,game->currentPlayer,-life*diff); } } } } } }; //Creatures that cannot attack if opponent has not a given type of land, and die if controller has not this type of land //Ex : pirate ship... class AStrongLandLinkCreature: public MTGAbility{ public: char land[20]; AStrongLandLinkCreature(int _id, MTGCardInstance * _source, const char * _land):MTGAbility(_id, _source){ sprintf(land,"%s",_land); } void Update(float dt){ if (source->isAttacker()){ if (!game->opponent()->game->inPlay->hasType(land)){ source->attacker=0; source->tapped = 0; //TODO Improve, there can be race conditions here } } Player * player = source->controller(); if(!player->game->inPlay->hasType(land)){ player->game->putInGraveyard(source); } } }; //Steal control of a target class AControlStealAura: public MTGAbility{ public: Player * originalController; AControlStealAura(int _id , MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source, _target){ originalController = _target->controller(); _target->changeController(game->currentlyActing()); } int destroy(){ MTGCardInstance * _target = (MTGCardInstance *) target; if (_target->controller()->game->inPlay->hasCard(_target)){ //if the target is still in game -> spell was destroyed _target->changeController(originalController); } return 1; } //TODO put it back into owners's graveyard if needed... }; //Ability to untap a target class AUntaper:public TargetAbility{ public: AUntaper(int _id, MTGCardInstance * card, ManaCost * _manacost, TargetChooser * _tc):TargetAbility(_id,card,_tc,_manacost){ } int resolve(){ tc->getNextCardTarget()->tapped = 0; return 1; } }; //Same as StealControl Aura ???? Obsolete ? class ATakeControlAura:public MTGAbility{ public: Player * previousController; ATakeControlAura(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source,_target){ previousController = _target->controller(); previousController->game->putInZone(_target, previousController->game->inPlay, source->controller()->game->inPlay); } int destroy(){ MTGCardInstance * _target = (MTGCardInstance *) target; if (_target->controller()->game->inPlay->hasCard(_target)){ _target->controller()->game->putInZone(_target, _target->controller()->game->inPlay, previousController->game->inPlay); } return 1; } }; //Creatures that kill their blockers //Ex : Cockatrice class AOldSchoolDeathtouch:public MTGAbility{ public: MTGCardInstance * opponents[20]; int nbOpponents; AOldSchoolDeathtouch(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ nbOpponents = 0; } void Update(float dt){ if (newPhase != currentPhase){ if( newPhase == MTG_PHASE_COMBATDAMAGE){ nbOpponents = 0; MTGCardInstance * opponent = source->getNextOpponent(); while (opponent && !opponent->hasSubtype("wall")){ opponents[nbOpponents] = opponent; nbOpponents ++; opponent = source->getNextOpponent(opponent); } }else if (newPhase == MTG_PHASE_COMBATEND){ for (int i = 0; i < nbOpponents ; i++){ game->mLayers->stackLayer()->addPutInGraveyard(opponents[i]); } } } } int testDestroy(){ if(!game->isInPlay(source) && currentPhase != MTG_PHASE_UNTAP){ return 0; }else{ return MTGAbility::testDestroy(); } } }; //Converts a card to a creature (Aura) class AConvertToCreatureAura:public MTGAbility{ public: AConvertToCreatureAura(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness):MTGAbility(_id, _source, _target){ _target->setSubtype("creature"); _target->power = _power; _target->toughness = _toughness; _target->life = _toughness; //_target->afterDamage(); _target->doDamageTest = 1; } int destroy(){ MTGCardInstance * _target = (MTGCardInstance *) target; _target->removeType("creature"); return 1; } }; /* Specific Classes */ // 1092 Specific to Aladdin's Lamp class AAladdinsLamp: public TargetAbility{ public: CardDisplay cd; int nbcards; int init; AAladdinsLamp(int _id, MTGCardInstance * card):TargetAbility(_id,card){ cost = NEW ManaCost(); cost->x(); cd = CardDisplay(1,game,SCREEN_WIDTH/2, SCREEN_HEIGHT/2,NULL); MTGGameZone * zones[] = {game->currentPlayer->game->library}; tc = NEW TargetZoneChooser(zones,1,source); nbcards = 0; init = 0; } void Update(float dt){ if (waitingForAnswer){ if (!init){ cd.resetObjects(); int wished = game->currentlyActing()->getManaPool()->getConvertedCost(); game->currentlyActing()->getManaPool()->pay(cost); nbcards = 0; MTGGameZone * library = game->currentlyActing()->game->library; while (nbcards < wished && nbcards < library->nb_cards){ cd.AddCard(library->cards[library->nb_cards - 1 - nbcards]); nbcards++; } init = 1; } cd.Update(dt); cd.CheckUserInput(dt); } } void Render(float dt){ if (waitingForAnswer){ cd.Render(); } } int fireAbility(){ source->tapped = 1; MTGLibrary * library = game->currentlyActing()->game->library; library->removeCard(tc->getNextCardTarget()); library->shuffleTopToBottom(nbcards - 1 ); library->addCard(tc->getNextCardTarget()); init = 0; return 1; } int resolve(){return 1;}; }; //Ankh of Mishra class AAnkhOfMishra: public MTGAbility{ public: int playerLands[2]; AAnkhOfMishra(int id, MTGCardInstance * _source):MTGAbility(id, _source){ for (int i=0; i< 2; i++){ playerLands[i] = GameObserver::GetInstance()->players[i]->game->inPlay->countByType("land"); } } void Update(float dt){ for (int i=0; i < 2; i++){ int lands = GameObserver::GetInstance()->players[i]->game->inPlay->countByType("land"); while (lands > playerLands[i]){ GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,GameObserver::GetInstance()->players[i], 2); playerLands[i]++; } } } }; // Armageddon Clock class AArmageddonClock:public MTGAbility{ public: int counters; ManaCost cost; AArmageddonClock(int id, MTGCardInstance * _source):MTGAbility(id, _source){ counters = 0; int _cost[] = {MTG_COLOR_ARTIFACT, 4}; cost = ManaCost(_cost,1); } void Update(float dt){ if (newPhase != currentPhase){ if (newPhase == MTG_PHASE_UPKEEP && game->currentPlayer->game->inPlay->hasCard(source)){ counters ++; }else if (newPhase == MTG_PHASE_DRAW && counters > 0 && game->currentPlayer->game->inPlay->hasCard(source)){ //End of upkeep = beginning of draw GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,GameObserver::GetInstance()->players[0], counters); GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,GameObserver::GetInstance()->players[1], counters); } } } int isReactingToClick(MTGCardInstance * _card){ if (counters > 0 && _card == source && currentPhase == MTG_PHASE_UPKEEP){ if (game->currentlyActing()->getManaPool()->canAfford( & cost)){ return 1; } } return 0; } int reactToClick(MTGCardInstance * _card){ if (!isReactingToClick( _card)) return 0; game->currentlyActing()->getManaPool()->pay(& cost); counters --; return 1; } }; //Black Vise class ABlackVise: public MTGAbility{ public: int nbcards; ABlackVise(int id, MTGCardInstance * _source):MTGAbility(id, _source){ nbcards = game->opponent()->game->hand->nb_cards; } void Update(float dt){ if (newPhase == MTG_PHASE_UPKEEP && GameObserver::GetInstance()->opponent()->game->inPlay->hasCard(source)){ nbcards = game->currentPlayer->game->hand->nb_cards; } if (newPhase != currentPhase && newPhase == MTG_PHASE_DRAW && GameObserver::GetInstance()->opponent()->game->inPlay->hasCard(source)){ if ( nbcards > 4) game->mLayers->stackLayer()->addDamage(source,game->currentPlayer, nbcards - 4); } } }; //Channel class AChannel:public ActivatedAbility{ public: AChannel(int _id, MTGCardInstance * card):ActivatedAbility(_id, card,0,0,0){ } int isReactingToClick(PlayGuiObject * object){ if (object->type == GUI_AVATAR){ Player * player = ((GuiAvatar *)object)->player; if (player == source->controller()) return 1; } return 0; } int resolve(){ source->controller()->life--; source->controller()->getManaPool()->add(MTG_COLOR_ARTIFACT, 1); return 1; } int testDestroy(){ if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP) return 1; currentPhase = newPhase; return 0; } }; // Clockwork Beast class AClockworkBeast:public MTGAbility{ public: int counters; ManaCost cost; AClockworkBeast(int id, MTGCardInstance * _source):MTGAbility(id, _source){ counters = 7; ((MTGCardInstance *)target)->power+=7; int _cost[] = {MTG_COLOR_ARTIFACT, 1}; cost = ManaCost(_cost,1); } void Update(float dt){ if (newPhase != currentPhase && newPhase == MTG_PHASE_COMBATEND){ if (((MTGCardInstance *)source)->isAttacker() || ((MTGCardInstance *)source)->isDefenser()){ counters--; ((MTGCardInstance *)target)->power-=1; } } } int isReactingToClick(MTGCardInstance * _card){ if (counters < 7 && _card == source && currentPhase == MTG_PHASE_UPKEEP && game->currentPlayer->game->inPlay->hasCard(source)){ if (game->currentlyActing()->getManaPool()->canAfford( & cost)){ return 1; } } return 0; } int reactToClick(MTGCardInstance * _card){ if (!isReactingToClick( _card)) return 0; game->currentlyActing()->getManaPool()->pay(& cost); counters ++; ((MTGCardInstance *)target)->power++; ((MTGCardInstance *)target)->tapped = 1; return 1; } }; //1102: Conservator class AConservator: public MTGAbility{ public: int canprevent; ManaCost cost; AConservator(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ canprevent = 0; int _cost[] = {MTG_COLOR_ARTIFACT, 2}; cost = ManaCost(_cost, 1); } int alterDamage(Damage * damage){ if (canprevent && damage->target == source->controller()){ if (damage->damage >= canprevent){ damage->damage-=canprevent; canprevent = 0; }else{ canprevent-=damage->damage; damage->damage = 0; } } return 1; } int alterDamage(){ if (canprevent){ ActionStack * stack = game->mLayers->stackLayer(); for (int i = stack->mCount-1; i>=0; i--){ if (!canprevent) return 1; Interruptible * current = ((Interruptible *)stack->mObjects[i]); if (current->type == ACTION_DAMAGE && current->state==NOT_RESOLVED){ Damage * damage = (Damage *)current; alterDamage(damage); }else if (current->type == ACTION_DAMAGES && current->state == NOT_RESOLVED){ DamageStack * damages = (DamageStack *)current; for (int j = damages->mCount-1;j >=0; j--){ alterDamage(((Damage *)damages->mObjects[j])); } } } } return 1; } void Update(float dt){ alterDamage(); } int isReactingToClick(MTGCardInstance * _card){ if ( _card == source && game->currentlyActing()->game->inPlay->hasCard(source) && !_card->isTapped()){ if (game->currentlyActing()->getManaPool()->canAfford( & cost)){ return 1; } } return 0; } int reactToClick(MTGCardInstance * _card){ if (!isReactingToClick( _card)) return 0; game->currentlyActing()->getManaPool()->pay(& cost); source->tapped = 1; canprevent = 2; alterDamage(); return 1; } }; //Creature bond class ACreatureBond:public TriggeredAbility{ public: int resolved; ACreatureBond(int _id, MTGCardInstance * _source, MTGCardInstance * _target):TriggeredAbility(_id,_source,_target){ resolved = 1; } int trigger(){ MTGCardInstance * _target = (MTGCardInstance *) target; for (int i = 0; i < 2; i++){ if (game->players[i]->game->graveyard->hasCard(_target)) return 1; } return 0; } int resolve(){ MTGCardInstance * _target = (MTGCardInstance *) target; game->mLayers->stackLayer()->addDamage(source,_target->controller(),_target->toughness); resolved = 1; return 1; } int testDestroy(){ MTGCardInstance * _target = (MTGCardInstance *)target; if(_target->controller()->game->graveyard->hasCard(_target) && !resolved){ return 0; }else{ return TriggeredAbility::testDestroy(); } } }; //1105: Dingus Egg class ADingusEgg: public MTGAbility{ public: int playerLands[2]; ADingusEgg(int id, MTGCardInstance * _source):MTGAbility(id, _source){ for (int i=0; i< 2; i++){ playerLands[i] = GameObserver::GetInstance()->players[i]->game->inPlay->countByType("land"); } } void Update(float dt){ for (int i=0; i < 2; i++){ int lands = GameObserver::GetInstance()->players[i]->game->inPlay->countByType("land"); while (lands < playerLands[i]){ GameObserver::GetInstance()->mLayers->stackLayer()->addDamage(source,GameObserver::GetInstance()->players[i], 2); playerLands[i]--; } } } }; //1106 DisruptingScepter class ADisruptingScepter:public TargetAbility{ public: ADisruptingScepter(int id, MTGCardInstance * _source):TargetAbility(id,_source){ MTGGameZone * zones[] = {GameObserver::GetInstance()->opponent()->game->hand}; tc = NEW TargetZoneChooser(zones,1,_source); int _cost[] = {MTG_COLOR_ARTIFACT, 3}; cost = NEW ManaCost(_cost,1); } void Update(float dt){ if (game->opponent()->isAI()){ if(waitingForAnswer){ MTGCardInstance * card = ((AIPlayer *)game->opponent())->chooseCard(tc, source); if (card) tc->toggleTarget(card); if (!card || tc->targetsReadyCheck() == TARGET_OK) waitingForAnswer = 0; } TargetAbility::Update(dt); }else{ TargetAbility::Update(dt); } } int resolve(){ game->opponent()->game->putInGraveyard(tc->getNextCardTarget()); return 1; } }; //1108 Ebony Horse class AEbonyHorse:public TargetAbility{ public: AEbonyHorse(int _id, MTGCardInstance * _source):TargetAbility(_id,_source, NEW CreatureTargetChooser()){ int _cost[] = {MTG_COLOR_ARTIFACT, 2}; cost = NEW ManaCost(_cost,1); } int resolve(){ tc->getNextCardTarget()->attacker = 0; return 1; } }; //1345 Farmstead class AFarmstead:public ActivatedAbility{ public: AFarmstead(int _id, MTGCardInstance * source, MTGCardInstance * _target):ActivatedAbility(_id, source,0,1,0){ int _cost[] = {MTG_COLOR_WHITE, 2}; cost = NEW ManaCost(_cost,1); target = _target; } int isReactingToClick(MTGCardInstance * card){ if (!ActivatedAbility::isReactingToClick(card)) return 0; if (currentPhase == MTG_PHASE_UPKEEP) return 1; return 0; } int resolve(){ source->controller()->life++; return 1; } }; //1110 Glasses of Urza class AGlassesOfUrza:public MTGAbility{ public: CardDisplay * display; AGlassesOfUrza(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ display = NEW CardDisplay(0, game,SCREEN_WIDTH/2, SCREEN_HEIGHT/2,NULL); } void Update(float dt){ if(modal){ display->Update(dt); } } void CheckUserInput(float dt){ if (modal){ display->CheckUserInput(dt); JGE * mEngine = JGE::GetInstance(); if (mEngine->GetButtonClick(PSP_CTRL_CROSS)){ modal = 0; } } } void Render(float dt){ if (modal){ display->Render(); } } int isReactingToClick(MTGCardInstance * card){ if ( card == source){ if (game->currentlyActing()->game->isInPlay(card) && !source->isTapped()){ return 1; } } return 0; } int reactToClick(MTGCardInstance * card){ if (!isReactingToClick(card)) return 0; source->tapped = 1; modal = 1; return 1; } }; //1112 Howling Mine class AHowlingMine:public MTGAbility{ public: AHowlingMine(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){} void Update(float dt){ if (newPhase != currentPhase && newPhase == MTG_PHASE_DRAW && !source->tapped){ game->mLayers->stackLayer()->addDraw(game->currentPlayer); } } }; //1119 Jayemdae Tome class AJayemdaeTome:public ActivatedAbility{ public: AJayemdaeTome(int _id, MTGCardInstance * card):ActivatedAbility(_id, card){ int _cost[] = {MTG_COLOR_ARTIFACT, 4}; cost = NEW ManaCost(_cost,1); } int resolve(){ game->mLayers->stackLayer()->addDraw(source->controller()); return 1; } }; //Living Artifact class ALivingArtifact:public MTGAbility{ public: int usedThisTurn; int counters; Damage * latest; ALivingArtifact(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id,_source,_target){ usedThisTurn = 0; counters = 0; latest = NULL; } void Update(float dt){ if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP) usedThisTurn = 0; Damage * damage = ((Damage *)game->mLayers->stackLayer()->getNext(latest,ACTION_DAMAGE,RESOLVED_OK)); while (damage){ if (damage->target == source->controller()){ counters += damage->damage; } latest = damage; damage = ((Damage *)game->mLayers->stackLayer()->getNext(damage,ACTION_DAMAGE,RESOLVED_OK)); } } int isReactingtoclick(MTGCardInstance * card){ if (currentPhase == MTG_PHASE_UPKEEP && card == source && game->currentPlayer == source->controller() && counters && !usedThisTurn){ return 1; } return 0; } int reactToClick(MTGCardInstance * card){ source->controller()->life+=1; counters--; usedThisTurn = 1; return 1; } }; //Lord of the Pit class ALordOfThePit: public TargetAbility{ public: int paidThisTurn; ALordOfThePit(int _id, MTGCardInstance * source):TargetAbility(_id, source, NEW CreatureTargetChooser(),0,1,0){ paidThisTurn = 1; } void Update(float dt){ if (newPhase != currentPhase && source->controller() == game->currentPlayer){ if (newPhase == MTG_PHASE_UNTAP){ paidThisTurn = 0; }else if( newPhase == MTG_PHASE_UPKEEP + 1 && !paidThisTurn){ game->mLayers->stackLayer()->addDamage(source,source->controller(), 7); } } TargetAbility::Update(dt); } int isReactingToClick(MTGCardInstance * card){ if (currentPhase != MTG_PHASE_UPKEEP || paidThisTurn) return 0; return TargetAbility::isReactingToClick(card); } int resolve(){ MTGCardInstance * card = tc->getNextCardTarget(); if (card && card != source && card->controller() == source->controller()){ card->controller()->game->putInGraveyard(card); paidThisTurn = 1; return 1; } return 0; } }; //1143 Animate Dead class AAnimateDead:public MTGAbility{ public: AAnimateDead(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source, _target){ MTGCardInstance * card = _target; card->power--; card->life = card->toughness; //Put the card in play again, with all its abilities ! //AbilityFactory af; Spell * spell = NEW Spell(card); //af.addAbilities(game->mLayers->actionLayer()->getMaxId(), spell); source->controller()->game->putInZone(card, _target->controller()->game->graveyard, source->controller()->game->stack); spell->resolve(); delete spell; } int destroy(){ MTGCardInstance * card = (MTGCardInstance *) target; card->power++; return 1; } }; //1144 Bad Moon, 1341 Crusade class ABadMoon:public ListMaintainerAbility{ public: int color; ABadMoon(int _id, MTGCardInstance * _source, int _color = MTG_COLOR_BLACK):ListMaintainerAbility(_id, _source),color(_color){ } int canBeInList(MTGCardInstance * card){ if (card->isACreature() && card->hasColor(color)) return 1; return 0; } int added(MTGCardInstance * card){ card->power += 1; card->addToToughness(1); return 1; } int removed(MTGCardInstance * card){ card->power -= 1; card->addToToughness(-1); return 1; } }; //1159 Erg Raiders class AErgRaiders:public MTGAbility{ public: int init; int dealDamage; AErgRaiders(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ init = 0; dealDamage = 0; } void Update(float dt){ if (newPhase != currentPhase){ Player * controller = source->controller(); if (newPhase == MTG_PHASE_COMBATDAMAGE && game->currentPlayer == controller){ if (!source->isAttacker() && init){ dealDamage = 1; } }else if (newPhase == MTG_PHASE_UNTAP && game->currentPlayer != controller){ if (dealDamage){ game->mLayers->stackLayer()->addDamage(source, controller,2); } init = 1; dealDamage = 0; } } } }; //Fastbond class AFastbond:public TriggeredAbility{ public: int alreadyPlayedALand; AFastbond(int _id, MTGCardInstance * card):TriggeredAbility(_id, card){ alreadyPlayedALand = 0; } void Update(float dt){ if (newPhase!=currentPhase && newPhase == MTG_PHASE_UNTAP){ alreadyPlayedALand = 0; } TriggeredAbility::Update(dt); } int trigger(){ if(source->controller()->canPutLandsIntoPlay==0) return 1; return 0; } int resolve(){ source->controller()->canPutLandsIntoPlay = 1; if (alreadyPlayedALand){ game->mLayers->stackLayer()->addDamage(source, source->controller(), 1); } alreadyPlayedALand = 1; return 1; } }; //1165 Hypnotic Specter class AHypnoticSpecter:public MTGAbility{ public: int nbdamagesthisturn[2]; AHypnoticSpecter(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ currentPhase = -1; for (int i = 0; i < 2; i++){ nbdamagesthisturn[i] = 0; } } void Update(float dt){ if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ for (int i = 0; i < 2; i++){ nbdamagesthisturn[i] = 0; } } ActionStack * as = game->mLayers->stackLayer(); int nbdamages[2]; for (int i = 0; i < 2; i++){ nbdamages[i] = 0; } Damage * current = ((Damage *)as->getNext(NULL,ACTION_DAMAGE,RESOLVED_OK)); while(current){ if (current->source == source){ for (int j=0; j < 2; j++){ if(current->target == game->players[j]) nbdamages[j]++; } } current = ((Damage *)as->getNext(current,ACTION_DAMAGE,RESOLVED_OK)); } for (int i = 0; i < 2; i++){ while(nbdamages[i] > nbdamagesthisturn[i]){ nbdamagesthisturn[i]++; game->players[i]->game->discardRandom(game->players[i]->game->hand); } } } }; //1117 Jandor's Ring class AJandorsRing:public ActivatedAbility{ public: AJandorsRing(int _id, MTGCardInstance * _source):ActivatedAbility(_id,_source, NEW ManaCost()){ cost->add(MTG_COLOR_ARTIFACT, 2); } int isReactingToClick(MTGCardInstance * card){ if (!source->controller()->game->hand->hasCard(source->controller()->game->library->lastCardDrawn)) return 0; return ActivatedAbility::isReactingToClick(card); } int resolve(){ source->controller()->game->putInGraveyard(source->controller()->game->library->lastCardDrawn); game->mLayers->stackLayer()->addDraw(source->controller()); return 1; } }; //Kudzu. //What happens when there are no targets ??? class AKudzu: public TargetAbility{ public: int previouslyTapped; AKudzu(int _id, MTGCardInstance * card, MTGCardInstance * _target):TargetAbility(_id,card, NEW TypeTargetChooser("land",card)){ tc->toggleTarget(_target); target = _target; previouslyTapped = 0; if (_target->tapped) previouslyTapped = 1; } void Update(float dt){ MTGCardInstance * _target = (MTGCardInstance *)target; if (!_target->tapped){ previouslyTapped = 0; }else if (!previouslyTapped){ #if defined (WIN32) || defined (LINUX) OutputDebugString("Kudzu Strikes !\n"); #endif MTGCardInstance * _target = (MTGCardInstance *)target; _target->controller()->game->putInGraveyard(_target); reactToClick(source); // ???? } TargetAbility::Update(dt); } int isReactingToClick(MTGCardInstance * card){ MTGCardInstance * _target = (MTGCardInstance *)target; if (card == source && (!_target || !_target->isInPlay())){ #if defined (WIN32) || defined (LINUX) OutputDebugString("Kudzu Reacts to click !\n"); #endif return 1; } return 0; } /* int reactToClick(MTGCardInstance * card){ if (!waitingForAnswer) { }else{ tc->toggleTarget(card); } return 1; } */ int resolve(){ target = tc->getNextCardTarget(); source->target = (MTGCardInstance *) target; previouslyTapped = 0; if (source->target->tapped) previouslyTapped = 1; return 1; } int testDestroy(){ GameObserver * g = GameObserver::GetInstance(); int stillLandsInPlay = 0; for (int i = 0; i < 2; i++){ if (game->players[i]->game->inPlay->hasType("land")) stillLandsInPlay = 1; } if (!stillLandsInPlay){ source->controller()->game->putInGraveyard(source); return 1; } if (!game->isInPlay(source)){ return 1; } return 0; } }; //Millstone class AMillstone:public TargetAbility{ public: AMillstone(int _id, MTGCardInstance * card):TargetAbility(_id,card, NEW PlayerTargetChooser(), NEW ManaCost()){ cost->add(MTG_COLOR_ARTIFACT, 2); } int resolve(){ Player * player = tc->getNextPlayerTarget(); if (!player) return 0; MTGLibrary * library = player->game->library; for (int i = 0; i < 2; i++){ if (library->nb_cards) player->game->putInZone(library->cards[library->nb_cards-1],library, player->game->graveyard); } return 1; } }; //1170: Nightmare class ANightmare:public ListMaintainerAbility{ public: ANightmare(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ } int canBeInList(MTGCardInstance * card){ if (source->controller()->game->inPlay->hasCard(card) && card->hasType("swamp") ) return 1; return 0; } int added(MTGCardInstance * card){ source->power += 1; source->addToToughness(1); return 1; } int removed(MTGCardInstance * card){ source->power -= 1; source->addToToughness(-1); return 1; } }; //1172 Pestilence class APestilence: public ActivatedAbility{ public: APestilence(int _id, MTGCardInstance * card):ActivatedAbility(_id, card, NEW ManaCost(), 0,0){ cost->add(MTG_COLOR_BLACK, 1); } void Update(float dt){ if (newPhase !=currentPhase && newPhase == MTG_PHASE_EOT){ if (!game->players[0]->game->inPlay->hasType("creature") && !game->players[1]->game->inPlay->hasType("creature")){ source->controller()->game->putInGraveyard(source); } } } int resolve(){ for (int i = 0; i < 2 ; i++){ MTGInPlay * inplay = game->players[i]->game->inPlay; for (int j = inplay->nb_cards - 1 ; j >=0; j--){ if (inplay->cards[j]->isACreature()) game->mLayers->stackLayer()->addDamage(source,inplay->cards[j],1); } game->mLayers->stackLayer()->addDamage(source,game->players[i],1); } return 1; } }; //Plague Rats and similar. Power and toughness equal to number of cards that share a name class APlagueRats:public ListMaintainerAbility{ public: string name; APlagueRats(int _id, MTGCardInstance * _source, const char * _name):ListMaintainerAbility(_id,_source){ name = _name; std::transform(name.begin(), name.end(), name.begin(),::tolower ); } int canBeInList(MTGCardInstance * card){ if (card == source) return 0; string compared = card->name; std::transform( compared.begin(), compared.end(), compared.begin(),::tolower ); if (name.compare(compared) == 0) return 1; return 0; } int added(MTGCardInstance * card){ source->power += 1; source->addToToughness(1); return 1; } int removed(MTGCardInstance * card){ source->power -= 1; source->addToToughness(-1); return 1; } }; //Power Leak class APowerLeak:public TriggeredAbility{ public: int damagesToDealThisTurn; ManaCost cost; APowerLeak(int _id, MTGCardInstance * _source, MTGCardInstance * _target):TriggeredAbility(_id, _source, _target){ cost.add(MTG_COLOR_ARTIFACT, 1); damagesToDealThisTurn = 0; } void Update(float dt){ MTGCardInstance * _target = (MTGCardInstance *) target; if (newPhase != currentPhase && newPhase == MTG_PHASE_UPKEEP && _target->controller() == game->currentPlayer){ damagesToDealThisTurn = 2; } TriggeredAbility::Update(dt); } int isReactingToClick(MTGCardInstance * card){ MTGCardInstance * _target = (MTGCardInstance *) target; if (damagesToDealThisTurn && currentPhase == MTG_PHASE_UPKEEP && card==source && _target->controller() == game->currentPlayer){ if (game->currentPlayer->getManaPool()->canAfford(& cost)) return 1; } return 0; } int reactToclick(MTGCardInstance * card){ game->currentPlayer->getManaPool()->pay( & cost); damagesToDealThisTurn--; return 1; } int trigger(){ MTGCardInstance * _target = (MTGCardInstance *) target; if (newPhase != currentPhase && newPhase == MTG_PHASE_DRAW && _target->controller() == game->currentPlayer){ if (damagesToDealThisTurn) return 1; } return 0; } int resolve(){ MTGCardInstance * _target = (MTGCardInstance *) target; game->mLayers->stackLayer()->addDamage(source,_target->controller(), damagesToDealThisTurn); return 1; } }; //Power Surge class APowerSurge:public TriggeredAbility{ public: int totalLands; APowerSurge(int _id, MTGCardInstance * _source):TriggeredAbility(_id,_source){ totalLands = 0; } int trigger(){ if (newPhase != currentPhase && newPhase == MTG_PHASE_EOT){ //That's ugly but untapped land at the beginning of the turn are opponent's untapped lands at the end of the turn totalLands = 0; MTGInPlay * inPlay = game->opponent()->game->inPlay; for (int i = 0; i < inPlay->nb_cards; i++){ MTGCardInstance * card = inPlay->cards[i]; if (!card->tapped && card->hasType("land")){ totalLands++; } } } if (newPhase != currentPhase && newPhase == MTG_PHASE_UPKEEP && totalLands){ return 1; } return 0; } int resolve(){ if (totalLands) game->mLayers->stackLayer()->addDamage(source,game->currentPlayer,totalLands); totalLands = 0; return 1; } }; //1175 Royal Assassin class ARoyalAssassin:public TargetAbility{ public: ARoyalAssassin(int _id, MTGCardInstance * _source):TargetAbility(_id,_source, NEW CreatureTargetChooser()){ } int resolve(){ MTGCardInstance * _target = tc->getNextCardTarget(); if(_target && _target->tapped){ _target->controller()->game->putInGraveyard(_target); return 1; } return 0; } }; //1176 Sacrifice class ASacrifice:public InstantAbility{ public: ASacrifice(int _id, MTGCardInstance * _source, MTGCardInstance * _target):InstantAbility(_id, _source){ target = _target; } int resolve(){ MTGCardInstance * _target = (MTGCardInstance *) target; if (_target->isInPlay()){ game->currentlyActing()->game->putInGraveyard(_target); int x = _target->getManaCost()->getConvertedCost(); game->currentlyActing()->getManaPool()->add(MTG_COLOR_BLACK, x); } return 1; } }; //1178 Scavenging Ghoul class AScavengingGhoul:public MTGAbility{ public: int counters; AScavengingGhoul(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source, _target){ counters = 0; } void Update(float dt){ //TODO } int isReactingToClick(MTGCardInstance * _card){ if (counters > 0 && _card == source && game->currentlyActing()->game->inPlay->hasCard(source)){ return 1; } return 0; } int reactToClick(MTGCardInstance * _card){ if (!isReactingToClick( _card)) return 0; counters--; source->regenerate(); return 1; } }; //1218 Psychic Venom class APsychicVenom:public MTGAbility{ public: int tapped; APsychicVenom(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id, _source,_target){ tapped = _target->tapped; } void Update(float dt){ MTGCardInstance* _target = (MTGCardInstance* )target; int newState = _target->isTapped(); if (newState != tapped && newState == 1){ game->mLayers->stackLayer()->addDamage(source,_target->controller(),2); } tapped = newState; } }; //1221 Serendib Efreet class ASerendibEfreet:public MTGAbility{ public: ASerendibEfreet(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ } void Update(float dt){ if (newPhase == MTG_PHASE_UPKEEP && newPhase != currentPhase && game->currentPlayer == source->controller()){ game->mLayers->stackLayer()->addDamage(source,game->currentPlayer,1); } } }; //1235 Aspect of Wolf class AAspectOfWolf:public ListMaintainerAbility{ public: int color; AAspectOfWolf(int _id, MTGCardInstance * _source, MTGCardInstance * _target):ListMaintainerAbility(_id, _source, _target){ } int canBeInList(MTGCardInstance * card){ if (card->controller() == source->controller() && card->hasType("forest")) return 1; return 0; } int added(MTGCardInstance * card){ MTGCardInstance * _target = (MTGCardInstance *) target; int size = cards.size(); if (size % 2 == 0){ _target->power += 1; }else{ _target->addToToughness(1); } return 1; } int removed(MTGCardInstance * card){ MTGCardInstance * _target = (MTGCardInstance *) target; int size = cards.size(); if (size % 2 == 1){ _target->power -= 1; }else{ _target->addToToughness(-1); } return 1; } }; //1276 Wanderlust, 1148 Cursed Lands class AWanderlust:public TriggeredAbility{ public: AWanderlust(int _id, MTGCardInstance * _source, MTGCardInstance * _target):TriggeredAbility(_id,_source, _target){} int trigger(){ if (newPhase != currentPhase && newPhase == MTG_PHASE_UPKEEP && ((MTGCardInstance *) target)->controller()==game->currentPlayer){ return 1; } return 0; } int resolve(){ game->mLayers->stackLayer()->addDamage(source,((MTGCardInstance *) target)->controller(),1); return 1; } }; //1280 Atog class AAtog:public TargetAbility{ public: Player * currentController; int counters; AAtog(int _id, MTGCardInstance * _source):TargetAbility(_id, _source,NULL, NULL, 0,0){ currentController = source->controller(); MTGGameZone * zones[] = {currentController->game->inPlay}; tc = NEW TypeTargetChooser("artifact", zones, 1, source); counters = 0; } void Update(float dt){ if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP){ for (int i = 0; i < counters; i++){ source->power-=2; source->addToToughness(-2); } counters = 0; } TargetAbility::Update(dt); Player * newController = source->controller(); if (newController != currentController){ delete tc; MTGGameZone * zones[] = {newController->game->inPlay}; //In case Atog's controller changes tc = NEW TypeTargetChooser("artifact", zones, 1, source); currentController = newController; } } int resolve(){ tc->getNextCardTarget()->controller()->game->putInGraveyard(tc->getNextCardTarget()); source->power+=2; source->addToToughness(2); counters ++; return 1; } }; //1284 Dragon Whelp class ADragonWhelp: public APowerToughnessModifierUntilEndOfTurn{ public: ADragonWhelp(int id, MTGCardInstance * card):APowerToughnessModifierUntilEndOfTurn(id, card, card, 1, 0, NEW ManaCost()){ cost->add(MTG_COLOR_RED, 1); } void Update(float dt){ if (newPhase != currentPhase && newPhase == MTG_PHASE_UNTAP && counters > 3){ source->controller()->game->putInGraveyard(source); } APowerToughnessModifierUntilEndOfTurn::Update(dt); } }; //1288 EarthBind class AEarthbind:public ABasicAbilityModifier{ public: AEarthbind(int _id, MTGCardInstance * _source, MTGCardInstance * _target):ABasicAbilityModifier(_id,_source,_target,FLYING,0){ if (value_before_modification) game->mLayers->stackLayer()->addDamage(source,target,2); } }; //1291 Fireball class AFireball:public InstantAbility{ public: AFireball(int _id, MTGCardInstance * card, Spell * spell, int x):InstantAbility(_id, card){ int nbtargets = spell->cursor; int totaldamage = x+1-nbtargets; int individualdamage = totaldamage / nbtargets; Damageable * _target = spell->getNextDamageableTarget(); while(_target){ game->mLayers->stackLayer()->addDamage(source,_target,individualdamage); _target = spell->getNextDamageableTarget(_target); } } }; //1245 ForceOfNature class AForceOfNature:public ActivatedAbility{ public: int dealDamageThisTurn; AForceOfNature(int _id, MTGCardInstance * card):ActivatedAbility(_id,card, NEW ManaCost(),1,0){ dealDamageThisTurn = 0; cost->add(MTG_COLOR_GREEN,4); } void Update(float dt){ if (newPhase !=currentPhase){ if (newPhase == MTG_PHASE_UNTAP){ dealDamageThisTurn = 1; }else if (newPhase == MTG_PHASE_DRAW && dealDamageThisTurn && game->currentPlayer==source->controller() ){ game->mLayers->stackLayer()->addDamage(source,source->controller(),8); } } ActivatedAbility::Update(dt); } int isReactingToClick(MTGCardInstance * card){ return (dealDamageThisTurn && currentPhase == MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card)); } int resolve(){ dealDamageThisTurn = 0; return 1; } }; //1301 KeldonWarlord class AKeldonWarlord:public ListMaintainerAbility{ public: AKeldonWarlord(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ } int canBeInList(MTGCardInstance * card){ if (source->controller()->game->inPlay->hasCard(card) && card->isACreature() && !card->hasType("wall") ) return 1; return 0; } int added(MTGCardInstance * card){ source->power += 1; source->addToToughness(1); return 1; } int removed(MTGCardInstance * card){ source->power -= 1; source->addToToughness(-1); return 1; } }; //1302 : Kird Ape class AKirdApe:public MTGAbility{ public: int init; AKirdApe(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ init = 0; } void Update(float dt){ if (source->controller()->game->inPlay->hasType("forest")){ if(!init){ init = 1; source->power+=1; source->addToToughness(2); } }else{ if (init){ init = 0; source->power-=1; source->addToToughness(-2); } } } }; //1309 Orcish Artilery class AOrcishArtillery: public ADamager{ public: AOrcishArtillery(int _id,MTGCardInstance * card): ADamager(_id, card, NEW ManaCost(), 2){ } int resolve(){ ADamager::resolve(); game->mLayers->stackLayer()->addDamage(source,source->controller(), 3); return 1; } }; //1310 Orcish Oriflame class AOrcishOriflame:public ListMaintainerAbility{ public: int color; AOrcishOriflame(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ } int canBeInList(MTGCardInstance * card){ if (source->controller() == game->currentPlayer && game->currentPlayer->game->inPlay->hasCard(card) && card->attacker) return 1; return 0; } int added(MTGCardInstance * card){ card->power += 1; return 1; } int removed(MTGCardInstance * card){ card->power -= 1; return 1; } }; //1334 Castle class ACastle:public ListMaintainerAbility{ public: ACastle(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ } int canBeInList(MTGCardInstance * card){ if (source->controller()->game->inPlay->hasCard(card) && card->isACreature() && !card->isAttacker() && !card->tapped) return 1; return 0; } int added(MTGCardInstance * card){ card->addToToughness(2); return 1; } int removed(MTGCardInstance * card){ card->addToToughness(-2); return 1; } }; //1351 Island Sanctuary class AIslandSanctuary:public MTGAbility{ public: int initThisTurn; AIslandSanctuary(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ initThisTurn = 0; } void Update(float dt){ if (currentPhase == MTG_PHASE_UNTAP && game->currentPlayer == source->controller()) initThisTurn = 0; if (initThisTurn && currentPhase == MTG_PHASE_COMBATATTACKERS && game->currentPlayer != source->controller()){ MTGGameZone * zone = game->currentPlayer->game->inPlay; for (int i = 0; i < zone->nb_cards; i++){ MTGCardInstance * card = zone->cards[i]; if (card->isAttacker() && !card->basicAbilities[FLYING] && !card->basicAbilities[ISLANDWALK]) card->attacker=0; } } } int isReactingToClick(MTGCardInstance * card){ if (card==source && game->currentPlayer == card->controller() && currentPhase == MTG_PHASE_DRAW){ Interruptible * action = game->mLayers->stackLayer()->_(-1); if (action->type == ACTION_DRAW) return 1; } return 0; } int reactToClick(MTGCardInstance * card){ if (!isReactingToClick(card)) return 0; game->mLayers->stackLayer()->Remove(game->mLayers->stackLayer()->_(-1)); initThisTurn = 1; return 1; } }; //1352 Karma class AKarma: public TriggeredAbility{ public: AKarma(int _id, MTGCardInstance * _source):TriggeredAbility(_id, _source){ } int trigger(){ if (newPhase != currentPhase && newPhase == MTG_PHASE_UPKEEP) return 1; return 0; } int resolve(){ int totaldamage = 0; MTGGameZone * zone = game->currentPlayer->game->inPlay; for (int i = 0; i < zone->nb_cards; i++){ if (zone->cards[i]->hasType("swamp")) totaldamage++;; } if (totaldamage) game->mLayers->stackLayer()->addDamage(source,game->currentPlayer, totaldamage); return 1; } }; //1355 Norther Paladin class ANorthernPaladin:public TargetAbility{ public: ANorthernPaladin(int _id, MTGCardInstance * card):TargetAbility(_id, card){ int _cost[] = {MTG_COLOR_WHITE, 2}; cost = NEW ManaCost(_cost,1); tc = NEW TargetChooser(); } int resolve(){ MTGCardInstance * card = tc->getNextCardTarget(); if (card->hasColor(MTG_COLOR_BLACK)){ card->controller()->game->putInGraveyard(card); return 1; } return 0; } }; //Sedge Troll class ASedgeTroll:public MTGAbility{ public: int init; ASedgeTroll(int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ init = 0; } void Update(float dt){ if (source->controller()->game->inPlay->hasType("swamp")){ if(!init){ init = 1; source->power+=1; source->addToToughness(1); } }else{ if (init){ init = 0; source->power-=1; source->addToToughness(-1); } } } }; //Soul Net class ASoulNet:public ActivatedAbility{ public: PutInGraveyard * latest; PutInGraveyard * newDead; ASoulNet(int _id, MTGCardInstance * card):ActivatedAbility(_id, card,0,0,0){ int _cost[] = {MTG_COLOR_ARTIFACT, 1}; cost = NEW ManaCost(_cost,1); latest = ((PutInGraveyard *) GameObserver::GetInstance()->mLayers->stackLayer()->getPrevious(NULL,ACTION_PUTINGRAVEYARD,RESOLVED_OK)); newDead = latest; } int isReactingToClick(MTGCardInstance * card){ newDead = ((PutInGraveyard *) GameObserver::GetInstance()->mLayers->stackLayer()->getPrevious(NULL,ACTION_PUTINGRAVEYARD,RESOLVED_OK)); if (newDead && newDead != latest && newDead->card->isACreature()) return ActivatedAbility::isReactingToClick(card); return 0; } int resolve(){ latest = newDead; source->controller()->life++; return 1; } }; //Stasis class AStasis:public ActivatedAbility{ public: int paidThisTurn; AStasis(int _id, MTGCardInstance * card):ActivatedAbility(_id,card, NEW ManaCost(),1,0){ paidThisTurn = 1; cost->add(MTG_COLOR_BLUE,1); } void Update(float dt){ //Upkeep Cost if (newPhase !=currentPhase){ if (newPhase == MTG_PHASE_UPKEEP){ paidThisTurn = 0; }else if (!paidThisTurn && newPhase > MTG_PHASE_UPKEEP && game->currentPlayer==source->controller() ){ game->currentPlayer->game->putInGraveyard(source); paidThisTurn = 1; } } //Stasis Effect for (int i = 0; i < 2; i++){ game->phaseRing->removePhase(MTG_PHASE_UNTAP,game->players[i]); } //Parent Class Method Call ActivatedAbility::Update(dt); } int isReactingToClick(MTGCardInstance * card){ return (!paidThisTurn && currentPhase == MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card)); } int resolve(){ paidThisTurn = 1; return 1; } int destroy(){ for (int i = 0; i < 2; i++){ game->phaseRing->addPhaseBefore(MTG_PHASE_UNTAP,game->players[i],MTG_PHASE_UPKEEP,game->players[i]); } return 1; } }; //--------------Addon Abra------------------ //ShieldOfTheAge class AShieldOfTheAge: public TargetAbility{ public: AShieldOfTheAge(int _id, MTGCardInstance * card):TargetAbility(_id,card,NEW DamageTargetChooser(card,_id),NEW ManaCost(),0,0){ cost->add(MTG_COLOR_ARTIFACT,2); } int resolve(){ Damage * damage = tc->getNextDamageTarget(); if (!damage) return 0; game->mLayers->stackLayer()->Fizzle(damage); return 1; } }; // GiveLifeForTappedType class AGiveLifeForTappedType:public MTGAbility{ public: char type[20]; int nbtypestapped; int counttypesTapped(){ int result = 0; MTGInPlay * inplay = source->controller()->opponent()->game->inPlay; for (int i = 0; i < inplay->nb_cards; i++){ MTGCardInstance * card = inplay->cards[i]; if (card->tapped && card->hasType(type)) result++; } return result; } AGiveLifeForTappedType(int _id, MTGCardInstance * source, const char * _type):MTGAbility(_id, source){ sprintf(type,"%s",_type);{ nbtypestapped = counttypesTapped(); } } void Update(float dt){ int newcount = counttypesTapped(); for (int i=0; i < newcount - nbtypestapped; i++){ source->controller()->life++; } nbtypestapped = newcount; } }; // People of the Woods class APeopleOfTheWoods:public ListMaintainerAbility{ public: APeopleOfTheWoods(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ } int canBeInList(MTGCardInstance * card){ if (source->controller()->game->inPlay->hasCard(card) && card->hasType("forest") ) return 1; return 0; } int added(MTGCardInstance * card){ source->addToToughness(1); return 1; } int removed(MTGCardInstance * card){ source->addToToughness(-1); return 1; } }; //Abomination Kill blocking creature if white or green class AAbomination :public MTGAbility{ public: MTGCardInstance * opponents[20]; int nbOpponents; AAbomination (int _id, MTGCardInstance * _source):MTGAbility(_id, _source){ nbOpponents = 0; } void Update(float dt){ if (newPhase != currentPhase){ if( newPhase == MTG_PHASE_COMBATDAMAGE){ nbOpponents = 0; MTGCardInstance * opponent = source->getNextOpponent(); while ((opponent && opponent->hasColor(MTG_COLOR_GREEN)) || opponent->hasColor(MTG_COLOR_WHITE)){ opponents[nbOpponents] = opponent; nbOpponents ++; opponent = source->getNextOpponent(opponent); } }else if (newPhase == MTG_PHASE_COMBATEND){ for (int i = 0; i < nbOpponents ; i++){ game->mLayers->stackLayer()->addPutInGraveyard(opponents[i]); } } } } int testDestroy(){ if(!game->isInPlay(source) && currentPhase != MTG_PHASE_UNTAP){ return 0; }else{ return MTGAbility::testDestroy(); } } }; //Minion of Leshrac class AMinionofLeshrac: public TargetAbility{ public: int paidThisTurn; AMinionofLeshrac(int _id, MTGCardInstance * source):TargetAbility(_id, source, NEW CreatureTargetChooser(),0,1,0){ paidThisTurn = 1; } void Update(float dt){ if (newPhase != currentPhase && source->controller() == game->currentPlayer){ if (newPhase == MTG_PHASE_UNTAP){ paidThisTurn = 0; }else if( newPhase == MTG_PHASE_UPKEEP + 1 && !paidThisTurn){ game->mLayers->stackLayer()->addDamage(source,source->controller(), 5); source->tapped = 1; } } TargetAbility::Update(dt); } int isReactingToClick(MTGCardInstance * card){ if (currentPhase != MTG_PHASE_UPKEEP || paidThisTurn) return 0; return TargetAbility::isReactingToClick(card); } int resolve(){ MTGCardInstance * card = tc->getNextCardTarget(); if (card && card != source && card->controller() == source->controller()){ card->controller()->game->putInGraveyard(card); paidThisTurn = 1; return 1; } return 0; } }; //2703 Lost Order of Jarkeld class ALostOrderofJarkeld:public ListMaintainerAbility{ public: ALostOrderofJarkeld(int _id, MTGCardInstance * _source):ListMaintainerAbility(_id, _source){ } int canBeInList(MTGCardInstance * card){ if (card==source || (game->currentPlayer->game->inPlay->hasCard(card) && card->isACreature()) ) return 1; return 0; } int added(MTGCardInstance * card){ source->power += 1; source->addToToughness(1); return 1; } int removed(MTGCardInstance * card){ source->power -= 1; source->addToToughness(-1); return 1; } }; //CreaturePowerToughnessModifierForAllTypeControlled class ACreaturePowerToughnessModifierForAllTypeControlled:public ListMaintainerAbility{ public: char type[20]; ACreaturePowerToughnessModifierForAllTypeControlled(int _id, MTGCardInstance * _source, const char * _type):ListMaintainerAbility(_id, _source){ } int canBeInList(MTGCardInstance * card){ if (source->controller()->game->inPlay->hasCard(card) && card->hasType(type) ) return 1; return 0; } int added(MTGCardInstance * card){ source->power += 1; source->addToToughness(1); return 1; } int removed(MTGCardInstance * card){ source->power -= 1; source->addToToughness(-1); return 1; } }; //GenericKirdApe class AGenericKirdApe:public MTGAbility{ public: int init; char type [20]; int power; int toughness; AGenericKirdApe(int _id, MTGCardInstance * _source, const char * _type, int _power, int _toughness):MTGAbility(_id, _source){ init = 0; } void Update(float dt){ if (source->controller()->game->inPlay->hasType(type)){ if(!init){ init = 1; source->power+=power; source->addToToughness(toughness); } }else{ if (init){ init = 0; source->power-=power; source->addToToughness(-toughness); } } } }; //Rampage ability Tentative 2 class ARampageAbility:public MTGAbility{ public: int nbOpponents; int PowerModifier; int ToughnessModifier; int modifier; ARampageAbility(int _id, MTGCardInstance * _source,int _PowerModifier, int _ToughnessModifier):MTGAbility(_id, _source){ modifier=0; } void Update(float dt){ if (source->isAttacker()){ MTGInPlay * inPlay = game->opponent()->game->inPlay; for (int i = 0; i < inPlay->nb_cards; i ++){ MTGCardInstance * current = inPlay->cards[i]; if (current->isDefenser()){ modifier++; } } source->power+= (PowerModifier * modifier); source->addToToughness(ToughnessModifier * modifier); } } }; //Rampage ability Tentative 1 - Did not work as expected class A1RampageAbility:public MTGAbility{ public: MTGCardInstance * opponents[20]; int nbOpponents; int PowerModifier; int ToughnessModifier; A1RampageAbility(int _id, MTGCardInstance * _source,int _PowerModifier, int _ToughnessModifier):MTGAbility(_id, _source){ nbOpponents = 0; } void Update(float dt){ if (source->isAttacker()){ if (newPhase != currentPhase){ if( newPhase == MTG_PHASE_COMBATDAMAGE){ nbOpponents = 0; MTGCardInstance * opponent = source->getNextOpponent(); while (opponent){ opponents[nbOpponents] = opponent; nbOpponents ++; source->power+= PowerModifier; source->addToToughness(ToughnessModifier); opponent = source->getNextOpponent(opponent); } } } } } }; #endif