diff --git a/projects/mtg/bin/Res/sets/10E/_cards.dat b/projects/mtg/bin/Res/sets/10E/_cards.dat index 39503dfcc..6eaebb351 100644 --- a/projects/mtg/bin/Res/sets/10E/_cards.dat +++ b/projects/mtg/bin/Res/sets/10E/_cards.dat @@ -1243,6 +1243,17 @@ type=Artifact mana={2} [/card] [card] +text=Target player discards two cards. +id=129645 +target=player +auto=discard:2 +name=Mind Rot +rarity=C +color=Black +type=Sorcery +mana={2}{B} +[/card] +[card] text={T}: Add {1} to your mana pool. {1}, {T}, Sacrifice Mind Stone: Draw a card. auto={T}:Add{1} auto={1}{T}{S}:draw:1 diff --git a/projects/mtg/bin/Res/sets/10E/todo.dat b/projects/mtg/bin/Res/sets/10E/todo.dat index e78354ae6..4bd5f3864 100644 --- a/projects/mtg/bin/Res/sets/10E/todo.dat +++ b/projects/mtg/bin/Res/sets/10E/todo.dat @@ -944,15 +944,7 @@ color=Blue type=Instant mana={U} [/card] -[card] -text=Target player discards two cards. -id=129645 -name=Mind Rot -rarity=C -color=Black -type=Sorcery -mana={2}{B} -[/card] + [card] text=At the beginning of your upkeep, if twenty or more creature cards are in your graveyard, you win the game. diff --git a/projects/mtg/bin/Res/sets/TMP/_cards.dat b/projects/mtg/bin/Res/sets/TMP/_cards.dat index c9d78a2ef..2454f6c0c 100644 --- a/projects/mtg/bin/Res/sets/TMP/_cards.dat +++ b/projects/mtg/bin/Res/sets/TMP/_cards.dat @@ -25,6 +25,14 @@ mana={2}{R}{R} type=Sorcery [/card] [card] +text=At the beginning of each player's upkeep, Ancient Runes deals damage to that player equal to the number of artifacts he or she controls. +id=4801 +name=Ancient Runes +rarity=U +type=Enchantment +mana={2}{R} +[/card] +[card] text={T}: Add {2} to your mana pool. Ancient Tomb deals 2 damage to you. auto={T}: Add {2} && Damage 2 controller id=4636 @@ -424,6 +432,16 @@ type=Enchantment subtype=Aura [/card] [card] +text={2}{B}{B}: Put a -1/-1 counter on target creature. +id=4664 +abilities=wither +auto={2}{B}{B}:damage:1 target(creature) +name=Fevered Convulsions +rarity=R +type=Enchantment +mana={B}{B} +[/card] +[card] text=Flying id=4700 name=Fighting Drake diff --git a/projects/mtg/bin/Res/sets/TMP/todo.dat b/projects/mtg/bin/Res/sets/TMP/todo.dat index d4d7535ae..a0b7cb444 100644 --- a/projects/mtg/bin/Res/sets/TMP/todo.dat +++ b/projects/mtg/bin/Res/sets/TMP/todo.dat @@ -7,25 +7,6 @@ type=Sorcery mana={X}{1}{B} [/card] [card] -text=First strike {W}: Target creature gains first strike until end of turn. -id=4857 -name=Advance Scout -rarity=C -type=Creature -mana={1}{W} -power=1 -subtype=Human Soldier Scout -toughness=1 -[/card] -[card] -text=Destroy target artifact, creature, or land. Aftershock deals 3 damage to you. -id=4800 -name=Aftershock -rarity=C -type=Sorcery -mana={2}{R}{R} -[/card] -[card] text=Sacrifice a creature: Target player puts a number of cards equal to the sacrificed creature's power from the top of his or her library into his or her graveyard. id=4596 name=Altar of Dementia @@ -41,15 +22,6 @@ rarity=R type=Enchantment mana={2}{G}{G} [/card] -[card] -text=At the beginning of each player's upkeep, Ancient Runes deals damage to that player equal to the number of artifacts he or she controls. -id=4801 -name=Ancient Runes -rarity=U -type=Enchantment -mana={2}{R} -[/card] - [card] text=Flying Whenever Angelic Protector becomes the target of a spell or ability, Angelic Protector gets +0/+3 until end of turn. id=4858 @@ -100,8 +72,6 @@ power=2 subtype=Sliver toughness=2 [/card] - - [card] text=Flying When Avenging Angel is put into a graveyard from play, you may put Avenging Angel on top of its owner's library. id=4863 @@ -113,7 +83,6 @@ power=3 subtype=Angel toughness=3 [/card] - [card] text=All Sliver creatures have "{2}: This creature gets +1/+0 until end of turn." id=4803 @@ -462,17 +431,6 @@ type=Artifact mana={4} [/card] [card] -text=Other Elf creatures have forestwalk. Other Elves have shroud. (They can't be the targets of spells or abilities.) -id=4757 -name=Eladamri, Lord of Leaves -rarity=R -type=Legendary Creature -mana={G}{G} -power=2 -subtype=Elf Warrior -toughness=2 -[/card] -[card] text=At the beginning of each player's precombat main phase, add {G}{G} to that player's mana pool. id=4758 name=Eladamri's Vineyard @@ -617,14 +575,7 @@ rarity=R type=Sorcery mana={4}{B} [/card] -[card] -text={2}{B}{B}: Put a -1/-1 counter on target creature. -id=4664 -name=Fevered Convulsions -rarity=R -type=Enchantment -mana={B}{B} -[/card] + [card] text=Whenever a nontoken creature is put into your graveyard from play, put a 1/1 white Spirit creature token with flying into play. id=4874 @@ -634,7 +585,6 @@ type=Enchantment mana={2}{W}{W} [/card] - [card] text={T}: Fireslinger deals 1 damage to target creature or player and 1 damage to you. id=4814 diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 4193148d8..fce6341b6 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -1,217 +1,217 @@ -#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 "GameOptions.h" -#include "Token.h" -#include "WEvent.h" - -#include -#include - - -#include -using std::map; - -/* - Generic classes -*/ - -//MayAbility: May do something when comes into play (should be extended) -class MayAbility:public MTGAbility{ -public: - int triggered; - MTGAbility * ability; - int deleteAbility; - MayAbility(int _id, MTGAbility * _ability, MTGCardInstance * _source):MTGAbility(_id,_source),ability(_ability){ - triggered = 0; - ability->forceDestroy = 1; - deleteAbility = 1; - } - - void Update(float dt){ - MTGAbility::Update(dt); - if (!triggered){ - triggered = 1; - game->mLayers->actionLayer()->setMenuObject(source); - OutputDebugString("SetMenuObject!\n"); - } - } - - const char * getMenuText(){ - return ability->getMenuText(); - } - - int testDestroy(){ - if (triggered && !game->mLayers->actionLayer()->menuObject){ - OutputDebugString("Destroy!\n"); - return 1; - } - return 0; - } - - int isReactingToTargetClick(Targetable * card){ - OutputDebugString("IsReacting ???\n"); - if (card == source) return 1; - return 0; - } - - int reactToTargetClick(Targetable * object){ - OutputDebugString("ReactToTargetClick!\n"); - deleteAbility = 0; - game->addObserver(ability); - return ability->reactToTargetClick(object); - } - - ~MayAbility(){ - if (deleteAbility) SAFE_DELETE(ability); - } -}; - - -//MultiAbility : triggers several actions for a cost -class MultiAbility:public ActivatedAbility{ -public: - vector abilities; - vector events; - - MultiAbility(int _id, MTGCardInstance * card,ManaCost * _cost, int _tap):ActivatedAbility(_id, card,_cost,0,_tap){ - } - - - int Add(TriggeredEvent * event){ - events.push_back(event); - return 1; - } - - int Add(MTGAbility * ability){ - abilities.push_back(ability); - return 1; - } - - int resolve(){ +#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 "GameOptions.h" +#include "Token.h" +#include "WEvent.h" + +#include +#include + + +#include +using std::map; + +/* + Generic classes +*/ + +//MayAbility: May do something when comes into play (should be extended) +class MayAbility:public MTGAbility{ +public: + int triggered; + MTGAbility * ability; + int deleteAbility; + MayAbility(int _id, MTGAbility * _ability, MTGCardInstance * _source):MTGAbility(_id,_source),ability(_ability){ + triggered = 0; + ability->forceDestroy = 1; + deleteAbility = 1; + } + + void Update(float dt){ + MTGAbility::Update(dt); + if (!triggered){ + triggered = 1; + game->mLayers->actionLayer()->setMenuObject(source); + OutputDebugString("SetMenuObject!\n"); + } + } + + const char * getMenuText(){ + return ability->getMenuText(); + } + + int testDestroy(){ + if (triggered && !game->mLayers->actionLayer()->menuObject){ + OutputDebugString("Destroy!\n"); + return 1; + } + return 0; + } + + int isReactingToTargetClick(Targetable * card){ + OutputDebugString("IsReacting ???\n"); + if (card == source) return 1; + return 0; + } + + int reactToTargetClick(Targetable * object){ + OutputDebugString("ReactToTargetClick!\n"); + deleteAbility = 0; + game->addObserver(ability); + return ability->reactToTargetClick(object); + } + + ~MayAbility(){ + if (deleteAbility) SAFE_DELETE(ability); + } +}; + + +//MultiAbility : triggers several actions for a cost +class MultiAbility:public ActivatedAbility{ +public: + vector abilities; + vector events; + + MultiAbility(int _id, MTGCardInstance * card,ManaCost * _cost, int _tap):ActivatedAbility(_id, card,_cost,0,_tap){ + } + + + int Add(TriggeredEvent * event){ + events.push_back(event); + return 1; + } + + int Add(MTGAbility * ability){ + abilities.push_back(ability); + return 1; + } + + int resolve(){ vector::size_type sz = abilities.size(); - for (unsigned int i = 0; i < sz; i++){ - abilities[i]->resolve(); - } - sz = events.size(); - for (unsigned int i = 0; i < sz; i++){ - events[i]->resolve(); - } - return 1; - } - - ~MultiAbility(){ + for (unsigned int i = 0; i < sz; i++){ + abilities[i]->resolve(); + } + sz = events.size(); + for (unsigned int i = 0; i < sz; i++){ + events[i]->resolve(); + } + return 1; + } + + ~MultiAbility(){ vector::size_type sz = abilities.size(); - for (unsigned int i = 0; i < sz; i++){ - delete abilities[i]; - } - sz = events.size(); - for (unsigned int i = 0; i < sz; i++){ - delete events[i]; - } - } -}; - - -//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"; - } - - ~ADrawer(){ - OutputDebugString("Deleting ADrawer\n"); - } - -}; - -// Gives/Takes Life to controller of source -class ALifeGiver:public ActivatedAbility{ - public: - int life; - ALifeGiver(int _id, MTGCardInstance * card,ManaCost * _cost, int _life, int _tap = 1):ActivatedAbility(_id, card,_cost,0,_tap),life(_life){ - } - - int resolve(){ - source->controller()->life+=life; - return 1; - } - - - - const char * getMenuText(){ - if (life < 0) return "Lose life"; - return "Gain life"; - } - - -}; - -class ATokenCreator:public ActivatedAbility{ -public: - listabilities; - listtypes; - listcolors; - int power, toughness; - string name; - ATokenCreator(int _id,MTGCardInstance * _source,ManaCost * _cost, string sname, string stypes,int _power,int _toughness, string sabilities, int _doTap):ActivatedAbility(_id,_source,_cost,0,_doTap){ - power = _power; - toughness = _toughness; - name = sname; - -//TODO this is a copy/past of other code that's all around the place, everything should be in a dedicated parser class; - - for (int j = 0; j < Constants::NB_BASIC_ABILITIES; j++){ - unsigned int found = sabilities.find(Constants::MTGBasicAbilities[j]); - if (found != string::npos){ - abilities.push_back(j); - } - } - - for (int j = 0; j < Constants::MTG_NB_COLORS; j++){ - unsigned int found = sabilities.find(Constants::MTGColorStrings[j]); - if (found != string::npos){ - colors.push_back(j); - } - } - - string s = stypes; - while (s.size()){ - unsigned int found = s.find(" "); - if (found != string::npos){ - int id = Subtypes::subtypesList->Add(s.substr(0,found)); - types.push_back(id); - s = s.substr(found+1); - }else{ - int id = Subtypes::subtypesList->Add(s); - types.push_back(id); - s = ""; - } - } - } - - int resolve(){ - Token * myToken = NEW Token(name,source,power,toughness); + for (unsigned int i = 0; i < sz; i++){ + delete abilities[i]; + } + sz = events.size(); + for (unsigned int i = 0; i < sz; i++){ + delete events[i]; + } + } +}; + + +//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"; + } + + ~ADrawer(){ + OutputDebugString("Deleting ADrawer\n"); + } + +}; + +// Gives/Takes Life to controller of source +class ALifeGiver:public ActivatedAbility{ + public: + int life; + ALifeGiver(int _id, MTGCardInstance * card,ManaCost * _cost, int _life, int _tap = 1):ActivatedAbility(_id, card,_cost,0,_tap),life(_life){ + } + + int resolve(){ + source->controller()->life+=life; + return 1; + } + + + + const char * getMenuText(){ + if (life < 0) return "Lose life"; + return "Gain life"; + } + + +}; + +class ATokenCreator:public ActivatedAbility{ +public: + listabilities; + listtypes; + listcolors; + int power, toughness; + string name; + ATokenCreator(int _id,MTGCardInstance * _source,ManaCost * _cost, string sname, string stypes,int _power,int _toughness, string sabilities, int _doTap):ActivatedAbility(_id,_source,_cost,0,_doTap){ + power = _power; + toughness = _toughness; + name = sname; + +//TODO this is a copy/past of other code that's all around the place, everything should be in a dedicated parser class; + + for (int j = 0; j < Constants::NB_BASIC_ABILITIES; j++){ + unsigned int found = sabilities.find(Constants::MTGBasicAbilities[j]); + if (found != string::npos){ + abilities.push_back(j); + } + } + + for (int j = 0; j < Constants::MTG_NB_COLORS; j++){ + unsigned int found = sabilities.find(Constants::MTGColorStrings[j]); + if (found != string::npos){ + colors.push_back(j); + } + } + + string s = stypes; + while (s.size()){ + unsigned int found = s.find(" "); + if (found != string::npos){ + int id = Subtypes::subtypesList->Add(s.substr(0,found)); + types.push_back(id); + s = s.substr(found+1); + }else{ + int id = Subtypes::subtypesList->Add(s); + types.push_back(id); + s = ""; + } + } + } + + int resolve(){ + Token * myToken = NEW Token(name,source,power,toughness); list::iterator it; for ( it=types.begin() ; it != types.end(); it++ ){ myToken->addType(*it); @@ -221,2662 +221,2686 @@ public: } for ( it=abilities.begin() ; it != abilities.end(); it++ ){ myToken->basicAbilities[*it] = 1; - } - source->controller()->game->stack->addCard(myToken); - Spell * spell = NEW Spell(myToken); - - - spell->resolve(); - delete spell; - return 1; - } - -}; - -//Moves Cards from a zone to another -class AZoneMover:public TargetAbility{ - -public: - string destinationZone; - - AZoneMover(int _id, MTGCardInstance * _source, TargetChooser * _tc,string destZone, ManaCost * _cost = NULL, int _tap=0):TargetAbility(_id,_source, _tc,_cost,0,_tap){ - destinationZone = destZone; - } - - static int moveTarget(MTGCardInstance * _target, string destinationZone, MTGCardInstance * source){ - GameObserver * g = GameObserver::GetInstance(); - if(_target){ - Player* p = _target->controller(); - if (p){ - MTGGameZone * fromZone = _target->getCurrentZone(); - MTGGameZone * destZone = MTGGameZone::stringToZone(destinationZone, source,_target); - - //inplay is a special zone ! - for (int i=0; i < 2; i++){ - if (destZone == g->players[i]->game->inPlay){ - MTGCardInstance * copy = g->players[i]->game->putInZone(_target, fromZone, g->players[i]->game->stack); - Spell * spell = NEW Spell(copy); - - spell->resolve(); - delete spell; - return 1; - } - } - p->game->putInZone(_target,fromZone,destZone); - } - return 1; - } - return 0; - } - - int resolve(){ - MTGCardInstance * _target = tc->getNextCardTarget(); - return moveTarget(_target,destinationZone, source); - } -}; - - -//Moves Cards from a zone to another -//TODO: this looks awfully similar to the equivalent targetAbility...woudln't there be a way to merge them ? -class AZoneSelfMover:public ActivatedAbility{ - -public: - string destinationZone; - - AZoneSelfMover(int _id, MTGCardInstance * _source,string destZone, ManaCost * _cost = NULL, int _tap=0):ActivatedAbility(_id,_source,_cost,0,_tap){ - destinationZone = destZone; - } - - int resolve(){ - MTGCardInstance * _target = source; - if(_target){ - Player* p = _target->controller(); - if (p){ - MTGGameZone * fromZone = _target->getCurrentZone(); - MTGGameZone * destZone = MTGGameZone::stringToZone(destinationZone, source,_target); - //inplay is a special zone ! - for (int i=0; i < 2; i++){ - if (destZone == game->players[i]->game->inPlay){ - MTGCardInstance * copy = game->players[i]->game->putInZone(_target, fromZone, game->players[i]->game->stack); - Spell * spell = NEW Spell(copy); - - spell->resolve(); - delete spell; - return 1; - } - } - p->game->putInZone(_target,fromZone,destZone); - } - return 1; - } - return 0; - } -}; - - -//Copier. TargetAbility -class ACopier:public TargetAbility{ - public: - ACopier(int _id, MTGCardInstance * _source, TargetChooser * _tc = NULL, ManaCost * _cost=NULL):TargetAbility(_id,_source, _tc,_cost,0,0){ - if (!tc) tc = NEW CreatureTargetChooser(); - } - - int resolve(){ - MTGCardInstance * _target = tc->getNextCardTarget(); - if(_target){ - source->copy(_target); - return 1; - } - return 0; - } - - const char * getMenuText(){ - return "Copy"; - } - -}; - - -//All Destroyer. TargetAbility -class AAllDestroyer:public ActivatedAbility{ - public: - int bury; - AAllDestroyer(int _id, MTGCardInstance * _source, TargetChooser * _tc, int _bury = 0, ManaCost * _cost=NULL,int doTap =1):ActivatedAbility(_id,_source,_cost,0,doTap),bury(_bury){ - tc = _tc; - - } - - int resolve(){ - AbilityFactory af; - af.destroyAllInPlay(tc,bury); - return 1; - } - - const char * getMenuText(){ - return "Destroy All..."; - } - -}; - -//Destroyer. TargetAbility -class ADestroyer:public TargetAbility{ - public: - int bury; - ADestroyer(int _id, MTGCardInstance * _source, TargetChooser * _tc = NULL, int _bury = 0, ManaCost * _cost=NULL):TargetAbility(_id,_source, _tc,_cost),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,ManaCost * _cost=NULL):ADestroyer(_id,_source, _tc,1,_cost){ - } - - 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 == Constants::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 Constants::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 == Constants::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 Constants::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, ManaCost * mana = NULL){ - if (_card == source && game->currentlyActing()->game->inPlay->hasCard(source)){ - if (game->currentlyActing()->getManaPool()->canAfford(cost)){ - Interruptible * laststackitem = game->mLayers->stackLayer()->getAt(-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,ManaCost * mana = NULL){ - 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 == Constants::MTG_PHASE_UNTAP) untappedThisTurn = 0; - AUnBlocker::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ - if (onlyPlayerTurn && game->currentPlayer!=source->controller()) return 0; - if (untappedThisTurn) return 0; - return AUnBlocker::isReactingToClick(card,mana); - } - - 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, int doTap=1):TargetAbility(_id,_source,_tc,_cost,0,doTap),power(_power),toughness(_toughness){ - if (!tc) tc = NEW CreatureTargetChooser(_source); - nbTargets = 0; - } - - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == Constants::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 ActivatedAbility{ - public: - int power, toughness; - int counters; - int maxcounters; - APowerToughnessModifierUntilEndOfTurn(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness, ManaCost * _cost, int _maxcounters = 0):ActivatedAbility(id,_source,_cost,0,0),power(_power),toughness(_toughness),maxcounters(_maxcounters){ - counters = 0; - target=_target; - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_UNTAP){ - while(counters){ - ((MTGCardInstance *)target)->power -= power; - ((MTGCardInstance *)target)->addToToughness(-toughness); - counters--; - } - } - ActivatedAbility::Update(dt); - } - - int fireAbility(){ - return resolve(); - } - - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ - if (!ActivatedAbility::isReactingToClick(card,mana)) return 0; - return (!maxcounters || (counters < maxcounters)); - } - - int resolve(){ - ((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; - } - -}; - - -//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(Constants::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; - aType = MTGAbility::STANDARD_REGENERATE; - } - - 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; - } - - ~AProtectionFrom(){ - delete(cd); - } - -}; - -//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() && game->isInPlay(card)) 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() && game->isInPlay(card)) 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) && game->isInPlay(card)) 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: - int power, toughness; - int ability; - int modifier; - ManaCost * regenCost; - int includeSelf; - map regenerations; - ALord(int _id, MTGCardInstance * card, TargetChooser * _tc, int _includeSelf, int _power = 0 , int _toughness = 0, int _ability = -1, ManaCost * _regenCost = NULL, int _modifier = 1):ListMaintainerAbility(_id,card){ - tc = _tc; - tc->source = NULL; - includeSelf = _includeSelf; - power = _power; - toughness = _toughness; - ability = _ability; - regenCost = _regenCost; - modifier = _modifier; - if (!modifier) modifier = -1; - } - - int canBeInList(MTGCardInstance * card){ - if ( (includeSelf || card!=source) && tc->canTarget(card)) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - card->power += power; - card->addToToughness(toughness); - if (ability != -1) card->basicAbilities[ability] +=modifier; - if (regenCost){ - ManaCost * _regenCost = NEW ManaCost(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]>0 && (modifier >0)) || (card->basicAbilities[ability]<=0 && (modifier <0)) )) card->basicAbilities[ability] -=modifier; - if (regenCost){ - if(regenerations.find(card) != regenerations.end()){ - if (game->isInPlay(card)) game->removeObserver(regenerations[card]); - regenerations.erase(card); - } - } - return 1; - } - -}; - - -class ALordUEOT:public ALord{ -public: - ALordUEOT(int _id, MTGCardInstance * card, TargetChooser * _tc, int _includeSelf, int _power = 0 , int _toughness = 0, int _ability = -1, ManaCost * _regenCost = NULL, int _modifier = 1): ALord(_id, card, _tc, _includeSelf, _power , _toughness , _ability , _regenCost, _modifier){ - } - - - int testDestroy(){ - if (newPhase == Constants::MTG_PHASE_AFTER_EOT) return 1; - return 0; - } -}; - -//Foreach (plague rats...) -class AForeach:public ListMaintainerAbility{ - public: - int power, toughness; - int includeSelf; - AForeach(int _id, MTGCardInstance * card,MTGCardInstance * _target, TargetChooser * _tc, int _includeSelf, int _power = 0 , int _toughness = 0):ListMaintainerAbility(_id,card,_target){ - tc = _tc; - tc->source = NULL; - includeSelf = _includeSelf; - power = _power; - toughness = _toughness; - if (!target) target = source; //Is this needed ? - } - - int canBeInList(MTGCardInstance * card){ - if ( (includeSelf || card!=source) && tc->canTarget(card)) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - MTGCardInstance * _target = (MTGCardInstance *)target; - _target->power += power; - _target->addToToughness(toughness); - return 1; - } - - int removed(MTGCardInstance * card){ - MTGCardInstance * _target = (MTGCardInstance *)target; - _target->power -= power; - _target->addToToughness(-toughness); - 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); - aType = MTGAbility::DAMAGER; - } - 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; - Player * p = _target->controller(); - if (p && p->game->inPlay->hasCard(_target)){ //if the target is still in game -> spell was destroyed - _target->changeController(originalController); - } - 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; - Player * p = _target->controller(); - if (p && p->game->inPlay->hasCard(_target)){ - p->game->putInZone(_target, p->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 == Constants::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 == Constants::MTG_PHASE_COMBATEND){ - for (int i = 0; i < nbOpponents ; i++){ - game->mLayers->stackLayer()->addPutInGraveyard(opponents[i]); - } - } - } - } - - int testDestroy(){ - if(!game->isInPlay(source) && currentPhase != Constants::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; - MTGCardInstance * card = library->removeCard(tc->getNextCardTarget()); - library->shuffleTopToBottom(nbcards - 1 ); - library->addCard(card); - init = 0; - return 1; - } - - int resolve(){return 1;}; - - -}; - - - - -//Ankh of Mishra -class AAnkhOfMishra: public ListMaintainerAbility{ - public: - int init; - AAnkhOfMishra(int id, MTGCardInstance * _source):ListMaintainerAbility(id, _source){ - init = 0; - } - - void Update(float dt){ - ListMaintainerAbility::Update(dt); - init = 1; - } - - int canBeInList(MTGCardInstance * card){ - if (card->hasType("land") && game->isInPlay(card)) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - if (!init) return 0; - game->mLayers->stackLayer()->addDamage(source,card->controller(), 2); - return 1; - } - - int removed(MTGCardInstance * card){ - return 1; - } -}; - - - -// Armageddon Clock -class AArmageddonClock:public MTGAbility{ - public: - int counters; - ManaCost cost; - AArmageddonClock(int id, MTGCardInstance * _source):MTGAbility(id, _source){ - counters = 0; - int _cost[] = {Constants::MTG_COLOR_ARTIFACT, 4}; - cost = ManaCost(_cost,1); - } - - void Update(float dt){ - if (newPhase != currentPhase){ - if (newPhase == Constants::MTG_PHASE_UPKEEP && game->currentPlayer->game->inPlay->hasCard(source)){ - counters ++; - }else if (newPhase == Constants::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, ManaCost * mana = NULL){ - if (counters > 0 && _card == source && currentPhase == Constants::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 == Constants::MTG_PHASE_UPKEEP && GameObserver::GetInstance()->opponent()->game->inPlay->hasCard(source)){ - nbcards = game->currentPlayer->game->hand->nb_cards; - } - if (newPhase != currentPhase && newPhase == Constants::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(Constants::MTG_COLOR_ARTIFACT, 1); - return 1; - } - - int testDestroy(){ - if (newPhase != currentPhase && newPhase == Constants::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[] = {Constants::MTG_COLOR_ARTIFACT, 1}; - cost = ManaCost(_cost,1); - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_COMBATEND){ - if (((MTGCardInstance *)source)->isAttacker() || ((MTGCardInstance *)source)->isDefenser()){ - counters--; - ((MTGCardInstance *)target)->power-=1; - } - } - } - int isReactingToClick(MTGCardInstance * _card, ManaCost * mana = NULL){ - if (counters < 7 && _card == source && currentPhase == Constants::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[] = {Constants::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, ManaCost * mana = NULL){ - 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 MTGAbility{ - public: - int resolved; - ACreatureBond(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id,_source,_target){ - resolved = 0; - } - - int receiveEvent(WEvent * event){ - MTGCardInstance * _target = (MTGCardInstance *) target; - if (event->type == WEvent::CHANGE_ZONE){ - WEventZoneChange * e = (WEventZoneChange *) event; - MTGCardInstance * card = e->card->previous; - if (card == _target){ - for (int i = 0; i < 2 ; i++){ - Player * p = game->players[i]; - if (e->to == p->game->graveyard){ - game->mLayers->stackLayer()->addDamage(source,_target->controller(),_target->toughness); - return 1; - } - } - } - } - return 0; - } - -}; - -//1105: Dingus Egg -class ADingusEgg: public ListMaintainerAbility{ - public: - ADingusEgg(int id, MTGCardInstance * _source):ListMaintainerAbility(id, _source){ - } - - int canBeInList(MTGCardInstance * card){ - if (card->hasType("land") && game->isInPlay(card)) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - return 1; - } - - int removed(MTGCardInstance * card){ - game->mLayers->stackLayer()->addDamage(source,card->controller(), 2); - return 1; - } -}; - - - -//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[] = {Constants::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[] = {Constants::MTG_COLOR_ARTIFACT, 2}; - cost = NEW ManaCost(_cost,1); - } - - int resolve(){ - tc->getNextCardTarget()->attacker = 0; - return 1; - } - -}; - -//1345 Farmstead -class AFarmstead:public ActivatedAbility{ - public: - int usedThisTurn; - AFarmstead(int _id, MTGCardInstance * source, MTGCardInstance * _target):ActivatedAbility(_id, source,0,1,0){ - int _cost[] = {Constants::MTG_COLOR_WHITE, 2}; - cost = NEW ManaCost(_cost,1); - target = _target; - usedThisTurn = 0; - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase != Constants::MTG_PHASE_UPKEEP){ - usedThisTurn = 0; - } - ActivatedAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ - if (!ActivatedAbility::isReactingToClick(card,mana)) return 0; - if (currentPhase != Constants::MTG_PHASE_UPKEEP) return 0; - if (usedThisTurn) return 0; - return 1; - } - - int resolve(){ - source->controller()->life++; - usedThisTurn = 1; - return 1; - } - -}; - -//1110 Glasses of Urza -class AGlassesOfUrza:public MTGAbility{ - public: - CardDisplay * display; - bool isActive; - AGlassesOfUrza(int _id, MTGCardInstance * _source):MTGAbility(_id, _source),isActive(false){ - display = NEW CardDisplay(0, game,SCREEN_WIDTH/2, SCREEN_HEIGHT/2,NULL); - } - - void Update(float dt){ - if(isActive){ - display->Update(dt); - } - } - - bool CheckUserInput(u32 key){ - if (isActive){ - if (display->CheckUserInput(key)) return true; - if (PSP_CTRL_CROSS == key){ - isActive = false; - return true; - } - } - return false; - } - - void Render(float dt){ - if (isActive){ - display->Render(); - } - - } - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ - 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; - isActive = true; - 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 == Constants::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[] = {Constants::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 == Constants::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, ManaCost * mana = NULL){ - if (currentPhase == Constants::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 == Constants::MTG_PHASE_UNTAP){ - paidThisTurn = 0; - }else if( newPhase == Constants::MTG_PHASE_UPKEEP + 1 && !paidThisTurn){ - game->mLayers->stackLayer()->addDamage(source,source->controller(), 7); - } - } - TargetAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ - if (currentPhase != Constants::MTG_PHASE_UPKEEP || paidThisTurn) return 0; - return TargetAbility::isReactingToClick(card,mana); - } - - 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; - - //Put the card in play again, with all its abilities ! - //AbilityFactory af; - MTGCardInstance * copy = source->controller()->game->putInZone(card, _target->controller()->game->graveyard, source->controller()->game->stack); - Spell * spell = NEW Spell(copy); - //af.addAbilities(game->mLayers->actionLayer()->getMaxId(), spell); - - spell->resolve(); - target = spell->source; - card = spell->source; - card->power--; - card->life = card->toughness; - delete spell; - } - - int destroy(){ - MTGCardInstance * card = (MTGCardInstance *) target; - card->power++; - card->controller()->game->putInZone(card, card->controller()->game->inPlay,card->owner->game->graveyard); - 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 == Constants::MTG_PHASE_COMBATDAMAGE && game->currentPlayer == controller){ - if (!source->isAttacker() && init){ - dealDamage = 1; - } - }else if (newPhase == Constants::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; - int previous; - AFastbond(int _id, MTGCardInstance * card):TriggeredAbility(_id, card){ - alreadyPlayedALand = 0; - } - - void Update(float dt){ - if (newPhase!=currentPhase && newPhase == Constants::MTG_PHASE_UNTAP){ - alreadyPlayedALand = 0; - } - TriggeredAbility::Update(dt); - } - - int trigger(){ - if(source->controller()->canPutLandsIntoPlay==0 && previous ==1){ - previous = 0; - source->controller()->canPutLandsIntoPlay = 1; - if (alreadyPlayedALand) return 1; - alreadyPlayedALand = 1; - return 0; - } - previous = source->controller()->canPutLandsIntoPlay; - return 0; - } - - int resolve(){ - game->mLayers->stackLayer()->addDamage(source, source->controller(), 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 == Constants::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(Constants::MTG_COLOR_ARTIFACT, 2); - } - - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ - if (!source->controller()->game->hand->hasCard(source->controller()->game->library->lastCardDrawn)) return 0; - return ActivatedAbility::isReactingToClick(card,mana); - } - - 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 && !_target->tapped){ - previouslyTapped = 0; - }else if (!previouslyTapped){ -#if defined (WIN32) || defined (LINUX) - OutputDebugString("Kudzu Strikes !\n"); -#endif - MTGCardInstance * _target = (MTGCardInstance *)target; - target = _target->controller()->game->putInGraveyard(_target); - reactToClick(source); // ???? - } - TargetAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ - 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 resolve(){ - target = tc->getNextCardTarget(); - source->target = (MTGCardInstance *) target; - previouslyTapped = 0; - if (source->target && source->target->tapped) previouslyTapped = 1; - return 1; - } - - int testDestroy(){ - 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(Constants::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; - } - -}; - - - - -//1172 Pestilence -class APestilence: public ActivatedAbility{ - public: - APestilence(int _id, MTGCardInstance * card):ActivatedAbility(_id, card, NEW ManaCost(), 0,0){ - cost->add(Constants::MTG_COLOR_BLACK, 1); - } - - void Update(float dt){ - if (newPhase !=currentPhase && newPhase == Constants::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; - } - -}; - - -//Power Leak -class APowerLeak:public TriggeredAbility{ - public: - int damagesToDealThisTurn; - ManaCost cost; - APowerLeak(int _id, MTGCardInstance * _source, MTGCardInstance * _target):TriggeredAbility(_id, _source, _target){ - cost.add(Constants::MTG_COLOR_ARTIFACT, 1); - damagesToDealThisTurn = 0; - } - - void Update(float dt){ - MTGCardInstance * _target = (MTGCardInstance *) target; - if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_UPKEEP && _target->controller() == game->currentPlayer){ - damagesToDealThisTurn = 2; - } - TriggeredAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ - MTGCardInstance * _target = (MTGCardInstance *) target; - if (damagesToDealThisTurn && currentPhase == Constants::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 == Constants::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 == Constants::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 == Constants::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(Constants::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, ManaCost * mana = NULL){ - 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 == Constants::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") && game->isInPlay(card)) 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 == Constants::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; - } -}; - - -//1284 Dragon Whelp -class ADragonWhelp: public APowerToughnessModifierUntilEndOfTurn{ - public: - ADragonWhelp(int id, MTGCardInstance * card):APowerToughnessModifierUntilEndOfTurn(id, card, card, 1, 0, NEW ManaCost()){ - cost->add(Constants::MTG_COLOR_RED, 1); - } - - void Update(float dt){ - if (newPhase != currentPhase && newPhase == Constants::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,Constants::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(Constants::MTG_COLOR_GREEN,4); - } - - void Update(float dt){ - if (newPhase !=currentPhase){ - if (newPhase == Constants::MTG_PHASE_UNTAP){ - dealDamageThisTurn = 1; - }else if (newPhase == Constants::MTG_PHASE_DRAW && dealDamageThisTurn && game->currentPlayer==source->controller() ){ - game->mLayers->stackLayer()->addDamage(source,source->controller(),8); - } - } - ActivatedAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ - return (dealDamageThisTurn && currentPhase == Constants::MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card,mana)); - } - - int resolve(){ - dealDamageThisTurn = 0; - return 1; - } -}; - - - - -//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; - } - -}; - - -//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 == Constants::MTG_PHASE_UNTAP && game->currentPlayer == source->controller()) initThisTurn = 0; - - if (initThisTurn && currentPhase == Constants::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[Constants::FLYING] && !card->basicAbilities[Constants::ISLANDWALK]) card->attacker=0; - } - } - } - - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ - if (card==source && game->currentPlayer == card->controller() && currentPhase == Constants::MTG_PHASE_DRAW){ - Interruptible * action = game->mLayers->stackLayer()->getAt(-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()->getAt(-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 == Constants::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; - } -}; - - -//Soul Net -class ASoulNet:public ActivatedAbility{ - public: - PutInGraveyard * latest; - PutInGraveyard * newDead; - ASoulNet(int _id, MTGCardInstance * card):ActivatedAbility(_id, card,0,0,0){ - int _cost[] = {Constants::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, ManaCost * mana = NULL){ - newDead = ((PutInGraveyard *) GameObserver::GetInstance()->mLayers->stackLayer()->getPrevious(NULL,ACTION_PUTINGRAVEYARD,RESOLVED_OK)); - if (newDead && newDead != latest && newDead->card->isACreature()) - return ActivatedAbility::isReactingToClick(card,mana); - 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(Constants::MTG_COLOR_BLUE,1); - } - - void Update(float dt){ - //Upkeep Cost - if (newPhase !=currentPhase){ - if (newPhase == Constants::MTG_PHASE_UPKEEP){ - paidThisTurn = 0; - }else if (!paidThisTurn && newPhase > Constants::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(Constants::MTG_PHASE_UNTAP,game->players[i]); - } - - //Parent Class Method Call - ActivatedAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ - return (!paidThisTurn && currentPhase == Constants::MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card,mana)); - } - - int resolve(){ - paidThisTurn = 1; - return 1; - } - - int destroy(){ - for (int i = 0; i < 2; i++){ - game->phaseRing->addPhaseBefore(Constants::MTG_PHASE_UNTAP,game->players[i],Constants::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(Constants::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 == Constants::MTG_PHASE_COMBATDAMAGE){ - nbOpponents = 0; - MTGCardInstance * opponent = source->getNextOpponent(); - while ((opponent && opponent->hasColor(Constants::MTG_COLOR_GREEN)) || opponent->hasColor(Constants::MTG_COLOR_WHITE)){ - opponents[nbOpponents] = opponent; - nbOpponents ++; - opponent = source->getNextOpponent(opponent); - } - }else if (newPhase == Constants::MTG_PHASE_COMBATEND){ - for (int i = 0; i < nbOpponents ; i++){ - game->mLayers->stackLayer()->addPutInGraveyard(opponents[i]); - } - } - } - } - - int testDestroy(){ - if(!game->isInPlay(source) && currentPhase != Constants::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 == Constants::MTG_PHASE_UNTAP){ - paidThisTurn = 0; - }else if( newPhase == Constants::MTG_PHASE_UPKEEP + 1 && !paidThisTurn){ - game->mLayers->stackLayer()->addDamage(source,source->controller(), 5); - source->tapped = 1; - } - } - TargetAbility::Update(dt); - } - - int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ - if (currentPhase != Constants::MTG_PHASE_UPKEEP || paidThisTurn) return 0; - return TargetAbility::isReactingToClick(card,mana); - } - - 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; - } - -}; - - - - - -//Generic Kird Ape -class AKirdApe:public ListMaintainerAbility{ - public: - int power; - int toughness; - int ability; - int modifier; - int includeSelf; - AKirdApe(int _id, MTGCardInstance * _source, TargetChooser * _tc, int _includeSelf,int _power = 0, int _toughness = 0, int _ability=-1, int _abilityModifier = 1):ListMaintainerAbility(_id, _source){ - power = _power; - toughness = _toughness; - tc = _tc; - includeSelf = _includeSelf; - ability=_ability; - modifier = _abilityModifier; - if (!modifier) modifier = -1; - } - - int canBeInList(MTGCardInstance * card){ - if ((includeSelf || card!=source) && tc->canTarget(card)) return 1; - return 0; - } - - int added(MTGCardInstance * card){ - if (cards.size()== 1){ - source->power+=power; - source->addToToughness(toughness); - if (ability != -1) source->basicAbilities[ability] +=modifier; - return 1; - } - return 0; - } - - int removed(MTGCardInstance * card){ - - if (cards.size()== 0){ - source->power-=power; - source->addToToughness(-toughness); - if ((ability != -1) && source->basicAbilities[ability] >0 ) source->basicAbilities[ability] -=modifier; - return 1; - } - return 0; - } - - -}; - - -//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 == Constants::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 + } + source->controller()->game->stack->addCard(myToken); + Spell * spell = NEW Spell(myToken); + + + spell->resolve(); + delete spell; + return 1; + } + +}; + +//Moves Cards from a zone to another +class AZoneMover:public TargetAbility{ + +public: + string destinationZone; + + AZoneMover(int _id, MTGCardInstance * _source, TargetChooser * _tc,string destZone, ManaCost * _cost = NULL, int _tap=0):TargetAbility(_id,_source, _tc,_cost,0,_tap){ + destinationZone = destZone; + } + + static int moveTarget(MTGCardInstance * _target, string destinationZone, MTGCardInstance * source){ + GameObserver * g = GameObserver::GetInstance(); + if(_target){ + Player* p = _target->controller(); + if (p){ + MTGGameZone * fromZone = _target->getCurrentZone(); + MTGGameZone * destZone = MTGGameZone::stringToZone(destinationZone, source,_target); + + //inplay is a special zone ! + for (int i=0; i < 2; i++){ + if (destZone == g->players[i]->game->inPlay){ + MTGCardInstance * copy = g->players[i]->game->putInZone(_target, fromZone, g->players[i]->game->stack); + Spell * spell = NEW Spell(copy); + + spell->resolve(); + delete spell; + return 1; + } + } + p->game->putInZone(_target,fromZone,destZone); + } + return 1; + } + return 0; + } + + int resolve(){ + MTGCardInstance * _target = tc->getNextCardTarget(); + return moveTarget(_target,destinationZone, source); + } +}; + + +//Moves Cards from a zone to another +//TODO: this looks awfully similar to the equivalent targetAbility...woudln't there be a way to merge them ? +class AZoneSelfMover:public ActivatedAbility{ + +public: + string destinationZone; + + AZoneSelfMover(int _id, MTGCardInstance * _source,string destZone, ManaCost * _cost = NULL, int _tap=0):ActivatedAbility(_id,_source,_cost,0,_tap){ + destinationZone = destZone; + } + + int resolve(){ + MTGCardInstance * _target = source; + if(_target){ + Player* p = _target->controller(); + if (p){ + MTGGameZone * fromZone = _target->getCurrentZone(); + MTGGameZone * destZone = MTGGameZone::stringToZone(destinationZone, source,_target); + //inplay is a special zone ! + for (int i=0; i < 2; i++){ + if (destZone == game->players[i]->game->inPlay){ + MTGCardInstance * copy = game->players[i]->game->putInZone(_target, fromZone, game->players[i]->game->stack); + Spell * spell = NEW Spell(copy); + + spell->resolve(); + delete spell; + return 1; + } + } + p->game->putInZone(_target,fromZone,destZone); + } + return 1; + } + return 0; + } +}; + + +//Copier. TargetAbility +class ACopier:public TargetAbility{ + public: + ACopier(int _id, MTGCardInstance * _source, TargetChooser * _tc = NULL, ManaCost * _cost=NULL):TargetAbility(_id,_source, _tc,_cost,0,0){ + if (!tc) tc = NEW CreatureTargetChooser(); + } + + int resolve(){ + MTGCardInstance * _target = tc->getNextCardTarget(); + if(_target){ + source->copy(_target); + return 1; + } + return 0; + } + + const char * getMenuText(){ + return "Copy"; + } + +}; + + +//All Destroyer. TargetAbility +class AAllDestroyer:public ActivatedAbility{ + public: + int bury; + AAllDestroyer(int _id, MTGCardInstance * _source, TargetChooser * _tc, int _bury = 0, ManaCost * _cost=NULL,int doTap =1):ActivatedAbility(_id,_source,_cost,0,doTap),bury(_bury){ + tc = _tc; + + } + + int resolve(){ + AbilityFactory af; + af.destroyAllInPlay(tc,bury); + return 1; + } + + const char * getMenuText(){ + return "Destroy All..."; + } + +}; + +//Destroyer. TargetAbility +class ADestroyer:public TargetAbility{ + public: + int bury; + ADestroyer(int _id, MTGCardInstance * _source, TargetChooser * _tc = NULL, int _bury = 0, ManaCost * _cost=NULL):TargetAbility(_id,_source, _tc,_cost),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,ManaCost * _cost=NULL):ADestroyer(_id,_source, _tc,1,_cost){ + } + + 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 == Constants::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 Constants::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 == Constants::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 Constants::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, ManaCost * mana = NULL){ + if (_card == source && game->currentlyActing()->game->inPlay->hasCard(source)){ + if (game->currentlyActing()->getManaPool()->canAfford(cost)){ + Interruptible * laststackitem = game->mLayers->stackLayer()->getAt(-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,ManaCost * mana = NULL){ + 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 == Constants::MTG_PHASE_UNTAP) untappedThisTurn = 0; + AUnBlocker::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + if (onlyPlayerTurn && game->currentPlayer!=source->controller()) return 0; + if (untappedThisTurn) return 0; + return AUnBlocker::isReactingToClick(card,mana); + } + + 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, int doTap=1):TargetAbility(_id,_source,_tc,_cost,0,doTap),power(_power),toughness(_toughness){ + if (!tc) tc = NEW CreatureTargetChooser(_source); + nbTargets = 0; + } + + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == Constants::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 ActivatedAbility{ + public: + int power, toughness; + int counters; + int maxcounters; + APowerToughnessModifierUntilEndOfTurn(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness, ManaCost * _cost, int _maxcounters = 0):ActivatedAbility(id,_source,_cost,0,0),power(_power),toughness(_toughness),maxcounters(_maxcounters){ + counters = 0; + target=_target; + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_UNTAP){ + while(counters){ + ((MTGCardInstance *)target)->power -= power; + ((MTGCardInstance *)target)->addToToughness(-toughness); + counters--; + } + } + ActivatedAbility::Update(dt); + } + + int fireAbility(){ + return resolve(); + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + if (!ActivatedAbility::isReactingToClick(card,mana)) return 0; + return (!maxcounters || (counters < maxcounters)); + } + + int resolve(){ + ((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; + } + +}; + + +//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(Constants::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; + aType = MTGAbility::STANDARD_REGENERATE; + } + + 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; + } + + ~AProtectionFrom(){ + delete(cd); + } + +}; + +//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() && game->isInPlay(card)) 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() && game->isInPlay(card)) 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) && game->isInPlay(card)) 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: + int power, toughness; + int ability; + int modifier; + ManaCost * regenCost; + int includeSelf; + map regenerations; + ALord(int _id, MTGCardInstance * card, TargetChooser * _tc, int _includeSelf, int _power = 0 , int _toughness = 0, int _ability = -1, ManaCost * _regenCost = NULL, int _modifier = 1):ListMaintainerAbility(_id,card){ + tc = _tc; + tc->source = NULL; + includeSelf = _includeSelf; + power = _power; + toughness = _toughness; + ability = _ability; + regenCost = _regenCost; + modifier = _modifier; + if (!modifier) modifier = -1; + } + + int canBeInList(MTGCardInstance * card){ + if ( (includeSelf || card!=source) && tc->canTarget(card)) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + card->power += power; + card->addToToughness(toughness); + if (ability != -1) card->basicAbilities[ability] +=modifier; + if (regenCost){ + ManaCost * _regenCost = NEW ManaCost(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]>0 && (modifier >0)) || (card->basicAbilities[ability]<=0 && (modifier <0)) )) card->basicAbilities[ability] -=modifier; + if (regenCost){ + if(regenerations.find(card) != regenerations.end()){ + if (game->isInPlay(card)) game->removeObserver(regenerations[card]); + regenerations.erase(card); + } + } + return 1; + } + +}; + + +class ALordUEOT:public ALord{ +public: + ALordUEOT(int _id, MTGCardInstance * card, TargetChooser * _tc, int _includeSelf, int _power = 0 , int _toughness = 0, int _ability = -1, ManaCost * _regenCost = NULL, int _modifier = 1): ALord(_id, card, _tc, _includeSelf, _power , _toughness , _ability , _regenCost, _modifier){ + } + + + int testDestroy(){ + if (newPhase == Constants::MTG_PHASE_AFTER_EOT) return 1; + return 0; + } +}; + +//Foreach (plague rats...) +class AForeach:public ListMaintainerAbility{ + public: + int power, toughness; + int includeSelf; + AForeach(int _id, MTGCardInstance * card,MTGCardInstance * _target, TargetChooser * _tc, int _includeSelf, int _power = 0 , int _toughness = 0):ListMaintainerAbility(_id,card,_target){ + tc = _tc; + tc->source = NULL; + includeSelf = _includeSelf; + power = _power; + toughness = _toughness; + if (!target) target = source; //Is this needed ? + } + + int canBeInList(MTGCardInstance * card){ + if ( (includeSelf || card!=source) && tc->canTarget(card)) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + MTGCardInstance * _target = (MTGCardInstance *)target; + _target->power += power; + _target->addToToughness(toughness); + return 1; + } + + int removed(MTGCardInstance * card){ + MTGCardInstance * _target = (MTGCardInstance *)target; + _target->power -= power; + _target->addToToughness(-toughness); + 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); + aType = MTGAbility::DAMAGER; + } + 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; + Player * p = _target->controller(); + if (p && p->game->inPlay->hasCard(_target)){ //if the target is still in game -> spell was destroyed + _target->changeController(originalController); + } + 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; + Player * p = _target->controller(); + if (p && p->game->inPlay->hasCard(_target)){ + p->game->putInZone(_target, p->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 == Constants::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 == Constants::MTG_PHASE_COMBATEND){ + for (int i = 0; i < nbOpponents ; i++){ + game->mLayers->stackLayer()->addPutInGraveyard(opponents[i]); + } + } + } + } + + int testDestroy(){ + if(!game->isInPlay(source) && currentPhase != Constants::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; + MTGCardInstance * card = library->removeCard(tc->getNextCardTarget()); + library->shuffleTopToBottom(nbcards - 1 ); + library->addCard(card); + init = 0; + return 1; + } + + int resolve(){return 1;}; + + +}; + + + + +//Ankh of Mishra +class AAnkhOfMishra: public ListMaintainerAbility{ + public: + int init; + AAnkhOfMishra(int id, MTGCardInstance * _source):ListMaintainerAbility(id, _source){ + init = 0; + } + + void Update(float dt){ + ListMaintainerAbility::Update(dt); + init = 1; + } + + int canBeInList(MTGCardInstance * card){ + if (card->hasType("land") && game->isInPlay(card)) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + if (!init) return 0; + game->mLayers->stackLayer()->addDamage(source,card->controller(), 2); + return 1; + } + + int removed(MTGCardInstance * card){ + return 1; + } +}; + + + +// Armageddon Clock +class AArmageddonClock:public MTGAbility{ + public: + int counters; + ManaCost cost; + AArmageddonClock(int id, MTGCardInstance * _source):MTGAbility(id, _source){ + counters = 0; + int _cost[] = {Constants::MTG_COLOR_ARTIFACT, 4}; + cost = ManaCost(_cost,1); + } + + void Update(float dt){ + if (newPhase != currentPhase){ + if (newPhase == Constants::MTG_PHASE_UPKEEP && game->currentPlayer->game->inPlay->hasCard(source)){ + counters ++; + }else if (newPhase == Constants::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, ManaCost * mana = NULL){ + if (counters > 0 && _card == source && currentPhase == Constants::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 == Constants::MTG_PHASE_UPKEEP && GameObserver::GetInstance()->opponent()->game->inPlay->hasCard(source)){ + nbcards = game->currentPlayer->game->hand->nb_cards; + } + if (newPhase != currentPhase && newPhase == Constants::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(Constants::MTG_COLOR_ARTIFACT, 1); + return 1; + } + + int testDestroy(){ + if (newPhase != currentPhase && newPhase == Constants::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[] = {Constants::MTG_COLOR_ARTIFACT, 1}; + cost = ManaCost(_cost,1); + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_COMBATEND){ + if (((MTGCardInstance *)source)->isAttacker() || ((MTGCardInstance *)source)->isDefenser()){ + counters--; + ((MTGCardInstance *)target)->power-=1; + } + } + } + int isReactingToClick(MTGCardInstance * _card, ManaCost * mana = NULL){ + if (counters < 7 && _card == source && currentPhase == Constants::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[] = {Constants::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, ManaCost * mana = NULL){ + 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 MTGAbility{ + public: + int resolved; + ACreatureBond(int _id, MTGCardInstance * _source, MTGCardInstance * _target):MTGAbility(_id,_source,_target){ + resolved = 0; + } + + int receiveEvent(WEvent * event){ + MTGCardInstance * _target = (MTGCardInstance *) target; + if (event->type == WEvent::CHANGE_ZONE){ + WEventZoneChange * e = (WEventZoneChange *) event; + MTGCardInstance * card = e->card->previous; + if (card == _target){ + for (int i = 0; i < 2 ; i++){ + Player * p = game->players[i]; + if (e->to == p->game->graveyard){ + game->mLayers->stackLayer()->addDamage(source,_target->controller(),_target->toughness); + return 1; + } + } + } + } + return 0; + } + +}; + +//1105: Dingus Egg +class ADingusEgg: public ListMaintainerAbility{ + public: + ADingusEgg(int id, MTGCardInstance * _source):ListMaintainerAbility(id, _source){ + } + + int canBeInList(MTGCardInstance * card){ + if (card->hasType("land") && game->isInPlay(card)) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + return 1; + } + + int removed(MTGCardInstance * card){ + game->mLayers->stackLayer()->addDamage(source,card->controller(), 2); + return 1; + } +}; + + + +//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[] = {Constants::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[] = {Constants::MTG_COLOR_ARTIFACT, 2}; + cost = NEW ManaCost(_cost,1); + } + + int resolve(){ + tc->getNextCardTarget()->attacker = 0; + return 1; + } + +}; + +//1345 Farmstead +class AFarmstead:public ActivatedAbility{ + public: + int usedThisTurn; + AFarmstead(int _id, MTGCardInstance * source, MTGCardInstance * _target):ActivatedAbility(_id, source,0,1,0){ + int _cost[] = {Constants::MTG_COLOR_WHITE, 2}; + cost = NEW ManaCost(_cost,1); + target = _target; + usedThisTurn = 0; + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase != Constants::MTG_PHASE_UPKEEP){ + usedThisTurn = 0; + } + ActivatedAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + if (!ActivatedAbility::isReactingToClick(card,mana)) return 0; + if (currentPhase != Constants::MTG_PHASE_UPKEEP) return 0; + if (usedThisTurn) return 0; + return 1; + } + + int resolve(){ + source->controller()->life++; + usedThisTurn = 1; + return 1; + } + +}; + +//1110 Glasses of Urza +class AGlassesOfUrza:public MTGAbility{ + public: + CardDisplay * display; + bool isActive; + AGlassesOfUrza(int _id, MTGCardInstance * _source):MTGAbility(_id, _source),isActive(false){ + display = NEW CardDisplay(0, game,SCREEN_WIDTH/2, SCREEN_HEIGHT/2,NULL); + } + + void Update(float dt){ + if(isActive){ + display->Update(dt); + } + } + + bool CheckUserInput(u32 key){ + if (isActive){ + if (display->CheckUserInput(key)) return true; + if (PSP_CTRL_CROSS == key){ + isActive = false; + return true; + } + } + return false; + } + + void Render(float dt){ + if (isActive){ + display->Render(); + } + + } + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + 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; + isActive = true; + 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 == Constants::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[] = {Constants::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 == Constants::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, ManaCost * mana = NULL){ + if (currentPhase == Constants::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 == Constants::MTG_PHASE_UNTAP){ + paidThisTurn = 0; + }else if( newPhase == Constants::MTG_PHASE_UPKEEP + 1 && !paidThisTurn){ + game->mLayers->stackLayer()->addDamage(source,source->controller(), 7); + } + } + TargetAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + if (currentPhase != Constants::MTG_PHASE_UPKEEP || paidThisTurn) return 0; + return TargetAbility::isReactingToClick(card,mana); + } + + 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; + + //Put the card in play again, with all its abilities ! + //AbilityFactory af; + MTGCardInstance * copy = source->controller()->game->putInZone(card, _target->controller()->game->graveyard, source->controller()->game->stack); + Spell * spell = NEW Spell(copy); + //af.addAbilities(game->mLayers->actionLayer()->getMaxId(), spell); + + spell->resolve(); + target = spell->source; + card = spell->source; + card->power--; + card->life = card->toughness; + delete spell; + } + + int destroy(){ + MTGCardInstance * card = (MTGCardInstance *) target; + card->power++; + card->controller()->game->putInZone(card, card->controller()->game->inPlay,card->owner->game->graveyard); + 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 == Constants::MTG_PHASE_COMBATDAMAGE && game->currentPlayer == controller){ + if (!source->isAttacker() && init){ + dealDamage = 1; + } + }else if (newPhase == Constants::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; + int previous; + AFastbond(int _id, MTGCardInstance * card):TriggeredAbility(_id, card){ + alreadyPlayedALand = 0; + } + + void Update(float dt){ + if (newPhase!=currentPhase && newPhase == Constants::MTG_PHASE_UNTAP){ + alreadyPlayedALand = 0; + } + TriggeredAbility::Update(dt); + } + + int trigger(){ + if(source->controller()->canPutLandsIntoPlay==0 && previous ==1){ + previous = 0; + source->controller()->canPutLandsIntoPlay = 1; + if (alreadyPlayedALand) return 1; + alreadyPlayedALand = 1; + return 0; + } + previous = source->controller()->canPutLandsIntoPlay; + return 0; + } + + int resolve(){ + game->mLayers->stackLayer()->addDamage(source, source->controller(), 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 == Constants::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(Constants::MTG_COLOR_ARTIFACT, 2); + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + if (!source->controller()->game->hand->hasCard(source->controller()->game->library->lastCardDrawn)) return 0; + return ActivatedAbility::isReactingToClick(card,mana); + } + + 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 && !_target->tapped){ + previouslyTapped = 0; + }else if (!previouslyTapped){ +#if defined (WIN32) || defined (LINUX) + OutputDebugString("Kudzu Strikes !\n"); +#endif + MTGCardInstance * _target = (MTGCardInstance *)target; + target = _target->controller()->game->putInGraveyard(_target); + reactToClick(source); // ???? + } + TargetAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + 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 resolve(){ + target = tc->getNextCardTarget(); + source->target = (MTGCardInstance *) target; + previouslyTapped = 0; + if (source->target && source->target->tapped) previouslyTapped = 1; + return 1; + } + + int testDestroy(){ + 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(Constants::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; + } + +}; + + + +//1172 Pestilence +class APestilence: public ActivatedAbility{ + public: + APestilence(int _id, MTGCardInstance * card):ActivatedAbility(_id, card, NEW ManaCost(), 0,0){ + cost->add(Constants::MTG_COLOR_BLACK, 1); + } + + void Update(float dt){ + if (newPhase !=currentPhase && newPhase == Constants::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; + } + +}; + + +//Power Leak +class APowerLeak:public TriggeredAbility{ + public: + int damagesToDealThisTurn; + ManaCost cost; + APowerLeak(int _id, MTGCardInstance * _source, MTGCardInstance * _target):TriggeredAbility(_id, _source, _target){ + cost.add(Constants::MTG_COLOR_ARTIFACT, 1); + damagesToDealThisTurn = 0; + } + + void Update(float dt){ + MTGCardInstance * _target = (MTGCardInstance *) target; + if (newPhase != currentPhase && newPhase == Constants::MTG_PHASE_UPKEEP && _target->controller() == game->currentPlayer){ + damagesToDealThisTurn = 2; + } + TriggeredAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + MTGCardInstance * _target = (MTGCardInstance *) target; + if (damagesToDealThisTurn && currentPhase == Constants::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 == Constants::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 == Constants::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 == Constants::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(Constants::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, ManaCost * mana = NULL){ + 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 == Constants::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") && game->isInPlay(card)) 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 == Constants::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; + } +}; + + +//1284 Dragon Whelp +class ADragonWhelp: public APowerToughnessModifierUntilEndOfTurn{ + public: + ADragonWhelp(int id, MTGCardInstance * card):APowerToughnessModifierUntilEndOfTurn(id, card, card, 1, 0, NEW ManaCost()){ + cost->add(Constants::MTG_COLOR_RED, 1); + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase == Constants::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,Constants::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(Constants::MTG_COLOR_GREEN,4); + } + + void Update(float dt){ + if (newPhase !=currentPhase){ + if (newPhase == Constants::MTG_PHASE_UNTAP){ + dealDamageThisTurn = 1; + }else if (newPhase == Constants::MTG_PHASE_DRAW && dealDamageThisTurn && game->currentPlayer==source->controller() ){ + game->mLayers->stackLayer()->addDamage(source,source->controller(),8); + } + } + ActivatedAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + return (dealDamageThisTurn && currentPhase == Constants::MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card,mana)); + } + + int resolve(){ + dealDamageThisTurn = 0; + return 1; + } +}; + + + + +//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; + } + +}; + + +//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 == Constants::MTG_PHASE_UNTAP && game->currentPlayer == source->controller()) initThisTurn = 0; + + if (initThisTurn && currentPhase == Constants::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[Constants::FLYING] && !card->basicAbilities[Constants::ISLANDWALK]) card->attacker=0; + } + } + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + if (card==source && game->currentPlayer == card->controller() && currentPhase == Constants::MTG_PHASE_DRAW){ + Interruptible * action = game->mLayers->stackLayer()->getAt(-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()->getAt(-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 == Constants::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; + } +}; + + +//Soul Net +class ASoulNet:public ActivatedAbility{ + public: + PutInGraveyard * latest; + PutInGraveyard * newDead; + ASoulNet(int _id, MTGCardInstance * card):ActivatedAbility(_id, card,0,0,0){ + int _cost[] = {Constants::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, ManaCost * mana = NULL){ + newDead = ((PutInGraveyard *) GameObserver::GetInstance()->mLayers->stackLayer()->getPrevious(NULL,ACTION_PUTINGRAVEYARD,RESOLVED_OK)); + if (newDead && newDead != latest && newDead->card->isACreature()) + return ActivatedAbility::isReactingToClick(card,mana); + 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(Constants::MTG_COLOR_BLUE,1); + } + + void Update(float dt){ + //Upkeep Cost + if (newPhase !=currentPhase){ + if (newPhase == Constants::MTG_PHASE_UPKEEP){ + paidThisTurn = 0; + }else if (!paidThisTurn && newPhase > Constants::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(Constants::MTG_PHASE_UNTAP,game->players[i]); + } + + //Parent Class Method Call + ActivatedAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + return (!paidThisTurn && currentPhase == Constants::MTG_PHASE_UPKEEP && ActivatedAbility::isReactingToClick(card,mana)); + } + + int resolve(){ + paidThisTurn = 1; + return 1; + } + + int destroy(){ + for (int i = 0; i < 2; i++){ + game->phaseRing->addPhaseBefore(Constants::MTG_PHASE_UNTAP,game->players[i],Constants::MTG_PHASE_UPKEEP,game->players[i]); + } + return 1; + } +}; + + + +//--------------Addon Abra------------------ + +// Generic Karma +class ADamageForTypeControlled: public TriggeredAbility{ + public: + char type[20]; + ADamageForTypeControlled(int _id, MTGCardInstance * _source,const char * _type):TriggeredAbility(_id, _source){ + sprintf(type,"%s",_type); + } + + int trigger(){ + if (newPhase != currentPhase && newPhase == Constants::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(type)) totaldamage++;; + } + if (totaldamage) game->mLayers->stackLayer()->addDamage(source,game->currentPlayer, totaldamage); + return 1; + } +}; + +//ShieldOfTheAge +class AShieldOfTheAge: public TargetAbility{ + public: + AShieldOfTheAge(int _id, MTGCardInstance * card):TargetAbility(_id,card,NEW DamageTargetChooser(card,_id),NEW ManaCost(),0,0){ + cost->add(Constants::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 == Constants::MTG_PHASE_COMBATDAMAGE){ + nbOpponents = 0; + MTGCardInstance * opponent = source->getNextOpponent(); + while ((opponent && opponent->hasColor(Constants::MTG_COLOR_GREEN)) || opponent->hasColor(Constants::MTG_COLOR_WHITE)){ + opponents[nbOpponents] = opponent; + nbOpponents ++; + opponent = source->getNextOpponent(opponent); + } + }else if (newPhase == Constants::MTG_PHASE_COMBATEND){ + for (int i = 0; i < nbOpponents ; i++){ + game->mLayers->stackLayer()->addPutInGraveyard(opponents[i]); + } + } + } + } + + int testDestroy(){ + if(!game->isInPlay(source) && currentPhase != Constants::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 == Constants::MTG_PHASE_UNTAP){ + paidThisTurn = 0; + }else if( newPhase == Constants::MTG_PHASE_UPKEEP + 1 && !paidThisTurn){ + game->mLayers->stackLayer()->addDamage(source,source->controller(), 5); + source->tapped = 1; + } + } + TargetAbility::Update(dt); + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + if (currentPhase != Constants::MTG_PHASE_UPKEEP || paidThisTurn) return 0; + return TargetAbility::isReactingToClick(card,mana); + } + + 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; + } + +}; + + + + + +//Generic Kird Ape +class AKirdApe:public ListMaintainerAbility{ + public: + int power; + int toughness; + int ability; + int modifier; + int includeSelf; + AKirdApe(int _id, MTGCardInstance * _source, TargetChooser * _tc, int _includeSelf,int _power = 0, int _toughness = 0, int _ability=-1, int _abilityModifier = 1):ListMaintainerAbility(_id, _source){ + power = _power; + toughness = _toughness; + tc = _tc; + includeSelf = _includeSelf; + ability=_ability; + modifier = _abilityModifier; + if (!modifier) modifier = -1; + } + + int canBeInList(MTGCardInstance * card){ + if ((includeSelf || card!=source) && tc->canTarget(card)) return 1; + return 0; + } + + int added(MTGCardInstance * card){ + if (cards.size()== 1){ + source->power+=power; + source->addToToughness(toughness); + if (ability != -1) source->basicAbilities[ability] +=modifier; + return 1; + } + return 0; + } + + int removed(MTGCardInstance * card){ + + if (cards.size()== 0){ + source->power-=power; + source->addToToughness(-toughness); + if ((ability != -1) && source->basicAbilities[ability] >0 ) source->basicAbilities[ability] -=modifier; + return 1; + } + return 0; + } + + +}; + + +//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 == Constants::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/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 4fd24dc2c..ad882bf83 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -649,6 +649,37 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card){ continue; } + //Discard + found = s.find("discard:"); + if (found != string::npos){ + unsigned int start = s.find(":",found); + unsigned int end = s.find(" ",start); + int nbcards; + if (end != string::npos){ + nbcards = atoi(s.substr(start+1,end-start-1).c_str()); + }else{ + nbcards = atoi(s.substr(start+1).c_str()); + } + if (dryMode){ + dryModeResult = BAKA_EFFECT_BAD; + break; + } + if (trigger){ + //TODO ? + }else{ + if (tc){ + //TODO ? + }else{ + for (int i = 0; i < nbcards; i++){ + game->opponent()->game->discardRandom(game->opponent()->game->hand); + } + } + } + result++; + continue; + } + + //Change Power/Toughness int power, toughness; if ( parsePowerToughness(s,&power, &toughness)){ @@ -1642,10 +1673,18 @@ void AbilityFactory::addAbilities(int _id, Spell * spell){ game->addObserver(NEW ATargetterPowerToughnessModifierUntilEOT(id, card, 1,2, NEW ManaCost(cost,1),tc)); break; } +//---addon Tempest--- + case 4801: //Ancient Ruine + { + game->addObserver(NEW ADamageForTypeControlled(_id, card,"artifact")); + break; + } default: break; } + + /* Erwan - 2008/11/13: We want to get rid of these basicAbility things. * basicAbilities themselves are alright, but creating new object depending on them is dangerous * The main reason is that classes that add an ability to a card do NOT create these objects, and therefore do NOT