diff --git a/projects/mtg/bin/Res/sets/RV/_cards.dat b/projects/mtg/bin/Res/sets/RV/_cards.dat index a668f8444..1272e01a6 100644 --- a/projects/mtg/bin/Res/sets/RV/_cards.dat +++ b/projects/mtg/bin/Res/sets/RV/_cards.dat @@ -501,6 +501,7 @@ mana={W} text={B}{B}: Counter target green spell. id=1151 name=Deathgrip +auto={B}{B}:fizzle target(*[green]|stack) rarity=U type=Enchantment mana={B}{B} @@ -1251,6 +1252,7 @@ toughness=1 text={G}{G}: Counter target black spell. id=1256 name=Lifeforce +auto={G}{G}:fizzle target(*[black]|stack) rarity=U type=Enchantment mana={G}{G} diff --git a/projects/mtg/bin/Res/test/_tests.txt b/projects/mtg/bin/Res/test/_tests.txt index 15be1256c..f3d985765 100644 --- a/projects/mtg/bin/Res/test/_tests.txt +++ b/projects/mtg/bin/Res/test/_tests.txt @@ -13,6 +13,8 @@ generic/legendary.txt generic/lifelink.txt generic/persist.txt generic/persist2.txt +generic/rampage.txt +generic/regenerate.txt generic/sacrifice.txt generic/wither.txt ######################## @@ -22,6 +24,7 @@ afflict.txt akron_legionnaire.txt Amugaba.txt anarchy.txt +ancestors_chosen.txt animate_dead.txt animate_dead2.txt animate_dead3.txt @@ -57,6 +60,7 @@ counterspell3.txt counterspell4.txt creature_bond.txt dauthi_embrace.txt +death_ward.txt deja_vu.txt dingus_egg.txt doomed_necromancer.txt @@ -76,12 +80,14 @@ fountain_of_youth.txt ghost_warden.txt giant_growth.txt giant_growth2.txt +glimpse_the_unthinkable.txt goblin_balloon_brigade.txt goblin_balloon_brigade2.txt goblin_king.txt gravedigger.txt #hammerfist_giant.txt hannas_custody.txt +howl_of_the_night_pack.txt hymn_of_rebirth.txt icatian_priest.txt keldon_warlord.txt @@ -95,6 +101,8 @@ living_lands.txt lord_of_the_pit.txt lord_of_the_pit2.txt master_of_etherium.txt +millstone.txt +mind_rot.txt nantuko_husk.txt Nevinyrrals_Disk.txt Nevinyrrals_Disk2.txt @@ -118,8 +126,10 @@ siege_gang_commander.txt shivan_hellkite.txt shock.txt sphinx_summoner.txt +spitting_earth.txt spark_elemental.txt spirit_link.txt +spoils_of_evil.txt stasis.txt steelclad_serpent1.txt steelclad_serpent2.txt diff --git a/projects/mtg/bin/Res/test/ancestors_chosen.txt b/projects/mtg/bin/Res/test/ancestors_chosen.txt new file mode 100644 index 000000000..82d27ad8e --- /dev/null +++ b/projects/mtg/bin/Res/test/ancestors_chosen.txt @@ -0,0 +1,21 @@ +#Testing Ancestors chosen +[INIT] +FIRSTMAIN +[PLAYER1] +hand:Ancestor's chosen +graveyard:swamp,grizzly bears,dragon engine +manapool:{5}{W}{W} +[PLAYER2] +graveyard:black knight +[DO] +Ancestor's chosen +[ASSERT] +FIRSTMAIN +[PLAYER1] +inplay:Ancestor's chosen +life:23 +graveyard:swamp,grizzly bears,dragon engine +manapool:{0} +[PLAYER2] +graveyard:black knight +[END] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/death_ward.txt b/projects/mtg/bin/Res/test/death_ward.txt new file mode 100644 index 000000000..4195fefa7 --- /dev/null +++ b/projects/mtg/bin/Res/test/death_ward.txt @@ -0,0 +1,26 @@ +#Testing Regenerate (Death Ward) +[INIT] +COMBATATTACKERS +[PLAYER1] +hand:Death Ward +manapool:{W} +inplay:raging goblin +[PLAYER2] +inplay:grizzly bears +[DO] +Death Ward +raging goblin +raging goblin +next +grizzly bears +next +next +[ASSERT] +COMBATEND +[PLAYER1] +inplay:raging goblin +graveyard:Death Ward +manapool:{0} +[PLAYER2] +inplay:grizzly bears +[END] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/generic/rampage.txt b/projects/mtg/bin/Res/test/generic/rampage.txt new file mode 100644 index 000000000..cdc7c9148 --- /dev/null +++ b/projects/mtg/bin/Res/test/generic/rampage.txt @@ -0,0 +1,20 @@ +#Testing Rampage +[INIT] +COMBATATTACKERS +[PLAYER1] +inplay:Elvish Berserker +[PLAYER2] +inplay:raging goblin +[DO] +Elvish Berserker +next +raging goblin +next +next +[ASSERT] +COMBATEND +[PLAYER1] +inplay:Elvish Berserker +[PLAYER2] +graveyard:raging goblin +[END] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/generic/regenerate.txt b/projects/mtg/bin/Res/test/generic/regenerate.txt new file mode 100644 index 000000000..1405683a2 --- /dev/null +++ b/projects/mtg/bin/Res/test/generic/regenerate.txt @@ -0,0 +1,22 @@ +#Testing Regenerate +[INIT] +COMBATATTACKERS +[PLAYER1] +inplay:Drudge Skeletons,swamp +[PLAYER2] +inplay:raging goblin +[DO] +Drudge skeletons +swamp +Drudge skeletons +next +raging goblin +next +next +[ASSERT] +COMBATEND +[PLAYER1] +inplay:Drudge Skeletons,swamp +[PLAYER2] +graveyard:raging goblin +[END] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/glimpse_the_unthinkable.txt b/projects/mtg/bin/Res/test/glimpse_the_unthinkable.txt new file mode 100644 index 000000000..45244d464 --- /dev/null +++ b/projects/mtg/bin/Res/test/glimpse_the_unthinkable.txt @@ -0,0 +1,20 @@ +#Testing Deplete (sorcery +[INIT] +FIRSTMAIN +[PLAYER1] +hand:Glimpse the Unthinkable +manapool:{U}{B} +[PLAYER2] +library:swamp,plains,mountain,forest,island,bayou,plateau,white knight,black knight,grizzly bears,raging goblin +[DO] +Glimpse the Unthinkable +p2 +[ASSERT] +FIRSTMAIN +[PLAYER1] +graveyard:Glimpse the Unthinkable +manapool:{0} +[PLAYER2] +library:swamp +graveyard:plains,mountain,forest,island,bayou,plateau,white knight,black knight,grizzly bears,raging goblin +[END] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/howl_of_the_night_pack.txt b/projects/mtg/bin/Res/test/howl_of_the_night_pack.txt new file mode 100644 index 000000000..d79b05dae --- /dev/null +++ b/projects/mtg/bin/Res/test/howl_of_the_night_pack.txt @@ -0,0 +1,18 @@ +#Testing Howl of the night pack +[INIT] +FIRSTMAIN +[PLAYER1] +hand:153996 +inplay:1386,1387,1388 +manapool:{6}{G} +[PLAYER2] +[DO] +153996 +[ASSERT] +FIRSTMAIN +[PLAYER1] +inplay:1386,1387,1388,*,*,* +graveyard:153996 +manapool:{0} +[PLAYER2] +[END] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/millstone.txt b/projects/mtg/bin/Res/test/millstone.txt new file mode 100644 index 000000000..95a8c3943 --- /dev/null +++ b/projects/mtg/bin/Res/test/millstone.txt @@ -0,0 +1,20 @@ +#Testing Deplete +[INIT] +FIRSTMAIN +[PLAYER1] +inplay:Millstone +manapool:{2}} +[PLAYER2] +library:swamp,plains,mountain,forest,island,bayou,plateau,white knight,black knight,grizzly bears,raging goblin +[DO] +Millstone +p2 +[ASSERT] +FIRSTMAIN +[PLAYER1] +inplay:Millstone +manapool:{0} +[PLAYER2] +library:swamp,plains,mountain,forest,island,bayou,plateau,white knight,black knight +graveyard:grizzly bears,raging goblin +[END] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/mind_rot.txt b/projects/mtg/bin/Res/test/mind_rot.txt new file mode 100644 index 000000000..83ecee7cc --- /dev/null +++ b/projects/mtg/bin/Res/test/mind_rot.txt @@ -0,0 +1,20 @@ +#Testing Random discard +[INIT] +FIRSTMAIN +[PLAYER1] +hand:Mind Rot +manapool:{2}{B} +[PLAYER2] +hand:swamp,plains,mountain +[DO] +Mind Rot +p2 +[ASSERT] +FIRSTMAIN +[PLAYER1] +graveyard:Mind Rot +manapool:{0} +[PLAYER2] +hand:* +graveyard:*,* +[END] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/spitting_earth.txt b/projects/mtg/bin/Res/test/spitting_earth.txt new file mode 100644 index 000000000..5d081566f --- /dev/null +++ b/projects/mtg/bin/Res/test/spitting_earth.txt @@ -0,0 +1,22 @@ +#Testing Spitting Earth on Dragon engine +[INIT] +FIRSTMAIN +[PLAYER1] +hand:Spitting Earth +inplay:129652,129651,129650 +[PLAYER2] +inplay:Dragon Engine +[DO] +129652 +129651 +Spitting Earth +Dragon Engine +[ASSERT] +FIRSTMAIN +[PLAYER1] +inplay:129652,129651,129650 +graveyard:Spitting Earth +manapool:{0} +[PLAYER2] +graveyard:Dragon Engine +[END] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/spoils_of_evil.txt b/projects/mtg/bin/Res/test/spoils_of_evil.txt new file mode 100644 index 000000000..41d532f30 --- /dev/null +++ b/projects/mtg/bin/Res/test/spoils_of_evil.txt @@ -0,0 +1,20 @@ +#Testing Spoils of Evil +[INIT] +FIRSTMAIN +[PLAYER1] +hand:Spoils Of Evil +graveyard:black knight +manapool:{2}{B} +[PLAYER2] +graveyard:swamp,grizzly bears,dragon engine +[DO] +Spoils Of Evil +[ASSERT] +FIRSTMAIN +[PLAYER1] +graveyard:black knight,Spoils Of Evil +life:22 +manapool:{2} +[PLAYER2] +graveyard:swamp,grizzly bears,dragon engine +[END] \ No newline at end of file diff --git a/projects/mtg/include/ActionElement.h b/projects/mtg/include/ActionElement.h index edf49a6ce..0822dec48 100644 --- a/projects/mtg/include/ActionElement.h +++ b/projects/mtg/include/ActionElement.h @@ -22,10 +22,11 @@ class WEvent; class ActionElement: public JGuiObject{ protected: int activeState; - + public: + int isClone; TargetChooser * tc; int currentPhase; int newPhase; @@ -46,6 +47,7 @@ class ActionElement: public JGuiObject{ virtual int receiveEvent(WEvent * event){return 0;}; virtual int reactToClick(MTGCardInstance * card){return 0;}; virtual const char * getMenuText(){return "Ability";}; + virtual ActionElement * clone() const = 0; }; diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index a5743c473..258899dc4 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -20,10 +20,40 @@ #include using std::map; + + + +class AAFizzler:public ActivatedAbility{ + public: + AAFizzler(int _id, MTGCardInstance * card, Spell * _target, ManaCost * _cost = NULL, int _tap = 1):ActivatedAbility(_id, card,_cost,0,_tap){ + target = _target; + } + + int resolve(){ + Spell * _target = (Spell *) target; + game->mLayers->stackLayer()->Fizzle(_target); + return 1; + } + + const char * getMenuText(){ + return "Fizzle"; + } + + AAFizzler* clone() const{ + AAFizzler * a = NEW AAFizzler(*this); + a->isClone = 1; + return a; + } + +}; + + /* Generic classes */ + + //MayAbility: May do something when comes into play (should be extended) class MayAbility:public MTGAbility{ public: @@ -83,6 +113,12 @@ public: return MTGAbility::toString(out) << ")"; } + MayAbility * MayAbility::clone() const{ + MayAbility * a = NEW MayAbility(*this); + a->isClone = 1; + return a; + } + }; @@ -135,66 +171,150 @@ public: << " ("; return ActivatedAbility::toString(out) << ")"; } + + MultiAbility * MultiAbility::clone() const{ + MultiAbility * a = NEW MultiAbility(*this); + a->isClone = 1; + return a; + } +}; + + +//Generic Activated Ability + +class GenericActivatedAbility:public ActivatedAbility{ + public: + MTGAbility * ability; + int limitPerTurn; + int counters; + GenericActivatedAbility(int _id, MTGCardInstance * card, MTGAbility * a, ManaCost * _cost, int _tap = 1, int limit = 0):ActivatedAbility(_id, card,_cost,0,_tap),ability(a),limitPerTurn(limit){ + counters = 0; + } + + int resolve(){ + counters++; + if (ability) return ability->resolve(); + return 0; + } + + const char * getMenuText(){ + if (ability) return ability->getMenuText(); + return "Error"; + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + if (limitPerTurn && counters >= limitPerTurn) return 0; + return ActivatedAbility::isReactingToClick(card,mana); + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase ==Constants::MTG_PHASE_AFTER_EOT){ + counters = 0; + } + ActivatedAbility::Update(dt); + } + + GenericActivatedAbility * GenericActivatedAbility::clone() const{ + GenericActivatedAbility * a = NEW GenericActivatedAbility(*this); + a->isClone = 1; + return a; + } + + ~GenericActivatedAbility(){ + if (!isClone){ + SAFE_DELETE(ability); + } + } + +}; + +/* Generic TargetAbility */ +class GenericTargetAbility:public TargetAbility{ + +public: + int limitPerTurn; + int counters; + GenericTargetAbility(int _id, MTGCardInstance * _source, TargetChooser * _tc,MTGAbility * a, ManaCost * _cost = NULL, int _tap=0, int limit = 0):TargetAbility(_id,_source, _tc,_cost,0,_tap),limitPerTurn(limit){ + ability = a; + counters = 0; + } + + GenericTargetAbility * GenericTargetAbility::clone() const{ + GenericTargetAbility * a = NEW GenericTargetAbility(*this); + a->isClone = 1; + return a; + } + + int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL){ + if (limitPerTurn && counters >= limitPerTurn) return 0; + return TargetAbility::isReactingToClick(card,mana); + } + + void Update(float dt){ + if (newPhase != currentPhase && newPhase ==Constants::MTG_PHASE_AFTER_EOT){ + counters = 0; + } + TargetAbility::Update(dt); + } + + }; //Drawer, allows to draw a card for a cost: -class ADrawer:public ActivatedAbility{ +class AADrawer: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){ + AADrawer(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); + game->mLayers->stackLayer()->resolve(); return 1; } - - const char * getMenuText(){ return "Draw"; } - ~ADrawer(){ - OutputDebugString("Deleting ADrawer\n"); - } - - virtual ostream& toString(ostream& out) const - { - out << "ADrawer ::: nbcards : " << nbcards - << " ("; - return ActivatedAbility::toString(out) << ")"; + AADrawer * AADrawer::clone() const{ + AADrawer * a = NEW AADrawer(*this); + a->isClone = 1; + return a; } }; -// Gives/Takes Life to controller of source -class ALifeGiver:public ActivatedAbility{ +/*Gives life to target controller*/ +class AALifer: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){ + AALifer(int _id, MTGCardInstance * card, MTGCardInstance * _target, int life, ManaCost * _cost = NULL, int _tap = 1):ActivatedAbility(_id, card,_cost,0,_tap),life(life){ + target = _target; } int resolve(){ - source->controller()->life+=life; + MTGCardInstance * _target = (MTGCardInstance *) target; + _target->controller()->life+=life; return 1; } const char * getMenuText(){ - if (life < 0) return "Lose life"; - return "Gain life"; + return "Life"; } - virtual ostream& toString(ostream& out) const - { - out << "ALifeGiver ::: life : " << life - << " ("; - return ActivatedAbility::toString(out) << ")"; + AALifer * AALifer::clone() const{ + AALifer * a = NEW AALifer(*this); + a->isClone = 1; + return a; } + }; + + class ATokenCreator:public ActivatedAbility{ public: listabilities; @@ -202,10 +322,12 @@ public: 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){ + int multiplier; + ATokenCreator(int _id,MTGCardInstance * _source,ManaCost * _cost, string sname, string stypes,int _power,int _toughness, string sabilities, int _doTap, int _multiplier = 1):ActivatedAbility(_id,_source,_cost,0,_doTap){ power = _power; toughness = _toughness; name = sname; + multiplier = _multiplier; //TODO this is a copy/past of other code that's all around the place, everything should be in a dedicated parser class; @@ -239,23 +361,25 @@ public: } int resolve(){ - Token * myToken = NEW Token(name,source,power,toughness); - list::iterator it; - for ( it=types.begin() ; it != types.end(); it++ ){ - myToken->addType(*it); - } - for ( it=colors.begin() ; it != colors.end(); it++ ){ - myToken->setColor(*it); - } - for ( it=abilities.begin() ; it != abilities.end(); it++ ){ - myToken->basicAbilities[*it] = 1; - } - source->controller()->game->stack->addCard(myToken); - Spell * spell = NEW Spell(myToken); + for (int i = 0; i < multiplier; ++i){ + Token * myToken = NEW Token(name,source,power,toughness); + list::iterator it; + for ( it=types.begin() ; it != types.end(); it++ ){ + myToken->addType(*it); + } + for ( it=colors.begin() ; it != colors.end(); it++ ){ + myToken->setColor(*it); + } + 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; + spell->resolve(); + delete spell; + } return 1; } @@ -271,25 +395,29 @@ public: return ActivatedAbility::toString(out) << ")"; } -}; - -//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; + ATokenCreator * clone() const{ + ATokenCreator * a = NEW ATokenCreator(*this); + a->isClone = 1; + return a; } - static int moveTarget(MTGCardInstance * _target, string destinationZone, MTGCardInstance * source){ - GameObserver * g = GameObserver::GetInstance(); - if(_target){ +}; + +class AAMover:public ActivatedAbility{ +public: + string destination; + AAMover(int _id, MTGCardInstance * _source, MTGCardInstance * _target, string dest, ManaCost * _cost=NULL, int doTap=0):ActivatedAbility(_id,_source,_cost,0,doTap),destination(dest){ + if (_target) target = _target; + } + + int resolve(){ + MTGCardInstance * _target = (MTGCardInstance *) target; + if(target){ Player* p = _target->controller(); if (p){ + GameObserver * g = GameObserver::GetInstance(); MTGGameZone * fromZone = _target->getCurrentZone(); - MTGGameZone * destZone = MTGGameZone::stringToZone(destinationZone, source,_target); + MTGGameZone * destZone = MTGGameZone::stringToZone(destination, source,_target); //inplay is a special zone ! for (int i=0; i < 2; i++){ @@ -303,79 +431,35 @@ public: } } p->game->putInZone(_target,fromZone,destZone); + return 1; } - return 1; } return 0; - } - - int resolve(){ - MTGCardInstance * _target = tc->getNextCardTarget(); - return moveTarget(_target,destinationZone, source); } - virtual ostream& toString(ostream& out) const - { - out << "AZoneMover ::: destinationZone : " << destinationZone - << " ("; - return TargetAbility::toString(out) << ")"; + + const char * getMenuText(){ + return "Move"; + } + + + AAMover * AAMover::clone() const{ + AAMover * a = NEW AAMover(*this); + a->isClone = 1; + return a; } }; -//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; - } - virtual ostream& toString(ostream& out) const - { - out << "AZoneSelfMover ::: destinationZone : " << destinationZone - << " ("; - return ActivatedAbility::toString(out) << ")"; - } -}; - - -//Copier. TargetAbility -class ACopier:public TargetAbility{ +//Copier. ActivatedAbility +class AACopier:public ActivatedAbility{ public: - ACopier(int _id, MTGCardInstance * _source, TargetChooser * _tc = NULL, ManaCost * _cost=NULL):TargetAbility(_id,_source, _tc,_cost,0,0){ - if (!tc) tc = NEW CreatureTargetChooser(); + AACopier(int _id, MTGCardInstance * _source, MTGCardInstance * _target = NULL, ManaCost * _cost=NULL):ActivatedAbility(_id,_source,_cost,0,0){ + target = _target; } int resolve(){ - MTGCardInstance * _target = tc->getNextCardTarget(); + MTGCardInstance * _target = (MTGCardInstance *) target; if(_target){ source->copy(_target); return 1; @@ -386,53 +470,25 @@ class ACopier:public TargetAbility{ const char * getMenuText(){ return "Copy"; } - virtual ostream& toString(ostream& out) const - { - out << "ACopier ::: ("; - return TargetAbility::toString(out) << ")"; - } + + AACopier * AACopier::clone() const{ + AACopier * a = NEW AACopier(*this); + a->isClone = 1; + return a; + } }; -//All Destroyer. TargetAbility -class AAllDestroyer:public ActivatedAbility{ - public: +class AADestroyer: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; - - } + AADestroyer(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _bury = 0, ManaCost * _cost=NULL):ActivatedAbility(_id,_source,_cost),bury(_bury){ + if (_target) target = _target; + } int resolve(){ - AbilityFactory af; - af.destroyAllInPlay(tc,bury); - return 1; - } - - const char * getMenuText(){ - return "Destroy All..."; - } - - virtual ostream& toString(ostream& out) const - { - out << "AAllDestroyer ::: bury : " << bury - << " ("; - return ActivatedAbility::toString(out) << ")"; - } - -}; - -//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(); + MTGCardInstance * _target = (MTGCardInstance *) target; if(_target){ if (bury) return _target->bury(); else return _target->destroy(); @@ -444,30 +500,16 @@ class ADestroyer:public TargetAbility{ return "Destroy"; } - virtual ostream& toString(ostream& out) const - { - out << "ADestroyer ::: bury : " << bury - << " ("; - return TargetAbility::toString(out) << ")"; + + AADestroyer * AADestroyer::clone() const{ + AADestroyer * a = NEW AADestroyer(*this); + a->isClone = 1; + return a; } + + }; -//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"; - } - - virtual ostream& toString(ostream& out) const - { - out << "ABurier ::: ("; - return ADestroyer::toString(out) << ")"; - } -}; /*Changes one of the basic abilities of target @@ -482,9 +524,14 @@ class ABasicAbilityModifier:public MTGAbility{ 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){ + + } + + int addToGame(){ value_before_modification = ((MTGCardInstance * )target)->basicAbilities[ability]; ((MTGCardInstance * )target)->basicAbilities[ability]=modifier; - } + return MTGAbility::addToGame(); + } int destroy(){ if (((MTGCardInstance * )target)->basicAbilities[ability] == modifier){ @@ -504,6 +551,13 @@ class ABasicAbilityModifier:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + + ABasicAbilityModifier * ABasicAbilityModifier::clone() const{ + ABasicAbilityModifier * a = NEW ABasicAbilityModifier(*this); + a->isClone = 1; + return a; + } + }; //Modifies an ability until end of turn. Needs a target @@ -560,6 +614,12 @@ class ABasicAbilityModifierUntilEOT:public TargetAbility{ return TargetAbility::toString(out) << ")"; } + ABasicAbilityModifierUntilEOT * ABasicAbilityModifierUntilEOT::clone() const{ + ABasicAbilityModifierUntilEOT * a = NEW ABasicAbilityModifierUntilEOT(*this); + a->isClone = 1; + return a; + } + }; /*Instants that modifies a basic ability until end of turn */ @@ -567,10 +627,17 @@ 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){ + int value; + AInstantBasicAbilityModifierUntilEOT(int _id, MTGCardInstance * _source, MTGCardInstance * _target, int _ability, int value):InstantAbility(_id, _source, _target),ability(_ability),value(value){ + + } + + int addToGame(){ + MTGCardInstance * _target = (MTGCardInstance *) target; stateBeforeActivation = _target->basicAbilities[ability]; _target->basicAbilities[ability] = value; - } + return InstantAbility::addToGame(); + } int destroy(){ ((MTGCardInstance *)target)->basicAbilities[ability] = stateBeforeActivation; @@ -584,6 +651,12 @@ class AInstantBasicAbilityModifierUntilEOT: public InstantAbility{ return InstantAbility::toString(out) << ")"; } + AInstantBasicAbilityModifierUntilEOT * AInstantBasicAbilityModifierUntilEOT::clone() const{ + AInstantBasicAbilityModifierUntilEOT * a = NEW AInstantBasicAbilityModifierUntilEOT(*this); + a->isClone = 1; + return a; + } + }; //Alteration of Ability until of turn (Aura) @@ -625,6 +698,12 @@ class ABasicAbilityAuraModifierUntilEOT: public ActivatedAbility{ return ActivatedAbility::toString(out) << ")"; } + ABasicAbilityAuraModifierUntilEOT * ABasicAbilityAuraModifierUntilEOT::clone() const{ + ABasicAbilityAuraModifierUntilEOT * a = NEW ABasicAbilityAuraModifierUntilEOT(*this); + a->isClone = 1; + return a; + } + }; @@ -678,6 +757,12 @@ class ASpellCastLife:public MTGAbility{ return MTGAbility::toString(out) << ")"; } + ASpellCastLife * ASpellCastLife::clone() const{ + ASpellCastLife * a = NEW ASpellCastLife(*this); + a->isClone = 1; + return a; + } + }; //Allows to untap at any moment for an amount of mana @@ -711,6 +796,12 @@ class AUnBlocker:public MTGAbility{ return MTGAbility::toString(out) << ")"; } + AUnBlocker * AUnBlocker::clone() const{ + AUnBlocker * a = NEW AUnBlocker(*this); + a->isClone = 1; + return a; + } + }; //Allows to untap target card once per turn for a manaCost @@ -747,6 +838,12 @@ class AUntaperOnceDuringTurn:public AUnBlocker{ return AUnBlocker::toString(out) << ")"; } + AUntaperOnceDuringTurn * AUntaperOnceDuringTurn::clone() const{ + AUntaperOnceDuringTurn * a = NEW AUntaperOnceDuringTurn(*this); + a->isClone = 1; + return a; + } + }; //Alteration of Power and Toughness (enchantments) @@ -754,9 +851,15 @@ 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){ + + } + + int addToGame(){ + MTGCardInstance * _target = (MTGCardInstance *)target; _target->power += power; _target->addToToughness(toughness); - } + return MTGAbility::addToGame(); + } int destroy(){ ((MTGCardInstance *)target)->power -= power; @@ -770,6 +873,16 @@ class APowerToughnessModifier: public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + APowerToughnessModifier * APowerToughnessModifier::clone() const{ + APowerToughnessModifier * a = NEW APowerToughnessModifier(*this); + a->isClone = 1; + return a; + } + + ~APowerToughnessModifier(){ + OutputDebugString ("DELETING POWERTOUGHNESS"); + } + }; // Permanent life alteration evry turn of the target's controller. Useful only for unstable mutation currently @@ -794,7 +907,11 @@ class APowerToughnessModifierRegularCounter:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } - + APowerToughnessModifierRegularCounter * APowerToughnessModifierRegularCounter::clone() const{ + APowerToughnessModifierRegularCounter * a = NEW APowerToughnessModifierRegularCounter(*this); + a->isClone = 1; + return a; + } }; @@ -847,7 +964,11 @@ class ATargetterPowerToughnessModifierUntilEOT: public TargetAbility{ << " ("; return TargetAbility::toString(out) << ")"; } - + ATargetterPowerToughnessModifierUntilEOT * ATargetterPowerToughnessModifierUntilEOT::clone() const{ + ATargetterPowerToughnessModifierUntilEOT * a = NEW ATargetterPowerToughnessModifierUntilEOT(*this); + a->isClone = 1; + return a; + } }; @@ -858,7 +979,7 @@ class APowerToughnessModifierUntilEndOfTurn: public ActivatedAbility{ 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){ + APowerToughnessModifierUntilEndOfTurn(int id, MTGCardInstance * _source, MTGCardInstance * _target, int _power, int _toughness, ManaCost * _cost = NULL, int _maxcounters = 0):ActivatedAbility(id,_source,_cost,0,0),power(_power),toughness(_toughness),maxcounters(_maxcounters){ counters = 0; target=_target; } @@ -898,6 +1019,11 @@ class APowerToughnessModifierUntilEndOfTurn: public ActivatedAbility{ << " ("; return ActivatedAbility::toString(out) << ")"; } + APowerToughnessModifierUntilEndOfTurn * APowerToughnessModifierUntilEndOfTurn::clone() const{ + APowerToughnessModifierUntilEndOfTurn * a = NEW APowerToughnessModifierUntilEndOfTurn(*this); + a->isClone = 1; + return a; + } }; @@ -927,6 +1053,11 @@ class AInstantPowerToughnessModifierUntilEOT: public InstantAbility{ << " ("; return InstantAbility::toString(out) << ")"; } + AInstantPowerToughnessModifierUntilEOT * AInstantPowerToughnessModifierUntilEOT::clone() const{ + AInstantPowerToughnessModifierUntilEOT * a = NEW AInstantPowerToughnessModifierUntilEOT(*this); + a->isClone = 1; + return a; + } }; @@ -943,30 +1074,11 @@ class AUntapManaBlocker: public UntapBlocker{ out << "AUntapManaBlocker ::: ("; return UntapBlocker::toString(out) << ")"; } -}; - -/* 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){ + AUntapManaBlocker * AUntapManaBlocker::clone() const{ + AUntapManaBlocker * a = NEW AUntapManaBlocker(*this); + a->isClone = 1; + return a; } - - int resolve(){ - Spell * _target = tc->getNextSpellTarget(); - if(_target){ - game->mLayers->stackLayer()->Fizzle(_target); - return 1; - } - return 0; - } - virtual ostream& toString(ostream& out) const - { - out << "ASpellCounterEnchantment ::: ("; - return TargetAbility::toString(out) << ")"; - } - }; @@ -1018,12 +1130,18 @@ protected: out << "ACircleOfProtection ::: ("; return TargetAbility::toString(out) << ")"; } + ACircleOfProtection * ACircleOfProtection::clone() const{ + ACircleOfProtection * a = NEW ACircleOfProtection(*this); + a->isClone = 1; + return a; + } }; + //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){ + AStandardRegenerate(int _id, MTGCardInstance * _source, MTGCardInstance * _target, ManaCost * _cost = NULL):ActivatedAbility(_id,_source,_cost,0,0){ target = _target; aType = MTGAbility::STANDARD_REGENERATE; } @@ -1043,6 +1161,11 @@ class AStandardRegenerate:public ActivatedAbility{ out << "AStandardRegenerate ::: ("; return ActivatedAbility::toString(out) << ")"; } + AStandardRegenerate * AStandardRegenerate::clone() const{ + AStandardRegenerate * a = NEW AStandardRegenerate(*this); + a->isClone = 1; + return a; + } }; /*Gives protection to a target */ @@ -1077,6 +1200,11 @@ class AProtectionFrom:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + AProtectionFrom * AProtectionFrom::clone() const{ + AProtectionFrom * a = NEW AProtectionFrom(*this); + a->isClone = 1; + return a; + } }; //Aura Enchantments that provide controller of target life or damages at a given phase of their turn @@ -1107,6 +1235,11 @@ class ARegularLifeModifierAura:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + ARegularLifeModifierAura * ARegularLifeModifierAura::clone() const{ + ARegularLifeModifierAura * a = NEW ARegularLifeModifierAura(*this); + a->isClone = 1; + return a; + } }; @@ -1156,6 +1289,11 @@ class AExalted:public ListMaintainerAbility{ << " ("; return ListMaintainerAbility::toString(out) << ")"; } + AExalted * AExalted::clone() const{ + AExalted * a = NEW AExalted(*this); + a->isClone = 1; + return a; + } }; @@ -1200,6 +1338,11 @@ class AExaltedAbility:public ListMaintainerAbility{ << " ("; return ListMaintainerAbility::toString(out) << ")"; } + AExaltedAbility * AExaltedAbility::clone() const{ + AExaltedAbility * a = NEW AExaltedAbility(*this); + a->isClone = 1; + return a; + } }; @@ -1238,27 +1381,88 @@ class AConvertLandToCreatures:public ListMaintainerAbility{ << " ("; return ListMaintainerAbility::toString(out) << ")"; } + AConvertLandToCreatures * AConvertLandToCreatures::clone() const{ + AConvertLandToCreatures * a = NEW AConvertLandToCreatures(*this); + a->isClone = 1; + return a; + } +}; + +//Generic Kird Ape +class AAsLongAs:public ListMaintainerAbility{ + public: + MTGAbility * ability; + MTGAbility * a; + int includeSelf; + AAsLongAs(int _id, MTGCardInstance * _source, TargetChooser * _tc, int _includeSelf, MTGAbility * a):ListMaintainerAbility(_id, _source),ability(a){ + tc = _tc; + includeSelf = _includeSelf; + tc->targetter = NULL; + ability->source = source; + ability->target = target; + a = NULL; + } + + int canBeInList(MTGCardInstance * card){ + if ((includeSelf || card!=source) && tc->canTarget(card)) return 1; + return 0; + } + + int resolve(){ + //TODO check if ability is oneShot ? + updateTargets(); + cards.clear(); + players.clear(); + return 1; + } + + + int added(MTGCardInstance * card){ + if (cards.size()== 1){ + a = ability->clone(); + a->addToGame(); + return 1; + } + return 0; + } + + int removed(MTGCardInstance * card){ + + if (cards.size()== 0){ + game->removeObserver(a); + a = NULL; + return 1; + } + return 0; + } + + ~AAsLongAs(){ + if (!isClone) SAFE_DELETE(ability); + } + + + AAsLongAs * AAsLongAs::clone() const{ + AAsLongAs * a = NEW AAsLongAs(*this); + a->isClone = 1; + return a; + } }; //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; + MTGAbility * ability; 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){ + map abilities; + ALord(int _id, MTGCardInstance * card, TargetChooser * _tc, int _includeSelf, MTGAbility * a):ListMaintainerAbility(_id,card), ability(a){ tc = _tc; tc->targetter = NULL; includeSelf = _includeSelf; - power = _power; - toughness = _toughness; - ability = _ability; - regenCost = _regenCost; - modifier = _modifier; - if (!modifier) modifier = -1; + } + + int canBeInList(Player *p){ + if (tc->canTarget(p)) return 1; + return 0; } int canBeInList(MTGCardInstance * card){ @@ -1266,79 +1470,69 @@ class ALord:public ListMaintainerAbility{ 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); - } + int resolve(){ + //TODO check if ability is oneShot ? + updateTargets(); + cards.clear(); + players.clear(); return 1; } + + int _added(Damageable * d){ + MTGAbility * a = ability->clone(); + a->target = d; + if (a->oneShot){ + a->resolve(); + delete(a); + }else{ + if (d->type_as_damageable == DAMAGEABLE_MTGCARDINSTANCE){ + a->source = (MTGCardInstance *)d; + } + a->addToGame(); + abilities[d] = a; + } + return 1; + } + + int added(MTGCardInstance * card){ + return _added(card); + } + + int added(Player * p){ + return _added(p); + } 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); - } + if(abilities.find(card) != abilities.end()){ + game->removeObserver(abilities[card]); + abilities.erase(card); } return 1; } ~ALord(){ - SAFE_DELETE(regenCost); + if (!isClone) SAFE_DELETE(ability); } - virtual ostream& toString(ostream& out) const - { - out << "ALord ::: power : " << power - << " ; toughness : " << toughness - << " ; ability : " << ability - << " ; modifier : " << modifier - << " ; regenCost : " << regenCost - << " ; includeSelf : " << includeSelf - << " ("; - return ListMaintainerAbility::toString(out) << ")"; + ALord * ALord::clone() const{ + ALord * a = NEW ALord(*this); + a->isClone = 1; + return a; } }; -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; - } - virtual ostream& toString(ostream& out) const - { - out << "ALordUEOT ::: ("; - return ALord::toString(out) << ")"; - } -}; - //Foreach (plague rats...) class AForeach:public ListMaintainerAbility{ public: - int power, toughness; + MTGAbility * ability; int includeSelf; - AForeach(int _id, MTGCardInstance * card,MTGCardInstance * _target, TargetChooser * _tc, int _includeSelf, int _power = 0 , int _toughness = 0):ListMaintainerAbility(_id,card,_target){ + map abilities; + AForeach(int _id, MTGCardInstance * card,MTGCardInstance * _target, TargetChooser * _tc, int _includeSelf, MTGAbility * a):ListMaintainerAbility(_id,card,_target), ability(a){ tc = _tc; tc->targetter = NULL; includeSelf = _includeSelf; - power = _power; - toughness = _toughness; - if (!target) target = source; //Is this needed ? + ability->target = _target; } int canBeInList(MTGCardInstance * card){ @@ -1347,94 +1541,105 @@ class AForeach:public ListMaintainerAbility{ } int added(MTGCardInstance * card){ - MTGCardInstance * _target = (MTGCardInstance *)target; - _target->power += power; - _target->addToToughness(toughness); - return 1; + MTGAbility * a = ability->clone(); + if (a->oneShot){ + a->resolve(); + delete(a); + }else{ + a->addToGame(); + abilities[card] = a; + } + return 1; } int removed(MTGCardInstance * card){ - MTGCardInstance * _target = (MTGCardInstance *)target; - _target->power -= power; - _target->addToToughness(-toughness); - return 1; + if(abilities.find(card) != abilities.end()){ + game->removeObserver(abilities[card]); + abilities.erase(card); + return 1; + } + return 0; } - virtual ostream& toString(ostream& out) const - { - out << "AForeach ::: power : " << power - << " ; toughness : " << toughness - << " ; includeSelf : " << includeSelf - << " ("; - return ListMaintainerAbility::toString(out) << ")"; - } - -}; - -//Damage all.... ActivatedAbility -class AAllDamager:public ActivatedAbility{ - public: - int damage; - AAllDamager(int _id, MTGCardInstance * _source, ManaCost * _cost, int _damage, TargetChooser * _tc ,int doTap =1):ActivatedAbility(_id,_source,_cost,0,doTap),damage(_damage){ - tc = _tc; - + AForeach * AForeach::clone() const{ + AForeach * a = NEW AForeach(*this); + a->isClone = 1; + return a; } int resolve(){ - AbilityFactory af; - af.damageAll(tc,damage); + //TODO check if ability is oneShot ? + updateTargets(); + cards.clear(); + players.clear(); return 1; } + - const char * getMenuText(){ - return "Damage All..."; - } - - virtual ostream& toString(ostream& out) const - { - out << "AAllDamager ::: damage : " << damage - << " ("; - return ActivatedAbility::toString(out) << ")"; + ~AForeach(){ + if (!isClone) SAFE_DELETE(ability); } }; +class AADamager:public ActivatedAbility{ +public: + int damage; +AADamager(int _id, MTGCardInstance * _source, Damageable * _target, int _damage = 0, ManaCost * _cost=NULL):ActivatedAbility(_id,_source,_cost),damage(_damage){ + if (_target) target = _target; + aType = MTGAbility::DAMAGER; + } + + int resolve(){ + if(target){ + Damageable * _target = (Damageable *)target; + game->mLayers->stackLayer()->addDamage(source,_target, damage); + game->mLayers->stackLayer()->resolve(); + return 1; + } + return 0; + } + + const char * getMenuText(){ + return "Damage"; + } + + + AADamager * AADamager::clone() const{ + AADamager * a = NEW AADamager(*this); + a->isClone = 1; + return a; + } + + +}; + /* Standard Damager, can choose a NEW target each time the price is paid */ -class ADamager:public TargetAbility{ +class TADamager: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){ + TADamager(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; + ability = NEW AADamager(id,card,NULL,damage); } - const char * getMenuText(){ - return "Damage target"; - } - - virtual ostream& toString(ostream& out) const - { - out << "ADamager ::: damage : " << damage - << " ("; - return TargetAbility::toString(out) << ")"; + TADamager * TADamager::clone() const{ + TADamager * a = NEW TADamager(*this); + a->isClone = 1; + return a; } }; /* Can tap a target for a cost */ -class ATapper:public TargetAbility{ +class AATapper:public ActivatedAbility{ public: - int damage; - ATapper(int id, MTGCardInstance * card, ManaCost * _cost, TargetChooser * _chooser):TargetAbility(id,card, _chooser, _cost){ + AATapper(int id, MTGCardInstance * card, MTGCardInstance * _target,ManaCost * _cost = NULL, int doTap = 0):ActivatedAbility(id,card, _cost,0,doTap){ + target = _target; } int resolve(){ - MTGCardInstance * _target = tc->getNextCardTarget(); + MTGCardInstance * _target = (MTGCardInstance *) target; if (_target){ _target->tap(); } @@ -1445,39 +1650,41 @@ class ATapper:public TargetAbility{ return "Tap target"; } - virtual ostream& toString(ostream& out) const - { - out << "ATapper ::: damage : " << damage - << " ("; - return TargetAbility::toString(out) << ")"; + AATapper * AATapper::clone() const{ + AATapper * a = NEW AATapper(*this); + a->isClone = 1; + return a; } }; -//Ability to untap a target -class AUntaper:public TargetAbility{ + +/* Can untap a target for a cost */ +class AAUntapper:public ActivatedAbility{ public: - AUntaper(int _id, MTGCardInstance * card, ManaCost * _manacost, TargetChooser * _tc):TargetAbility(_id,card,_tc,_manacost){ + AAUntapper(int id, MTGCardInstance * card, MTGCardInstance * _target,ManaCost * _cost = NULL, int doTap = 0):ActivatedAbility(id,card, _cost,0,doTap){ + target = _target; } int resolve(){ - MTGCardInstance * _target = tc->getNextCardTarget(); + MTGCardInstance * _target = (MTGCardInstance *) target; if (_target){ - _target->untap(); + _target->tap(); } return 1; } const char * getMenuText(){ - return "Untap target"; + return "untap target"; } - virtual ostream& toString(ostream& out) const - { - out << "AUntaper ::: ("; - return TargetAbility::toString(out) << ")"; + AAUntapper * clone() const{ + AAUntapper * a = NEW AAUntapper(*this); + a->isClone = 1; + return a; } }; + // 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{ @@ -1528,6 +1735,11 @@ class ALifeZoneLink:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + ALifeZoneLink * ALifeZoneLink::clone() const{ + ALifeZoneLink * a = NEW ALifeZoneLink(*this); + a->isClone = 1; + return a; + } }; //Creatures that cannot attack if opponent has not a given type of land, and die if controller has not this type of land @@ -1558,6 +1770,11 @@ class AStrongLandLinkCreature: public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + AStrongLandLinkCreature * AStrongLandLinkCreature::clone() const{ + AStrongLandLinkCreature * a = NEW AStrongLandLinkCreature(*this); + a->isClone = 1; + return a; + } }; //Steal control of a target @@ -1586,6 +1803,11 @@ class AControlStealAura: public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + AControlStealAura * AControlStealAura::clone() const{ + AControlStealAura * a = NEW AControlStealAura(*this); + a->isClone = 1; + return a; + } }; //Creatures that kill their blockers @@ -1631,6 +1853,11 @@ class AOldSchoolDeathtouch:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + AOldSchoolDeathtouch * AOldSchoolDeathtouch::clone() const{ + AOldSchoolDeathtouch * a = NEW AOldSchoolDeathtouch(*this); + a->isClone = 1; + return a; + } }; //Converts a card to a creature (Aura) @@ -1656,6 +1883,11 @@ class AConvertToCreatureAura:public MTGAbility{ out << "AConvertToCreatureAura ::: ("; return MTGAbility::toString(out) << ")"; } + AConvertToCreatureAura * AConvertToCreatureAura::clone() const{ + AConvertToCreatureAura * a = NEW AConvertToCreatureAura(*this); + a->isClone = 1; + return a; + } }; /* @@ -1725,6 +1957,11 @@ class AAladdinsLamp: public TargetAbility{ << " ("; return TargetAbility::toString(out) << ")"; } + AAladdinsLamp * AAladdinsLamp::clone() const{ + AAladdinsLamp * a = NEW AAladdinsLamp(*this); + a->isClone = 1; + return a; + } }; @@ -1764,6 +2001,11 @@ class AAnkhOfMishra: public ListMaintainerAbility{ << " ("; return ListMaintainerAbility::toString(out) << ")"; } + AAnkhOfMishra * AAnkhOfMishra::clone() const{ + AAnkhOfMishra * a = NEW AAnkhOfMishra(*this); + a->isClone = 1; + return a; + } }; @@ -1812,6 +2054,11 @@ class AArmageddonClock:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + AArmageddonClock * AArmageddonClock::clone() const{ + AArmageddonClock * a = NEW AArmageddonClock(*this); + a->isClone = 1; + return a; + } }; //Channel @@ -1846,6 +2093,11 @@ class AChannel:public ActivatedAbility{ out << "AChannel ::: ("; return ActivatedAbility::toString(out) << ")"; } + AChannel * AChannel::clone() const{ + AChannel * a = NEW AChannel(*this); + a->isClone = 1; + return a; + } }; @@ -1894,6 +2146,11 @@ class AClockworkBeast:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + AClockworkBeast * AClockworkBeast::clone() const{ + AClockworkBeast * a = NEW AClockworkBeast(*this); + a->isClone = 1; + return a; + } }; //1102: Conservator @@ -1968,6 +2225,11 @@ class AConservator: public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + AConservator * AConservator::clone() const{ + AConservator * a = NEW AConservator(*this); + a->isClone = 1; + return a; + } }; @@ -2003,6 +2265,11 @@ class ACreatureBond:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + ACreatureBond * ACreatureBond::clone() const{ + ACreatureBond * a = NEW ACreatureBond(*this); + a->isClone = 1; + return a; + } }; //1105: Dingus Egg @@ -2030,6 +2297,11 @@ class ADingusEgg: public ListMaintainerAbility{ out << "ADingusEgg ::: ("; return ListMaintainerAbility::toString(out) << ")"; } + ADingusEgg * ADingusEgg::clone() const{ + ADingusEgg * a = NEW ADingusEgg(*this); + a->isClone = 1; + return a; + } }; @@ -2067,6 +2339,11 @@ class ADisruptingScepter:public TargetAbility{ out << "ADisruptingScepter ::: ("; return TargetAbility::toString(out) << ")"; } + ADisruptingScepter * ADisruptingScepter::clone() const{ + ADisruptingScepter * a = NEW ADisruptingScepter(*this); + a->isClone = 1; + return a; + } }; @@ -2089,6 +2366,11 @@ class AEbonyHorse:public TargetAbility{ out << "AEbonyHorse ::: ("; return TargetAbility::toString(out) << ")"; } + AEbonyHorse * AEbonyHorse::clone() const{ + AEbonyHorse * a = NEW AEbonyHorse(*this); + a->isClone = 1; + return a; + } }; //1345 Farmstead @@ -2128,6 +2410,11 @@ class AFarmstead:public ActivatedAbility{ << " ("; return ActivatedAbility::toString(out) << ")"; } + AFarmstead * AFarmstead::clone() const{ + AFarmstead * a = NEW AFarmstead(*this); + a->isClone = 1; + return a; + } }; //1110 Glasses of Urza @@ -2185,6 +2472,11 @@ class AGlassesOfUrza:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + AGlassesOfUrza * AGlassesOfUrza::clone() const{ + AGlassesOfUrza * a = NEW AGlassesOfUrza(*this); + a->isClone = 1; + return a; + } }; //1112 Howling Mine @@ -2203,6 +2495,11 @@ class AHowlingMine:public MTGAbility{ out << "AHowlingMine ::: ("; return MTGAbility::toString(out) << ")"; } + AHowlingMine * AHowlingMine::clone() const{ + AHowlingMine * a = NEW AHowlingMine(*this); + a->isClone = 1; + return a; + } }; @@ -2252,6 +2549,11 @@ class ALivingArtifact:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + ALivingArtifact * ALivingArtifact::clone() const{ + ALivingArtifact * a = NEW ALivingArtifact(*this); + a->isClone = 1; + return a; + } }; //Lord of the Pit @@ -2294,6 +2596,11 @@ class ALordOfThePit: public TargetAbility{ << " ("; return TargetAbility::toString(out) << ")"; } + ALordOfThePit * ALordOfThePit::clone() const{ + ALordOfThePit * a = NEW ALordOfThePit(*this); + a->isClone = 1; + return a; + } }; //1143 Animate Dead class AAnimateDead:public MTGAbility{ @@ -2327,6 +2634,11 @@ class AAnimateDead:public MTGAbility{ out << "AAnimateDead ::: ("; return MTGAbility::toString(out) << ")"; } + AAnimateDead * AAnimateDead::clone() const{ + AAnimateDead * a = NEW AAnimateDead(*this); + a->isClone = 1; + return a; + } }; @@ -2365,6 +2677,11 @@ class AErgRaiders:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + AErgRaiders * AErgRaiders::clone() const{ + AErgRaiders * a = NEW AErgRaiders(*this); + a->isClone = 1; + return a; + } }; //Fastbond @@ -2407,6 +2724,11 @@ class AFastbond:public TriggeredAbility{ << " ("; return TriggeredAbility::toString(out) << ")"; } + AFastbond * AFastbond::clone() const{ + AFastbond * a = NEW AFastbond(*this); + a->isClone = 1; + return a; + } }; @@ -2460,6 +2782,11 @@ class AHypnoticSpecter:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + AHypnoticSpecter * AHypnoticSpecter::clone() const{ + AHypnoticSpecter * a = NEW AHypnoticSpecter(*this); + a->isClone = 1; + return a; + } }; //1117 Jandor's Ring @@ -2485,6 +2812,11 @@ class AJandorsRing:public ActivatedAbility{ out << "AJandorsRing ::: ("; return ActivatedAbility::toString(out) << ")"; } + AJandorsRing * AJandorsRing::clone() const{ + AJandorsRing * a = NEW AJandorsRing(*this); + a->isClone = 1; + return a; + } }; @@ -2559,6 +2891,11 @@ class AKudzu: public TargetAbility{ << " ("; return TargetAbility::toString(out) << ")"; } + AKudzu * AKudzu::clone() const{ + AKudzu * a = NEW AKudzu(*this); + a->isClone = 1; + return a; + } }; //1172 Pestilence @@ -2592,6 +2929,11 @@ class APestilence: public ActivatedAbility{ out << "APestilence ::: ("; return ActivatedAbility::toString(out) << ")"; } + APestilence * APestilence::clone() const{ + APestilence * a = NEW APestilence(*this); + a->isClone = 1; + return a; + } }; @@ -2648,6 +2990,11 @@ class APowerLeak:public TriggeredAbility{ << " ("; return TriggeredAbility::toString(out) << ")"; } + APowerLeak * APowerLeak::clone() const{ + APowerLeak * a = NEW APowerLeak(*this); + a->isClone = 1; + return a; + } }; //Power Surge @@ -2688,6 +3035,11 @@ class APowerSurge:public TriggeredAbility{ << " ("; return TriggeredAbility::toString(out) << ")"; } + APowerSurge * APowerSurge::clone() const{ + APowerSurge * a = NEW APowerSurge(*this); + a->isClone = 1; + return a; + } }; @@ -2714,6 +3066,11 @@ class ASacrifice:public InstantAbility{ out << "ASacrifice ::: ("; return InstantAbility::toString(out) << ")"; } + ASacrifice * ASacrifice::clone() const{ + ASacrifice * a = NEW ASacrifice(*this); + a->isClone = 1; + return a; + } }; //1178 Scavenging Ghoul @@ -2749,6 +3106,11 @@ class AScavengingGhoul:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + AScavengingGhoul * AScavengingGhoul::clone() const{ + AScavengingGhoul * a = NEW AScavengingGhoul(*this); + a->isClone = 1; + return a; + } }; //1218 Psychic Venom @@ -2774,6 +3136,11 @@ class APsychicVenom:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + APsychicVenom * APsychicVenom::clone() const{ + APsychicVenom * a = NEW APsychicVenom(*this); + a->isClone = 1; + return a; + } }; @@ -2794,6 +3161,11 @@ class ASerendibEfreet:public MTGAbility{ out << "ASerendibEfreet ::: ("; return MTGAbility::toString(out) << ")"; } + ASerendibEfreet * ASerendibEfreet::clone() const{ + ASerendibEfreet * a = NEW ASerendibEfreet(*this); + a->isClone = 1; + return a; + } }; @@ -2838,6 +3210,11 @@ class AAspectOfWolf:public ListMaintainerAbility{ << " ("; return ListMaintainerAbility::toString(out) << ")"; } + AAspectOfWolf * AAspectOfWolf::clone() const{ + AAspectOfWolf * a = NEW AAspectOfWolf(*this); + a->isClone = 1; + return a; + } }; //1276 Wanderlust, 1148 Cursed Lands @@ -2862,6 +3239,11 @@ class AWanderlust:public TriggeredAbility{ out << "AWanderlust ::: ("; return TriggeredAbility::toString(out) << ")"; } + AWanderlust * AWanderlust::clone() const{ + AWanderlust * a = NEW AWanderlust(*this); + a->isClone = 1; + return a; + } }; @@ -2884,13 +3266,21 @@ class ADragonWhelp: public APowerToughnessModifierUntilEndOfTurn{ out << "ADragonWhelp ::: ("; return APowerToughnessModifierUntilEndOfTurn::toString(out) << ")"; } + ADragonWhelp * ADragonWhelp::clone() const{ + ADragonWhelp * a = NEW ADragonWhelp(*this); + a->isClone = 1; + return a; + } }; //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); + if (value_before_modification){ + Damageable * _target = (Damageable *)target; + game->mLayers->stackLayer()->addDamage(source,_target,2); + } } virtual ostream& toString(ostream& out) const @@ -2898,6 +3288,11 @@ class AEarthbind:public ABasicAbilityModifier{ out << "AEarthbind ::: ("; return ABasicAbilityModifier::toString(out) << ")"; } + AEarthbind * AEarthbind::clone() const{ + AEarthbind * a = NEW AEarthbind(*this); + a->isClone = 1; + return a; + } }; //1291 Fireball @@ -2919,6 +3314,11 @@ class AFireball:public InstantAbility{ out << "AFireball ::: ("; return InstantAbility::toString(out) << ")"; } + AFireball * AFireball::clone() const{ + AFireball * a = NEW AFireball(*this); + a->isClone = 1; + return a; + } }; //1245 ForceOfNature @@ -2956,27 +3356,33 @@ class AForceOfNature:public ActivatedAbility{ << " ("; return ActivatedAbility::toString(out) << ")"; } + AForceOfNature * AForceOfNature::clone() const{ + AForceOfNature * a = NEW AForceOfNature(*this); + a->isClone = 1; + return a; + } }; //1309 Orcish Artilery -class AOrcishArtillery: public ADamager{ +class AOrcishArtillery: public TADamager{ public: - AOrcishArtillery(int _id,MTGCardInstance * card): ADamager(_id, card, NEW ManaCost(), 2){ + AOrcishArtillery(int _id,MTGCardInstance * card): TADamager(_id, card, NEW ManaCost(), 2){ } int resolve(){ - ADamager::resolve(); + TADamager::resolve(); game->mLayers->stackLayer()->addDamage(source,source->controller(), 3); return 1; } - virtual ostream& toString(ostream& out) const - { - out << "AOrcishArtillery ::: ("; - return ADamager::toString(out) << ")"; + + AOrcishArtillery * AOrcishArtillery::clone() const{ + AOrcishArtillery * a = NEW AOrcishArtillery(*this); + a->isClone = 1; + return a; } }; @@ -3023,6 +3429,11 @@ class AIslandSanctuary:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + AIslandSanctuary * AIslandSanctuary::clone() const{ + AIslandSanctuary * a = NEW AIslandSanctuary(*this); + a->isClone = 1; + return a; + } }; @@ -3057,6 +3468,11 @@ class ASoulNet:public ActivatedAbility{ << " ("; return ActivatedAbility::toString(out) << ")"; } + ASoulNet * ASoulNet::clone() const{ + ASoulNet * a = NEW ASoulNet(*this); + a->isClone = 1; + return a; + } }; @@ -3110,6 +3526,11 @@ class AStasis:public ActivatedAbility{ << " ("; return ActivatedAbility::toString(out) << ")"; } + AStasis * AStasis::clone() const{ + AStasis * a = NEW AStasis(*this); + a->isClone = 1; + return a; + } }; @@ -3150,6 +3571,11 @@ class ABasilik:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + ABasilik * ABasilik::clone() const{ + ABasilik * a = NEW ABasilik(*this); + a->isClone = 1; + return a; + } }; @@ -3201,66 +3627,72 @@ virtual ostream& toString(ostream& out) const << " ; nbcards : " << nbcards << " ("; return MTGAbility::toString(out) << ")"; + } + +ALavaborn * ALavaborn::clone() const{ + ALavaborn * a = NEW ALavaborn(*this); + a->isClone = 1; + return a; } + }; -//GenericMillstone -class ADeplete:public TargetAbility{ +//Generic Millstone +class AADepleter:public ActivatedAbility{ public: int nbcards; - ADeplete(int _id, MTGCardInstance * card, ManaCost * _cost, int _nbcards = 1,TargetChooser * _tc = NULL, int _tap = 1):TargetAbility(_id,card, _tc, _cost,0,_tap){ - if (!tc) tc= NEW PlayerTargetChooser(card); - nbcards = _nbcards; + AADepleter(int _id, MTGCardInstance * card, Player * _target, int nbcards = 1, ManaCost * _cost=NULL, int _tap = 1):ActivatedAbility(_id,card, _cost,0,_tap),nbcards(nbcards){ + target = _target; } int resolve(){ - Player * player = tc->getNextPlayerTarget(); + Player * player = (Player *) target; if (!player) return 0; MTGLibrary * library = player->game->library; for (int i = 0; i < nbcards; i++){ if (library->nb_cards) - player->game->putInZone(library->cards[library->nb_cards-1],library, player->game->graveyard); + player->game->putInZone(library->cards[library->nb_cards-1],library, player->game->graveyard); } return 1; } - const char * getMenuText(){ - return "Deplete"; - } - virtual ostream& toString(ostream& out) const - { - out << "ADeplete ::: nbcards : " << nbcards - << " ("; - return TargetAbility::toString(out) << ")"; + const char * getMenuText(){ + return "Deplete"; + } + + AADepleter * AADepleter::clone() const{ + AADepleter * a = NEW AADepleter(*this); + a->isClone = 1; + return a; } }; -class ADiscard:public TargetAbility{ +//Random Discard +class AARandomDiscarder:public ActivatedAbility{ public: int nbcards; - ADiscard(int _id, MTGCardInstance * card, ManaCost * _cost, int _nbcards = 1,TargetChooser * _tc = NULL, int _tap = 1):TargetAbility(_id,card, _tc, _cost,0,_tap){ - if (!tc) tc= NEW PlayerTargetChooser(card); - nbcards = _nbcards; + AARandomDiscarder(int _id, MTGCardInstance * card, Player * _target, int nbcards = 1, ManaCost * _cost=NULL, int _tap = 1):ActivatedAbility(_id,card, _cost,0,_tap),nbcards(nbcards){ + target = _target; } int resolve(){ - Player * player = tc->getNextPlayerTarget(); + Player * player = (Player *) target; if (!player) return 0; - for (int i = 0; i < 2; i++){ - game->players[i]->game->discardRandom(game->players[i]->game->hand); - } + for (int i = 0; i < nbcards; i++){ + player->game->discardRandom(player->game->hand); + } return 1; } - const char * getMenuText(){ - return "Discard"; + + const char * getMenuText(){ + return "Discard Random"; } - virtual ostream& toString(ostream& out) const - { - out << "ADiscard ::: nbcards : " << nbcards - << " ("; - return TargetAbility::toString(out) << ")"; - } + AARandomDiscarder * clone() const{ + AARandomDiscarder * a = NEW AARandomDiscarder(*this); + a->isClone = 1; + return a; + } }; // Generic Karma @@ -3292,6 +3724,12 @@ class ADamageForTypeControlled: public TriggeredAbility{ << " ("; return TriggeredAbility::toString(out) << ")"; } + + ADamageForTypeControlled * ADamageForTypeControlled::clone() const{ + ADamageForTypeControlled * a = NEW ADamageForTypeControlled(*this); + a->isClone = 1; + return a; + } }; // Dreamborn Muse @@ -3322,6 +3760,12 @@ class ADreambornMuse: public TriggeredAbility{ << " ("; return TriggeredAbility::toString(out) << ")"; } + + ADreambornMuse * ADreambornMuse::clone() const{ + ADreambornMuse * a = NEW ADreambornMuse(*this); + a->isClone = 1; + return a; + } }; @@ -3344,6 +3788,12 @@ class AShieldOfTheAge: public TargetAbility{ out << "AShieldOfTheAge ::: ("; return TargetAbility::toString(out) << ")"; } + + AShieldOfTheAge * AShieldOfTheAge::clone() const{ + AShieldOfTheAge * a = NEW AShieldOfTheAge(*this); + a->isClone = 1; + return a; + } }; @@ -3384,6 +3834,12 @@ class AGiveLifeForTappedType:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + + AGiveLifeForTappedType * AGiveLifeForTappedType::clone() const{ + AGiveLifeForTappedType * a = NEW AGiveLifeForTappedType(*this); + a->isClone = 1; + return a; + } }; //Minion of Leshrac @@ -3427,64 +3883,14 @@ class AMinionofLeshrac: public TargetAbility{ << " ("; return TargetAbility::toString(out) << ")"; } + + AMinionofLeshrac * AMinionofLeshrac::clone() const{ + AMinionofLeshrac * a = NEW AMinionofLeshrac(*this); + a->isClone = 1; + return a; + } }; -//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; - } - - - virtual ostream& toString(ostream& out) const - { - out << "AKirdApe ::: power : " << power - << " ; toughness : " << toughness - << " ; ability : " << ability - << " ; modifier : " << modifier - << " ; includeSelf : " << includeSelf - << " ("; - return ListMaintainerAbility::toString(out) << ")"; - } -}; //Rampage ability class ARampageAbility:public MTGAbility{ @@ -3537,6 +3943,12 @@ class ARampageAbility:public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + + ARampageAbility * ARampageAbility::clone() const{ + ARampageAbility * a = NEW ARampageAbility(*this); + a->isClone = 1; + return a; + } }; // Seedborn Muse @@ -3564,6 +3976,12 @@ class ASeedbornMuse: public TriggeredAbility{ out << "ASeedbornMuse ::: ("; return TriggeredAbility::toString(out) << ")"; } + + ASeedbornMuse * ASeedbornMuse::clone() const{ + ASeedbornMuse * a = NEW ASeedbornMuse(*this); + a->isClone = 1; + return a; + } }; // Graveborn Muse @@ -3598,6 +4016,12 @@ class AGravebornMuse: public TriggeredAbility{ << " ("; return TriggeredAbility::toString(out) << ")"; } + + AGravebornMuse * AGravebornMuse::clone() const{ + AGravebornMuse * a = NEW AGravebornMuse(*this); + a->isClone = 1; + return a; + } }; // Verdant Force @@ -3641,6 +4065,12 @@ class AVerdantForce: public TriggeredAbility{ out << "AVerdantForce ::: ("; return TriggeredAbility::toString(out) << ")"; } + + AVerdantForce * AVerdantForce::clone() const{ + AVerdantForce * a = NEW AVerdantForce(*this); + a->isClone = 1; + return a; + } }; //Instant Steal control of a target @@ -3675,6 +4105,12 @@ class AInstantControlSteal: public InstantAbility{ << " ("; return InstantAbility::toString(out) << ")"; } + + AInstantControlSteal * AInstantControlSteal::clone() const{ + AInstantControlSteal * a = NEW AInstantControlSteal(*this); + a->isClone = 1; + return a; + } }; //Angelic Chorus (10E) @@ -3713,6 +4149,12 @@ class AAngelicChorus: public ListMaintainerAbility{ << " ("; return ListMaintainerAbility::toString(out) << ")"; } + + AAngelicChorus * AAngelicChorus::clone() const{ + AAngelicChorus * a = NEW AAngelicChorus(*this); + a->isClone = 1; + return a; + } }; //Life/Damage for type removed/added from game - Generic Ankh of Mishra/dingus Egg @@ -3808,6 +4250,12 @@ class ALifeModifierPutinplay: public ListMaintainerAbility{ << " ("; return ListMaintainerAbility::toString(out) << ")"; } + ALifeModifierPutinplay * ALifeModifierPutinplay::clone() const{ + ALifeModifierPutinplay * a = NEW ALifeModifierPutinplay(*this); + a->isClone = 1; + return a; + } + }; @@ -3832,6 +4280,12 @@ class ACounters: public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + + ACounters * ACounters::clone() const{ + ACounters * a = NEW ACounters(*this); + a->isClone = 1; + return a; + } }; ///// Not working need to work on this one @@ -3877,6 +4331,12 @@ class AAbomination :public MTGAbility{ << " ("; return MTGAbility::toString(out) << ")"; } + + AAbomination * AAbomination::clone() const{ + AAbomination * a = NEW AAbomination(*this); + a->isClone = 1; + return a; + } }; diff --git a/projects/mtg/include/Blocker.h b/projects/mtg/include/Blocker.h index 96a29a942..0d4fc1df4 100644 --- a/projects/mtg/include/Blocker.h +++ b/projects/mtg/include/Blocker.h @@ -27,6 +27,7 @@ class UntapBlocker : public MTGAbility { ~UntapBlocker(); virtual void Update(float dt); virtual int destroy(); + virtual UntapBlocker * clone() const; }; diff --git a/projects/mtg/include/GuiLayers.h b/projects/mtg/include/GuiLayers.h index a9b44e0f3..1256cf378 100644 --- a/projects/mtg/include/GuiLayers.h +++ b/projects/mtg/include/GuiLayers.h @@ -25,7 +25,7 @@ class GuiLayer{ int mCurr; vectormObjects; void Add(JGuiObject * object); - void Remove(JGuiObject * object); + int Remove(JGuiObject * object); int modal; bool hasFocus; virtual void resetObjects(); diff --git a/projects/mtg/include/MTGAbility.h b/projects/mtg/include/MTGAbility.h index 03de2d5a3..a3c5fa135 100644 --- a/projects/mtg/include/MTGAbility.h +++ b/projects/mtg/include/MTGAbility.h @@ -19,15 +19,18 @@ class WEvent; #include #include #include +#include "../include/Damage.h" using std::string; using std::map; -//Two stupid variables used to give a hint to the AI: +//stupid variables used to give a hint to the AI: // Should I cast a spell on an enemy or friendly unit ? #define BAKA_EFFECT_GOOD 1 #define BAKA_EFFECT_BAD -1 #define BAKA_EFFECT_DONTKNOW 0 +#define MODE_PUTINTOPLAY 1 +#define MODE_ABILITY 2 #define COUNT_POWER 1 @@ -38,16 +41,17 @@ using std::map; class MTGAbility: public ActionElement{ protected: char menuText[25]; - + GameObserver * game; public: + int oneShot; int forceDestroy; ManaCost * cost; - Damageable * target; + Targetable * target; int aType; MTGCardInstance * source; MTGAbility(int id, MTGCardInstance * card); - MTGAbility(int id, MTGCardInstance * _source, Damageable * _target); + MTGAbility(int id, MTGCardInstance * _source, Targetable * _target); virtual int testDestroy(); virtual ~MTGAbility(); virtual void Render(){}; @@ -58,7 +62,10 @@ class MTGAbility: public ActionElement{ virtual int fireAbility(); virtual int stillInUse(MTGCardInstance * card){if (card==source) return 1; return 0;}; virtual int resolve(){return 0;}; + virtual MTGAbility* clone() const = 0; virtual ostream& toString(ostream& out) const; + virtual int addToGame(); + virtual int removeFromGame(); /*Poor man's casting */ /* Todo replace that crap with dynamic casting */ @@ -78,11 +85,12 @@ class MTGAbility: public ActionElement{ class TriggeredAbility:public MTGAbility{ public: TriggeredAbility(int id, MTGCardInstance * card); - TriggeredAbility(int id, MTGCardInstance * _source, Damageable * _target); + TriggeredAbility(int id, MTGCardInstance * _source, Targetable * _target); virtual void Update(float dt); virtual void Render(){}; virtual int trigger()=0; virtual int resolve() = 0; + virtual TriggeredAbility* clone() const = 0; virtual ostream& toString(ostream& out) const; }; @@ -96,18 +104,24 @@ class ActivatedAbility:public MTGAbility{ virtual int isReactingToClick(MTGCardInstance * card, ManaCost * mana = NULL); virtual int reactToTargetClick(Targetable * object); virtual int resolve() = 0; + virtual ActivatedAbility* clone() const = 0; virtual ostream& toString(ostream& out) const; }; class TargetAbility:public ActivatedAbility{ public: + MTGAbility * ability; TargetAbility(int id, MTGCardInstance * card, TargetChooser * _tc,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1); TargetAbility(int id, MTGCardInstance * card,ManaCost * _cost = NULL, int _playerturnonly = 0,int tap = 1); virtual void Update(float dt); virtual int reactToClick(MTGCardInstance * card); virtual int reactToTargetClick(Targetable * object); + virtual TargetAbility* clone() const = 0; virtual void Render(); + virtual int resolve(); + virtual const char * getMenuText(); virtual ostream& toString(ostream& out) const; + ~TargetAbility(); }; class InstantAbility:public MTGAbility{ @@ -118,6 +132,7 @@ class InstantAbility:public MTGAbility{ InstantAbility(int _id, MTGCardInstance * source); InstantAbility(int _id, MTGCardInstance * source,Damageable * _target); virtual int resolve(){return 0;}; + virtual InstantAbility* clone() const = 0; virtual ostream& toString(ostream& out) const; }; @@ -125,26 +140,32 @@ class InstantAbility:public MTGAbility{ class ListMaintainerAbility:public MTGAbility{ public: map cards; + map players; ListMaintainerAbility(int _id):MTGAbility(_id,NULL){}; ListMaintainerAbility(int _id, MTGCardInstance *_source):MTGAbility(_id, _source){}; ListMaintainerAbility(int _id, MTGCardInstance *_source,Damageable * _target):MTGAbility(_id, _source, _target){}; virtual void Update(float dt); + void updateTargets(); virtual int canBeInList(MTGCardInstance * card) = 0; virtual int added(MTGCardInstance * card) = 0; virtual int removed(MTGCardInstance * card) = 0; + virtual int canBeInList(Player * p){return 0;}; + virtual int added(Player * p){return 0;}; + virtual int removed(Player * p){return 0;}; virtual int destroy(); + virtual ListMaintainerAbility* clone() const = 0; virtual ostream& toString(ostream& out) const; }; /* An attempt to globalize triggered abilities as much as possible */ class MTGAbilityBasicFeatures{ public: - Damageable * target; + Targetable * target; GameObserver * game; MTGCardInstance * source; MTGAbilityBasicFeatures(); - MTGAbilityBasicFeatures(MTGCardInstance * _source, Damageable * _target = NULL); - void init(MTGCardInstance * _source, Damageable * _target = NULL); + MTGAbilityBasicFeatures(MTGCardInstance * _source, Targetable * _target = NULL); + void init(MTGCardInstance * _source, Targetable * _target = NULL); }; class Trigger:public MTGAbilityBasicFeatures{ @@ -176,7 +197,7 @@ class TriggerNextPhase:public TriggerAtPhase{ class TriggeredEvent:public MTGAbilityBasicFeatures{ public: TriggeredEvent(); - TriggeredEvent(MTGCardInstance * source, Damageable * target = NULL); + TriggeredEvent(MTGCardInstance * source, Targetable * target = NULL); virtual int resolve()=0; }; @@ -213,21 +234,22 @@ class GenericTriggeredAbility:public TriggeredAbility{ Trigger * t; TriggeredEvent * te; DestroyCondition * dc; - GenericTriggeredAbility(int id, MTGCardInstance * _source, Trigger * _t, TriggeredEvent * _te, DestroyCondition * _dc = NULL, Damageable * _target = NULL); + GenericTriggeredAbility(int id, MTGCardInstance * _source, Trigger * _t, TriggeredEvent * _te, DestroyCondition * _dc = NULL, Targetable * _target = NULL); virtual int trigger(); virtual int resolve(); virtual int testDestroy(); + virtual GenericTriggeredAbility* clone() const; ~GenericTriggeredAbility(); }; /* Ability Factory */ class AbilityFactory{ private: - int countCards(TargetChooser * tc, Player * player = NULL, int option = 0); - int putInPlayFromZone(MTGCardInstance * card, MTGGameZone * zone, Player * p); + int countCards(TargetChooser * tc, Player * player = NULL, int option = 0); int parsePowerToughness(string s, int *power, int *toughness); Trigger * parseTrigger(string magicText); - Damageable * parseCollateralTarget(MTGCardInstance * card, string s); + MTGAbility * parseMagicLine(string s, int id, Spell * spell, MTGCardInstance *card, int activated = 0); + int abilityEfficiency(MTGAbility * a, Player * p, int mode = MODE_ABILITY); public: int magicText(int id, Spell * spell, MTGCardInstance * card = NULL); int destroyAllInPlay(TargetChooser * tc, int bury = 0); @@ -243,16 +265,16 @@ class AbilityFactory{ class AManaProducer: public MTGAbility{ protected: - ManaCost * cost; ManaCost * output; string menutext; float x0,y0,x1,y1,x,y; float animation; Player * controller; - int tap; + hgeParticleSystem * mParticleSys; public: + int tap; static int currentlyTapping; AManaProducer(int id, MTGCardInstance * card, ManaCost * _output, ManaCost * _cost = NULL, int doTap = 1 ); void Update(float dt); @@ -263,6 +285,7 @@ class AManaProducer: public MTGAbility{ const char * getMenuText(); int testDestroy(); ~AManaProducer(); + virtual AManaProducer * clone() const; virtual ostream& toString(ostream& out) const; }; diff --git a/projects/mtg/include/MTGGamePhase.h b/projects/mtg/include/MTGGamePhase.h index 9cf5c4530..c194a8153 100644 --- a/projects/mtg/include/MTGGamePhase.h +++ b/projects/mtg/include/MTGGamePhase.h @@ -18,6 +18,7 @@ class MTGGamePhase: public ActionElement { virtual void Render(); virtual void Update(float dt); bool CheckUserInput(u32 key); + virtual MTGGamePhase * clone() const; virtual ostream& toString(ostream& out) const; }; diff --git a/projects/mtg/include/MTGRules.h b/projects/mtg/include/MTGRules.h index 006e5815d..d03a54396 100644 --- a/projects/mtg/include/MTGRules.h +++ b/projects/mtg/include/MTGRules.h @@ -16,6 +16,7 @@ class MTGPutInPlayRule:public MTGAbility{ virtual ostream& toString(ostream& out) const; MTGPutInPlayRule(int _id); const char * getMenuText(){return "Put into play";} + virtual MTGPutInPlayRule * clone() const; }; class MTGAttackRule:public MTGAbility{ @@ -27,6 +28,7 @@ class MTGAttackRule:public MTGAbility{ MTGAttackRule(int _id); const char * getMenuText(){return "Attacker";} void Update(float dt); + virtual MTGAttackRule * clone() const; }; class MTGBlockRule:public MTGAbility{ @@ -37,49 +39,18 @@ class MTGBlockRule:public MTGAbility{ virtual ostream& toString(ostream& out) const; MTGBlockRule(int _id); const char * getMenuText(){return "Blocker";} + virtual MTGBlockRule * clone() const; }; /* Persist Rule */ class MTGPersistRule:public MTGAbility{ public: - MTGPersistRule(int _id):MTGAbility(_id,NULL){}; - - int receiveEvent(WEvent * event){ - if (event->type == WEvent::CHANGE_ZONE){ - WEventZoneChange * e = (WEventZoneChange *) event; - MTGCardInstance * card = e->card->previous; - if (card && card->basicAbilities[Constants::PERSIST] && !card->counters->hasCounter(-1,-1)){ - int ok = 0; - for (int i = 0; i < 2 ; i++){ - Player * p = game->players[i]; - if (e->from == p->game->inPlay) ok = 1; - } - if (!ok) return 0; - for (int i = 0; i < 2 ; i++){ - Player * p = game->players[i]; - if (e->to == p->game->graveyard){ - //p->game->putInZone(card, p->game->graveyard, card->owner->game->hand); - MTGCardInstance * copy = p->game->putInZone(e->card, p->game->graveyard, e->card->owner->game->stack); - Spell * spell = NEW Spell(copy); - spell->resolve(); - spell->source->counters->addCounter(-1,-1); - game->mLayers->playLayer()->forceUpdateCards(); - delete spell; - return 1; - } - } - } - } - return 0; - } - - virtual ostream& toString(ostream& out) const - { - out << "MTGPersistRule ::: ("; - return MTGAbility::toString(out) << ")"; - } - int testDestroy(){return 0;} + MTGPersistRule(int _id); + int receiveEvent(WEvent * event); + virtual ostream& toString(ostream& out) const; + int testDestroy(); + virtual MTGPersistRule * clone() const; }; @@ -91,39 +62,13 @@ class MTGPersistRule:public MTGAbility{ */ class MTGLegendRule:public ListMaintainerAbility{ public: - MTGLegendRule(int _id):ListMaintainerAbility(_id){}; - - int canBeInList(MTGCardInstance * card){ - if (card->basicAbilities[Constants::LEGENDARY] && game->isInPlay(card)){ - return 1; - } - return 0; - } - - int added(MTGCardInstance * card){ - map::iterator it; - int destroy = 0; - for ( it=cards.begin() ; it != cards.end(); it++ ){ - MTGCardInstance * comparison = (*it).first; - if (comparison!= card && !strcmp(comparison->getName(), card->getName())){ - comparison->owner->game->putInGraveyard(comparison); - destroy = 1; - } - } - if (destroy){ - card->owner->game->putInGraveyard(card); - } - return 1; - } - - int removed(MTGCardInstance * card){return 0;} - - int testDestroy(){return 0;} - - virtual ostream& toString(ostream& out) const - { - return out << "MTGLegendRule :::"; - } + MTGLegendRule(int _id); + int canBeInList(MTGCardInstance * card); + int added(MTGCardInstance * card); + int removed(MTGCardInstance * card); + int testDestroy(); + virtual ostream& toString(ostream& out) const; + virtual MTGLegendRule * clone() const; }; @@ -149,34 +94,22 @@ public: int reactToClick(MTGCardInstance * card, int id); const char * getMenuText(){return "Momir";} virtual ostream& toString(ostream& out) const; + virtual MTGMomirRule * clone() const; }; /* LifeLink */ class MTGLifelinkRule:public MTGAbility{ public: - MTGLifelinkRule(int _id):MTGAbility(_id,NULL){}; + MTGLifelinkRule(int _id); - int receiveEvent(WEvent * event){ - if (event->type == WEvent::DAMAGE){ - WEventDamage * e = (WEventDamage *) event; - Damage * d = e->damage; - MTGCardInstance * card = d->source; - if (d->damage>0 && card && card->basicAbilities[Constants::LIFELINK]){ - card->controller()->life+= d->damage; - return 1; - } - } - return 0; - } + int receiveEvent(WEvent * event); - int testDestroy(){return 0;} + int testDestroy(); - virtual ostream& toString(ostream& out) const - { - out << "MTGLifelinkRule ::: ("; - return MTGAbility::toString(out) << ")"; - } + virtual ostream& toString(ostream& out) const; + + virtual MTGLifelinkRule * clone() const; }; @@ -205,6 +138,7 @@ public: void Render(); HUDDisplay(int _id); ~HUDDisplay(); + virtual HUDDisplay * clone() const; }; diff --git a/projects/mtg/include/TargetsList.h b/projects/mtg/include/TargetsList.h index 2059b76e2..7583a4962 100644 --- a/projects/mtg/include/TargetsList.h +++ b/projects/mtg/include/TargetsList.h @@ -27,7 +27,7 @@ class TargetsList{ Interruptible * getNextInterruptible(Interruptible * previous, int type); Spell * getNextSpellTarget(Spell * previous = 0); Damage * getNextDamageTarget(Damage * previous = 0); - Targetable * getNextTarget(Targetable * previous, int type); + Targetable * getNextTarget(Targetable * previous = 0, int type = -1); void initTargets(){cursor = 0;}; }; diff --git a/projects/mtg/src/AIMomirPlayer.cpp b/projects/mtg/src/AIMomirPlayer.cpp index e6ad918c8..db72bf76d 100644 --- a/projects/mtg/src/AIMomirPlayer.cpp +++ b/projects/mtg/src/AIMomirPlayer.cpp @@ -15,13 +15,13 @@ AIMomirPlayer::AIMomirPlayer(MTGPlayerCards * _deck, char * file, char * fileSma } int AIMomirPlayer::getEfficiency(AIAction * action){ + MTGAbility * ability = action->ability; + if (ability->cost && !(ability->cost->isExtraPaymentSet())) return 0; //Does not handle abilities with sacrifice yet + int efficiency = AIPlayerBaka::getEfficiency(action); - -int efficiency = AIPlayerBaka::getEfficiency(action); - -GameObserver * g = GameObserver::GetInstance(); -if (g->getCurrentGamePhase() < Constants::MTG_PHASE_FIRSTMAIN) return 0; - return efficiency; + GameObserver * g = GameObserver::GetInstance(); + if (g->getCurrentGamePhase() < Constants::MTG_PHASE_FIRSTMAIN) return 0; + return efficiency; } MTGAbility * AIMomirPlayer::getMomirAbility(){ @@ -113,81 +113,4 @@ the general rule is this: if you want to get to Eight, you have to skip two drop return AIPlayerBaka::computeActions(); } -/* -int AIPlayerBaka::computeActions(){ - GameObserver * g = GameObserver::GetInstance(); - Player * p = g->currentPlayer; - if (!(g->currentlyActing() == this)) return 0; - if (chooseTarget()) return 1; - int currentGamePhase = g->getCurrentGamePhase(); - if (g->isInterrupting == this){ // interrupting - selectAbility(); - return 1; - }else if (p == this && g->mLayers->stackLayer()->count(0,NOT_RESOLVED) == 0){ //standard actions - CardDescriptor cd; - MTGCardInstance * card = NULL; - switch(currentGamePhase){ - case Constants::MTG_PHASE_FIRSTMAIN: - case Constants::MTG_PHASE_SECONDMAIN: - if (canPutLandsIntoPlay){ - //Attempt to put land into play - cd.init(); - cd.setColor(Constants::MTG_COLOR_LAND); - card = cd.match(game->hand); - if (card){ - AIAction * a = NEW AIAction(card); - clickstream.push(a); - return 1; - } - } - //No mana, try to get some - getPotentialMana(); - if (potentialMana->getConvertedCost() > 0){ - - - //look for the most expensive creature we can afford - nextCardToPlay = FindCardToPlay(potentialMana, "creature"); - //Let's Try an enchantment maybe ? - if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "enchantment"); - if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "artifact"); - if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "instant"); - if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "sorcery"); - if (nextCardToPlay){ -#if defined (WIN32) || defined (LINUX) - char buffe[4096]; - sprintf(buffe, "Putting Card Into Play: %s", nextCardToPlay->getName()); - OutputDebugString(buffe); -#endif - - tapLandsForMana(potentialMana,nextCardToPlay->getManaCost()); - AIAction * a = NEW AIAction(nextCardToPlay); - clickstream.push(a); - return 1; - }else{ - selectAbility(); - } - }else{ - selectAbility(); - } - break; - case Constants::MTG_PHASE_COMBATATTACKERS: - chooseAttackers(); - break; - default: - selectAbility(); - break; - } - }else{ - switch(currentGamePhase){ - case Constants::MTG_PHASE_COMBATBLOCKERS: - chooseBlockers(); - break; - default: - break; - } - return 1; - } - return 1; -}; -*/ diff --git a/projects/mtg/src/AIPlayer.cpp b/projects/mtg/src/AIPlayer.cpp index 81a50632f..b7d9dc4d0 100644 --- a/projects/mtg/src/AIPlayer.cpp +++ b/projects/mtg/src/AIPlayer.cpp @@ -135,17 +135,29 @@ int AIAction::getEfficiency(){ ActionStack * s = g->mLayers->stackLayer(); Player * p = g->currentlyActing(); if (s->has(ability)) return 0; - if (ability->cost && !(ability->cost->isExtraPaymentSet())) return 0; //Does not handle abilities with sacrifice yet - switch (ability->aType){ + + MTGAbility * a = ability; + GenericTargetAbility * gta = dynamic_cast(a); + if (gta) a = gta->ability; + + GenericActivatedAbility * gaa = dynamic_cast(a); + if (gaa) a = gaa->ability; + + if (!a){ + OutputDebugString("FATAL: Ability is NULL in AIAction::getEfficiency()"); + return 0; + } + + switch (a->aType){ case MTGAbility::DAMAGER: { - ADamager * a = (ADamager *) ability; + AADamager * aad = (AADamager *) a; if ( p == target->controller()){ efficiency = 0; - }else if (a->damage >= target->toughness){ + }else if (aad->damage >= target->toughness){ efficiency = 100; }else if (target->toughness){ - efficiency = (100 * a->damage) / target->toughness; + efficiency = (50 * aad->damage) / target->toughness; }else{ efficiency = 0; } @@ -153,22 +165,12 @@ int AIAction::getEfficiency(){ } case MTGAbility::STANDARD_REGENERATE: { - MTGCardInstance * _target = (MTGCardInstance *)(ability->target); - PutInGraveyard * action = ((PutInGraveyard *) g->mLayers->stackLayer()->getNext(NULL,ACTION_PUTINGRAVEYARD,NOT_RESOLVED)); - int i = 0; - while(action){ - i++; - if (action->card == _target){ - efficiency = 95; - action = NULL; - }else{ - action = ((PutInGraveyard *) g->mLayers->stackLayer()->getNext(action,ACTION_PUTINGRAVEYARD,NOT_RESOLVED)); - } + MTGCardInstance * _target = (MTGCardInstance *)(a->target); + efficiency = 0; + if (!_target->regenerateTokens && g->getCurrentGamePhase()< Constants::MTG_PHASE_COMBATDAMAGE && (_target->defenser || _target->blockers.size())){ + efficiency = 95; } - char buf[4096]; - sprintf(buf,"Graveyard : %i\n", i); - OutputDebugString(buf); - if (efficiency == -1) efficiency = 0; + //TODO If the card is the target of a damage spell break; } case MTGAbility::MANA_PRODUCER: //can't use mana producers right now :/ @@ -741,125 +743,3 @@ int AIPlayerBaka::Act(float dt){ return 1; }; -/* -int AIPlayerBaka::Act(float dt){ - GameObserver * gameObs = GameObserver::GetInstance(); - int currentGamePhase = gameObs->getCurrentGamePhase(); - - if (currentGamePhase == Constants::MTG_PHASE_CLEANUP && currentGamePhase != oldGamePhase){ -#if defined (WIN32) || defined (LINUX) - OutputDebugString("updating stats\n"); -#endif - if (getStats()) getStats()->updateStats(); - } - - - oldGamePhase = currentGamePhase; - - - //if (checkInterrupt()) return 0; - - timer-= dt; - if (AManaProducer::currentlyTapping || timer>0){ - return 0; - } - initTimer(); - checkInterrupt(); - if (currentAbility) return (useAbility()); - if (combatDamages()) return 0; - if (chooseTarget()) return 0; - - - Player * currentPlayer = gameObs->currentPlayer; - - - - - CardDescriptor cd; - - - if (currentPlayer == this){ - MTGCardInstance * card = NULL; - switch(currentGamePhase){ - case Constants::MTG_PHASE_FIRSTMAIN: - case Constants::MTG_PHASE_SECONDMAIN: - if (canPutLandsIntoPlay){ - - //Attempt to put land into play - cd.init(); - cd.setColor(Constants::MTG_COLOR_LAND); - card = cd.match(game->hand); - if (card){ - gameObs->cardClick(card); - } - } - if(NULL == card){ - - //Attempt to put creature into play - if (manaPool->getConvertedCost()==0){ - - //No mana, try to get some - getPotentialMana(); - if (potentialMana->getConvertedCost() > 0){ - - - //look for the most expensive creature we can afford - nextCardToPlay = FindCardToPlay(potentialMana, "creature"); - //Let's Try an enchantment maybe ? - if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "enchantment"); - if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "artifact"); - if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "instant"); - if (!nextCardToPlay) nextCardToPlay = FindCardToPlay(potentialMana, "sorcery"); - if (nextCardToPlay){ -#if defined (WIN32) || defined (LINUX) - char buffe[4096]; - sprintf(buffe, "Putting Card Into Play: %s", nextCardToPlay->getName()); - OutputDebugString(buffe); -#endif - - tapLandsForMana(potentialMana,nextCardToPlay->getManaCost()); - } - } - SAFE_DELETE(potentialMana); - }else{ - //We have mana, we can try to put the card into play -#if defined (WIN32) || defined (LINUX) - OutputDebugString("Mana paid, ready to put card into play\n"); -#endif - if (nextCardToPlay){ - gameObs->cardClick(nextCardToPlay); - nextCardToPlay = NULL; - }else{ - //ERROR, WE PAID MANA WITHOUT ANY WILL TO PLAY - } - } - } - if (NULL == card && NULL == nextCardToPlay){ -#if defined (WIN32) || defined (LINUX) - OutputDebugString("Switching to next phase\n"); -#endif - gameObs->userRequestNextGamePhase(); - } - break; - case Constants::MTG_PHASE_COMBATATTACKERS: - chooseAttackers(); - gameObs->userRequestNextGamePhase(); - break; - default: - gameObs->userRequestNextGamePhase(); - break; - } - }else{ - switch(currentGamePhase){ - case Constants::MTG_PHASE_COMBATBLOCKERS: - chooseBlockers(); - gameObs->userRequestNextGamePhase(); - break; - default: - break; - } - return 1; - } - return 1; -} -*/ diff --git a/projects/mtg/src/ActionElement.cpp b/projects/mtg/src/ActionElement.cpp index be60891ab..146fd107d 100644 --- a/projects/mtg/src/ActionElement.cpp +++ b/projects/mtg/src/ActionElement.cpp @@ -10,10 +10,13 @@ ActionElement::ActionElement(int id):JGuiObject(id){ currentPhase = -1; newPhase = -1; tc = NULL; + isClone = 0; } ActionElement::~ActionElement(){ - SAFE_DELETE(tc); + if (!isClone){ + SAFE_DELETE(tc); + } } int ActionElement::getActivity(){ diff --git a/projects/mtg/src/ActionLayer.cpp b/projects/mtg/src/ActionLayer.cpp index 7db08fff7..5c088d952 100644 --- a/projects/mtg/src/ActionLayer.cpp +++ b/projects/mtg/src/ActionLayer.cpp @@ -71,8 +71,7 @@ void ActionLayer::Update(float dt){ if (mObjects[i]!= NULL){ ActionElement * currentAction = (ActionElement *)mObjects[i]; if (currentAction->testDestroy()){ - currentAction->destroy(); - Remove(currentAction); + game->removeObserver(currentAction); } } } diff --git a/projects/mtg/src/Blocker.cpp b/projects/mtg/src/Blocker.cpp index 13662a5dd..286b7f39c 100644 --- a/projects/mtg/src/Blocker.cpp +++ b/projects/mtg/src/Blocker.cpp @@ -24,6 +24,12 @@ void UntapBlocker::init(ManaCost * _cost){ manaCost = _cost; } + UntapBlocker * UntapBlocker::clone() const{ + UntapBlocker * a = NEW UntapBlocker(*this); + a->isClone = 1; + return a; + } + //Default behaviour for blockers : they block the card they're attached to void UntapBlocker::Update(float dt){ diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index 76a753c3c..3e66ea644 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -152,7 +152,6 @@ int GameObserver::cancelCurrentAction(){ } void GameObserver::userRequestNextGamePhase(){ - OutputDebugString("requesting Next Phase\n"); if (mLayers->stackLayer()->getNext(NULL,0,NOT_RESOLVED)) return; if (getCurrentTargetChooser()) return; if (mLayers->combatLayer()->isDisplayed()) return; @@ -164,7 +163,6 @@ void GameObserver::userRequestNextGamePhase(){ return; } } - OutputDebugString("Next Phase Accepted\n"); if (cPhaseOld->id == Constants::MTG_PHASE_COMBATBLOCKERS || opponent()->isAI() || GameOptions::GetInstance()->values[GameOptions::phaseInterrupts[currentGamePhase]].getIntValue()){ @@ -241,11 +239,14 @@ void GameObserver::addObserver(MTGAbility * observer){ void GameObserver::removeObserver(ActionElement * observer){ if (observer){ - observer->destroy(); + if (mLayers->actionLayer()->getIndexOf(observer) != -1){ + observer->destroy(); + mLayers->actionLayer()->Remove(observer); + } }else{ //TODO log error } - mLayers->actionLayer()->Remove(observer); + } GameObserver::~GameObserver(){ diff --git a/projects/mtg/src/GuiLayers.cpp b/projects/mtg/src/GuiLayers.cpp index 1cd338c80..6677457f0 100644 --- a/projects/mtg/src/GuiLayers.cpp +++ b/projects/mtg/src/GuiLayers.cpp @@ -21,7 +21,7 @@ void GuiLayer::Add(JGuiObject *object){ mCount++; } -void GuiLayer::Remove(JGuiObject *object){ +int GuiLayer::Remove(JGuiObject *object){ for (int i=0;iplayers[i]) continue; - MTGGameZone * zones[] = {game->players[i]->game->inPlay,game->players[i]->game->graveyard,game->players[i]->game->hand}; - for (int k = 0; k < 3; k++){ - for (int j = zones[k]->nb_cards-1; j >=0 ; j--){ - MTGCardInstance * current = zones[k]->cards[j]; - if (tc->canTarget(current)){ - switch (option){ - case COUNT_POWER: - result+= current->power; - break; - default: - result++; - break; - } - } - } - } + MTGGameZone * zones[] = {game->players[i]->game->inPlay,game->players[i]->game->graveyard,game->players[i]->game->hand}; + for (int k = 0; k < 3; k++){ + for (int j = zones[k]->nb_cards-1; j >=0 ; j--){ + MTGCardInstance * current = zones[k]->cards[j]; + if (tc->canTarget(current)){ + switch (option){ + case COUNT_POWER: + result+= current->power; + break; + default: + result++; + break; + } + } + } + } } return result; } -int AbilityFactory::destroyAllInPlay(TargetChooser * tc, int bury){ - MTGCardInstance * targetter = tc->targetter; - tc->targetter = NULL; // This is to prevent protection from... as objects that destroy all do not actually target - GameObserver * game = GameObserver::GetInstance(); - for (int i = 0; i < 2 ; i++){ - Player * p = game->players[i]; - for (int j = p->game->inPlay->nb_cards-1; j >=0 ; j--){ - MTGCardInstance * current = p->game->inPlay->cards[j]; - if (tc->canTarget(current)){ - if (bury) current->bury(); - else current->destroy(); - } - } - } - tc->targetter = targetter; //restore targetter - return 1; -} + int AbilityFactory::CantBlock(TargetChooser * tc){ GameObserver * g = GameObserver::GetInstance(); @@ -66,106 +50,18 @@ int AbilityFactory::CantBlock(TargetChooser * tc){ return 1; } -int AbilityFactory::damageAll(TargetChooser * tc, int damage){ - MTGCardInstance * targetter = tc->targetter; - tc->targetter = NULL; // This is to prevent protection from... as objects that destroy all do not actually target - GameObserver * g = GameObserver::GetInstance(); - for (int i = 0; i < 2 ; i++){ - if (tc->canTarget(g->players[i])) g->mLayers->stackLayer()->addDamage(tc->source,g->players[i], damage); - for (int j = g->players[i]->game->inPlay->nb_cards-1; j >=0 ; j--){ - MTGCardInstance * current = g->players[i]->game->inPlay->cards[j]; - if (tc->canTarget(current)){ - g->mLayers->stackLayer()->addDamage(tc->source,current, damage); - } - } - } - tc->targetter = targetter; //restore source - return 1; -} - -int AbilityFactory::moveAll(TargetChooser * tc, string destinationZone){ - MTGCardInstance * targetter = tc->targetter; - tc->targetter = NULL; // This is to prevent protection from... as objects that destroy all do not actually target - GameObserver * g = GameObserver::GetInstance(); - for (int i = 0; i < 2 ; i++){ - MTGGameZone * zones[] = {g->players[i]->game->inPlay,g->players[i]->game->graveyard,g->players[i]->game->hand}; - for (int k = 0; k < 3; k++){ - for (int j = zones[k]->nb_cards-1; j >=0 ; j--){ - MTGCardInstance * current = zones[k]->cards[j]; - if (tc->canTarget(current)){ - AZoneMover::moveTarget(current,destinationZone , tc->source); - } - } - } - } - tc->targetter = targetter; //restore source - return 1; -} - - - - -int AbilityFactory::TapAll(TargetChooser * tc){ - MTGCardInstance * targetter = tc->targetter; - tc->targetter = NULL; // This is to prevent protection from... - GameObserver * g = GameObserver::GetInstance(); - for (int i = 0; i < 2 ; i++){ - for (int j = g->players[i]->game->inPlay->nb_cards-1; j >=0 ; j--){ - MTGCardInstance * current = g->players[i]->game->inPlay->cards[j]; - if (tc->canTarget(current)){ - current->tap(); - } - } - } - tc->targetter = targetter; //restore source - return 1; -} - -int AbilityFactory::UntapAll(TargetChooser * tc){ - MTGCardInstance * targetter = tc->targetter; - tc->targetter = NULL; // This is to prevent protection from... - GameObserver * g = GameObserver::GetInstance(); - for (int i = 0; i < 2 ; i++){ - for (int j = g->players[i]->game->inPlay->nb_cards-1; j >=0 ; j--){ - MTGCardInstance * current = g->players[i]->game->inPlay->cards[j]; - if (tc->canTarget(current)){ - current->untap(); - } - } - } - tc->targetter = targetter; //restore source - return 1; -} - -int AbilityFactory::putInPlayFromZone(MTGCardInstance * card, MTGGameZone * zone, Player * p){ - MTGCardInstance * copy = p->game->putInZone(card, zone, p->game->stack); - Spell * spell = NEW Spell(copy); - spell->resolve(); - delete spell; - return 1; -} - -Damageable * AbilityFactory::parseCollateralTarget(MTGCardInstance * card, string s){ - size_t found = s.find("controller"); - if (found != string::npos) return card->controller(); - return NULL; -} int AbilityFactory::parsePowerToughness(string s, int *power, int *toughness){ size_t found = s.find("/"); if (found != string::npos){ - int search_from = found - 4; - if (search_from < 0) search_from = 0; - size_t start = s.find(':', search_from); - if (start == string::npos) start = s.find(" ", search_from); + size_t end = s.find(" ", found); + if (end == string::npos) end = s.size(); + size_t start = s.find_last_of(" ",found); if (start == string::npos) start = -1; + *power = atoi(s.substr(start+1,s.size()-found).c_str()); - size_t end = s.find(" ",start); - if (end != string::npos){ - *toughness = atoi(s.substr(found+1,end-found-1).c_str()); - }else{ - *toughness = atoi(s.substr(found+1).c_str()); - } + *toughness = atoi(s.substr(found+1,end-found-1).c_str()); + return 1; } return 0; @@ -203,6 +99,626 @@ Trigger * AbilityFactory::parseTrigger(string magicText){ +//Parses a string and returns the corresponding MTGAbility object +// Returns NULL if parsing failed +MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTGCardInstance *card, int activated){ + size_t found; + + //TODO This block redundant with calling function + if (!card && spell) card = spell->source; + if (!card) return NULL; + MTGCardInstance * target = card->target; + if (!target) target = card; + + int doTap = 0; //Tap in the cost ? + if (s.find("{t}") != string::npos) doTap = 1; + + unsigned int delimiter = s.find("}:"); + + if (delimiter!= string::npos && s[0]=='{'){ + ManaCost * cost = ManaCost::parseManaCost(s.substr(0,delimiter+1),NULL,card); + if (doTap || (cost && !cost->isNull())){ + string s1 = s.substr(delimiter+2); + + MTGAbility * a = parseMagicLine(s1, id, spell, card, 1); + if (!a){ + OutputDebugString("Error parsing:"); + OutputDebugString(s.c_str()); + OutputDebugString("\n"); + return NULL; + } + + //A stupid Special case for ManaProducers because they don't use the stack :( + AManaProducer * amp = dynamic_cast(a); + if (amp){ + amp->cost = cost; + amp->oneShot = 0; + amp->tap = doTap; + return amp; + } + + int limit = 0; + unsigned int limit_str = s.find("limit:"); + if (limit_str != string::npos){ + limit = atoi(s.substr(limit_str+6).c_str()); + } + + TargetChooser * tc = NULL; + //Target Abilities + found = s.find("target("); + if (found != string::npos){ + int end = s.find(")", found); + string starget = s.substr(found + 7,end - found - 7); + TargetChooserFactory tcf; + tc = tcf.createTargetChooser(starget, card); + } + + if (tc) return NEW GenericTargetAbility(id, card, tc, a,cost, doTap,limit); + return NEW GenericActivatedAbility(id, card, a,cost,doTap,limit); + } + SAFE_DELETE(cost); + } + + + + //Multiple abilities for ONE cost + found = s.find("&&"); + if (found != string::npos){ + string s1 = s.substr(0,found); + string s2 = s.substr(found+2); + MultiAbility * multi = NEW MultiAbility(id, card,NULL,NULL); + MTGAbility * a1 = parseMagicLine(s1,id,spell, card); + MTGAbility * a2 = parseMagicLine(s2,id,spell, card); + multi->Add(a1); + multi->Add(a2); + return multi; + } + + //When...comes into play, you may... + found = s.find("may "); + if (found != string::npos){ + string s1 = s.substr(found+4); + MTGAbility * a1 = parseMagicLine(s1,id,spell, card); + if (!a1) return NULL; + TargetChooser * tc = NULL; + //Target Abilities + found = s.find("target("); + if (found != string::npos){ + int end = s.find(")", found); + string starget = s.substr(found + 7,end - found - 7); + TargetChooserFactory tcf; + tc = tcf.createTargetChooser(starget, card); + } + if (tc) a1 = NEW GenericTargetAbility(id, card, tc, a1); + return NEW MayAbility(id,a1,card); + } + + Trigger * trigger = NULL; + trigger = parseTrigger(s); + //Dirty way to remove the trigger text (could get in the way) + if (trigger){ + found = s.find(":"); + s = s.substr(found+1); + } + + + //Lord, foreach, aslongas + string lords[] = {"lord(","foreach(", "aslongas(", "all("}; + for (int i = 0; i < 4; ++i){ + found = s.find(lords[i]); + if (found != string::npos){ + size_t header = lords[i].size(); + size_t end = s.find(")", found+header); + string s1; + if (found == 0 || end != s.size()-1){ + s1 = s.substr(end+1); + }else{ + s1 = s.substr(0, found); + } + if (end != string::npos){ + int lordIncludeSelf = 1; + size_t other = s.find("other", end); + if ( other != string::npos){ + lordIncludeSelf = 0; + s.replace(other, 5,""); + } + string lordTargetsString = s.substr(found+header,end-found-header); + TargetChooserFactory tcf; + TargetChooser * lordTargets = tcf.createTargetChooser(lordTargetsString, card); + + + MTGAbility * a = parseMagicLine(s1,id,spell, card); + if (!a){ + SAFE_DELETE(lordTargets); + return NULL; + } + MTGAbility * result = NULL; + int oneShot = 0; + if (card->hasType("sorcery") || card->hasType("instant")) oneShot = 1; + if (i == 3) oneShot = 1; + switch(i){ + case 0: result = NEW ALord(id, card, lordTargets, lordIncludeSelf, a); break; + case 1: result = NEW AForeach(id, card, target,lordTargets, lordIncludeSelf, a); break; + case 2: result = NEW AAsLongAs(id, card, lordTargets, lordIncludeSelf, a); break; + case 3: result = NEW ALord(id, card, lordTargets, lordIncludeSelf, a); break; + default: result = NULL; + } + if (result) result->oneShot = oneShot; + return result; + } + return NULL; + } + } + + + //Fizzle (counterspell...) + found = s.find("fizzle"); + if (found != string::npos){ + Spell * starget = NULL; + if (spell) starget = spell->getNextSpellTarget(); + MTGAbility * a = NEW AAFizzler(id,card,starget); + a->oneShot = 1; + return a; + } + + + //Untapper (Ley Druid...) + found = s.find("untap"); + if (found != string::npos){ + MTGAbility * a = NEW AAUntapper(id,card,target); + a->oneShot = 1; + return a; + } + + + //Regeneration + found = s.find("regenerate"); + if (found != string::npos){ + MTGAbility * a = NEW AStandardRegenerate(id,card,target); + a->oneShot = 1; + return a; + } + + + //Token creator. Name, type, p/t, abilities + found = s.find("token("); + if (found != string::npos){ + int end = s.find(",", found); + string sname = s.substr(found + 6,end - found - 6); + int previous = end+1; + end = s.find(",",previous); + string stypes = s.substr(previous,end - previous); + previous = end+1; + end = s.find(",",previous); + string spt = s.substr(previous,end - previous); + int power, toughness; + parsePowerToughness(spt,&power, &toughness); + string sabilities = s.substr(end+1); + int multiplier = 1; + found = s.find("*"); + if (found != string::npos)multiplier = atoi(s.substr(found+1).c_str()); + ATokenCreator * tok = NEW ATokenCreator(id,card,NULL,sname,stypes,power,toughness,sabilities,0, multiplier); + tok->oneShot = 1; + return tok; + } + + + //MoveTo Move a card from a zone to another + found = s.find("moveto("); + if (found != string::npos){ + int end = s.find(")",found+1); + string szone = s.substr(found + 7,end - found - 7); + MTGAbility * a = NEW AAMover(id,card,target,szone); + a->oneShot = 1; + return a; + + } + + //Copy a target + found = s.find("copy "); + if (found != string::npos){ + MTGAbility * a = NEW AACopier(id,card,target); + a->oneShot = 1; + return a; + } + + + //Bury, destroy + string destroys[] = {"bury","destroy"}; + int destroyTypes[]= {1, 0}; + for (int i = 0; i < 2; ++i){ + found = s.find(destroys[i]); + if (found != string::npos){ + int bury = destroyTypes[i]; + if (trigger){ + if (bury){ + BuryEvent * action = NEW BuryEvent(); + return NEW GenericTriggeredAbility(id, card,trigger,action); + } + return NULL; + } + MTGAbility * a = NEW AADestroyer(id,card,target,bury); + a->oneShot = 1; + return a; + } + } + + //Damage + found = s.find("damage"); + if (found != string::npos){ + unsigned int start = s.find(":",found); + if (start == string::npos) start = s.find(" ",found); + unsigned int end = s.find(" ",start); + int damage; + if (end != string::npos){ + damage = atoi(s.substr(start+1,end-start-1).c_str()); + }else{ + damage = atoi(s.substr(start+1).c_str()); + } + + Damageable * d = NULL; + if (spell) d = spell->getNextDamageableTarget(); + if (s.find("controller") != string::npos) d = card->controller(); + MTGAbility * a = NEW AADamager(id,card,d, damage); + a->oneShot = 1; + return a; + } + + + //gain/lose life + found = s.find("life:"); + if (found != string::npos){ + unsigned int start = found+4; + unsigned int end = s.find(" ",start); + int life; + if (end != string::npos){ + life = atoi(s.substr(start+1,end-start-1).c_str()); + }else{ + life = atoi(s.substr(start+1).c_str()); + } + + MTGAbility * a = NEW AALifer(id,card,card,life); + a->oneShot = 1; + return a; + } + + //Draw + found = s.find("draw:"); + 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 (trigger){ + DrawEvent * action = NEW DrawEvent(card->controller(),nbcards); + return NEW GenericTriggeredAbility(id, card,trigger,action); + } + + MTGAbility * a = NEW AADrawer(id,card,NULL,nbcards); + a->oneShot = 1; + return a; + } + + //Deplete + found = s.find("deplete:"); + 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()); + } + Player * player = NULL; + if (spell) player = spell->getNextPlayerTarget(); + MTGAbility * a = NEW AADepleter(id,card,player,nbcards); + a->oneShot = 1; + return a; + } + + + /* + //CannotBeBlockedBy + found = s.find("cantbeblockedby("); + if (found != string::npos){ + int end = s.find(")",found); + string starget = s.substr(16, end - 16); + TargetChooserFactory tcf; + tc = tcf.createTargetChooser(starget,card); + return NULL; //NEW ACantBlock(tc); //hu ? CantBlock(tc); + } + +*/ + //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()); + } + + Player * player = NULL; + if (spell) player = spell->getNextPlayerTarget(); + if (!player) player = GameObserver::GetInstance()->currentlyActing(); + MTGAbility * a = NEW AARandomDiscarder (id, card, player,nbcards); + a->oneShot = 1; + return a; + } + + + + //rampage + found = s.find("rampage("); + if (found != string::npos){ + int end = s.find(",", found); + string spt = s.substr(8,end - 1); + int power, toughness; + if (parsePowerToughness(spt,&power, &toughness)){ + int MaxOpponent = atoi(s.substr(end+1,end+2).c_str()); + return NEW ARampageAbility(id,card,power,toughness,MaxOpponent); + } + return NULL; + } +/* + + //counter + found = s.find("counter("); + if (found != string::npos){ + int end = s.find(")", found); + string spt = s.substr(9,end - 1); + int power, toughness; + if ( parsePowerToughness(spt,&power, &toughness)){ + if(tc){ + //TODO + }else{ + return NEW ACounters(id,card,target,power,toughness); + } + } + return NULL; + } + +*/ + + + //Change Power/Toughness + int power, toughness; + if ( parsePowerToughness(s,&power, &toughness)){ + if (!activated){ + if(card->hasType("instant") || card->hasType("sorcery")){ + return NEW AInstantPowerToughnessModifierUntilEOT(id, card, target,power,toughness); + } + return NEW APowerToughnessModifier(id, card, target,power,toughness); + } + return NEW APowerToughnessModifierUntilEndOfTurn(id,card,target,power,toughness); + } + + + + //Mana Producer + found = s.find("add"); + if (found != string::npos){ + ManaCost * output = ManaCost::parseManaCost(s.substr(found)); + MTGAbility * a = NEW AManaProducer(id, target, output); + a->oneShot = 1; + return a; + } + + + //Gain/loose Ability + for (int j = 0; j < Constants::NB_BASIC_ABILITIES; j++){ + found = s.find(Constants::MTGBasicAbilities[j]); + if (found!= string::npos){ + int modifier = 1; + if (found > 0 && s[found-1] == '-') modifier = 0; + if (!activated){ + if(card->hasType("instant") || card->hasType("sorcery") ) return NEW AInstantBasicAbilityModifierUntilEOT(id, card,target, j,modifier); + return NEW ABasicAbilityModifier(id, card,target, j,modifier); + } + return NEW ABasicAbilityAuraModifierUntilEOT(id, card,target, NULL,j,modifier); + } + } + + //Tapper (icy manipulator) + found = s.find("tap"); + if (found != string::npos){ + MTGAbility * a = NEW AATapper(id,card,target); + a->oneShot = 1; + return a; + } + + return NULL; + +} + +//Tells the AI if the ability should target itself or an ennemy +int AbilityFactory::abilityEfficiency(MTGAbility * a, Player * p, int mode){ + if (!a) return BAKA_EFFECT_DONTKNOW; + + GenericTargetAbility * gta = dynamic_cast(a); + if (gta) { + if (mode == MODE_PUTINTOPLAY) return BAKA_EFFECT_GOOD; + return abilityEfficiency(gta->ability,p, mode); + } + + GenericActivatedAbility * gaa = dynamic_cast(a); + if (gaa) { + if (mode == MODE_PUTINTOPLAY) return BAKA_EFFECT_GOOD; + return abilityEfficiency(gaa->ability,p, mode); + } + + MultiAbility * mua = dynamic_cast(a); + if (mua) return abilityEfficiency(mua->abilities[0],p, mode); + + MayAbility * maya = dynamic_cast(a); + if (maya) return abilityEfficiency(maya->ability,p, mode); + + GameObserver * g = GameObserver::GetInstance(); + + ALord * alord = dynamic_cast(a); + if (alord) { + int myCards = countCards(alord->tc, p); + int theirCards = countCards(alord->tc, p->opponent()); + int efficiency = abilityEfficiency(alord->ability,p, mode); + if (myCards > theirCards) return efficiency; + return -efficiency; + } + + AAsLongAs * ala = dynamic_cast(a); + if (ala) { + return abilityEfficiency(ala->ability,p, mode); + } + + AForeach * af = dynamic_cast(a); + if (af) { + return abilityEfficiency(af->ability,p, mode); + } + + AAFizzler * aaf = dynamic_cast(a); + if (aaf){ + return BAKA_EFFECT_BAD; + } + + AAUntapper * aau = dynamic_cast(a); + if (aau){ + return BAKA_EFFECT_GOOD; + } + + + AATapper * aat = dynamic_cast(a); + if (aat){ + return BAKA_EFFECT_BAD; + } + + + ATokenCreator * aatc = dynamic_cast(a); + if (aatc){ + return BAKA_EFFECT_GOOD; + } + + + AAMover * aam = dynamic_cast(a); + if (aam){ + //TODO + return BAKA_EFFECT_BAD; + } + + + AACopier * aac = dynamic_cast(a); + if (aac){ + return BAKA_EFFECT_GOOD; + } + + + AADestroyer * aad = dynamic_cast(a); + if (aad){ + return BAKA_EFFECT_BAD; + } + + AStandardRegenerate * asr = dynamic_cast(a); + if (asr){ + return BAKA_EFFECT_GOOD; + } + + AADamager * aada = dynamic_cast(a); + if (aada){ + return BAKA_EFFECT_BAD; + } + + + AALifer * aal = dynamic_cast(a); + if (aal){ + if (aal->life > 0) return BAKA_EFFECT_GOOD; + return BAKA_EFFECT_BAD; + } + + + AADepleter * aade = dynamic_cast(a); + if (aade){ + return BAKA_EFFECT_BAD; + } + + + AADrawer * aadr = dynamic_cast(a); + if (aadr){ + return BAKA_EFFECT_GOOD; + } + + AARandomDiscarder * aard = dynamic_cast(a); + if (aard){ + return BAKA_EFFECT_BAD; + } + + ARampageAbility * ara = dynamic_cast(a); + if (ara){ + return BAKA_EFFECT_GOOD; + } + + AInstantPowerToughnessModifierUntilEOT * aiptm = dynamic_cast(a); + if (aiptm){ + if (aiptm->power>=0 && aiptm->toughness>=0) return BAKA_EFFECT_GOOD; + return BAKA_EFFECT_BAD; + } + + APowerToughnessModifier * aptm = dynamic_cast(a); + if (aptm){ + if (aptm->power>=0 && aptm->toughness>=0) return BAKA_EFFECT_GOOD; + return BAKA_EFFECT_BAD; + } + + APowerToughnessModifierUntilEndOfTurn * aptmu = dynamic_cast(a); + if (aptmu){ + if (aptmu->power>=0 && aptmu->toughness>=0) return BAKA_EFFECT_GOOD; + return BAKA_EFFECT_BAD; + } + + map badAbilities; + badAbilities[Constants::CANTATTACK] = true; + badAbilities[Constants::CANTBLOCK] = true; + badAbilities[Constants::CLOUD] = true; + badAbilities[Constants::DEFENDER] = true; + badAbilities[Constants::DOESNOTUNTAP] = true; + badAbilities[Constants::MUSTATTACK] = true; + + AInstantBasicAbilityModifierUntilEOT * aibam = dynamic_cast(a); + if (aibam){ + int result = BAKA_EFFECT_GOOD; + if (badAbilities[aibam->ability]) result = BAKA_EFFECT_BAD; + if (aibam->value <= 0) result = -result; + return result; + } + + ABasicAbilityModifier * abam = dynamic_cast(a); + if (abam){ + int result = BAKA_EFFECT_GOOD; + if (badAbilities[abam->ability]) result = BAKA_EFFECT_BAD; + if (abam->modifier <= 0) result = -result; + return result; + } + + ABasicAbilityAuraModifierUntilEOT * abamu = dynamic_cast(a); + if (abamu){ + int result = BAKA_EFFECT_GOOD; + if (badAbilities[abamu->ability]) result = BAKA_EFFECT_BAD; + if (abamu->value <= 0) result = -result; + return result; + } + + AManaProducer * amp = dynamic_cast(a); + if (amp) return BAKA_EFFECT_GOOD; + + return BAKA_EFFECT_DONTKNOW; +} + //Some basic functionalities that can be added automatically in the text file /* * Several objects are computed from the text string, and have a direct influence on what action we should take @@ -215,11 +731,10 @@ Trigger * AbilityFactory::parseTrigger(string magicText){ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card){ int dryMode = 0; if (!spell) dryMode = 1; - int dryModeResultSet = 0; - int dryModeResult = 0; GameObserver * game = GameObserver::GetInstance(); - if (!card) card = spell->source; + if (!card && spell) card = spell->source; + if (!card) return 0; MTGCardInstance * target = card->target; if (!target) target = card; string magicText = card->magicText; @@ -233,7 +748,7 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card){ unsigned int found; int result = id; - + while (magicText.size()){ found = magicText.find("\n"); if (found != string::npos){ @@ -243,857 +758,29 @@ int AbilityFactory::magicText(int id, Spell * spell, MTGCardInstance * card){ line = magicText; magicText = ""; } -#if defined (WIN32) || defined (LINUX) - char buf[4096]; - sprintf(buf, "AUTO ACTION: %s\n", line.c_str()); - OutputDebugString(buf); -#endif - - MultiAbility * multi = NULL; - unsigned int delimiter = line.find("}:"); - ManaCost * cost = NULL; - if (delimiter!= string::npos){ - cost = ManaCost::parseManaCost(line.substr(0,delimiter+1),NULL,card); - } - OutputDebugString("Parsing cost\n"); - if (cost && cost->isNull()){ - OutputDebugString("Cost is null\n"); - SAFE_DELETE(cost); - } - - int may = 0; - if (line.find("may ") != string::npos) may = 1; - - int doTap = 0; - //Tap in the cost ? - if (line.find("{t}") != string::npos) doTap = 1; - - TargetChooser * tc = NULL; - TargetChooser * lordTargets = NULL; - Trigger * trigger = NULL; - while (line.size()){ - string s; - found = line.find("&&"); - if (found != string::npos){ - s = line.substr(0,found); - line = line.substr(found+2); - if (!multi){ - OutputDebugString("Multi initializing\n"); - if (!dryMode) { - multi = NEW MultiAbility(id, card, cost,doTap); - game->addObserver(multi); - } - OutputDebugString("Multi initialized\n"); - } - }else{ - s = line; - line = ""; - } - - tc = NULL; - lordTargets = NULL; - int lordIncludeSelf = 1; - int lordType = 0; - string lordTargetsString; - - trigger = parseTrigger(s); - //Dirty way to remove the trigger text (could get in the way) - if (trigger){ - found = s.find(":"); - s = s.substr(found+1); - } - - int all = 0; - //Target Abilities - found = s.find("target("); - if (found != string::npos){ - int end = s.find(")", found); - string starget = s.substr(found + 7,end - found - 7); - TargetChooserFactory tcf; - tc = tcf.createTargetChooser(starget, card); - - }else{ - found = s.find("all("); - if (found != string::npos){ - all = 1; - int end = s.find(")", found); - string starget = s.substr(found + 4,end - found -4); - TargetChooserFactory tcf; - tc = tcf.createTargetChooser(starget, card); - } - } - - - //Lord - found = s.find("lord("); - if (found != string::npos){ - if (dryMode) { - dryModeResult = BAKA_EFFECT_GOOD; - dryModeResultSet = 1; - break; - } - unsigned int end = s.find(")", found+5); - if (end != string::npos){ - lordTargetsString = s.substr(found+5,end-found-5).c_str(); - lordType = PARSER_LORD; - } - } - found = s.find("foreach("); - if (found != string::npos){ - if (dryMode) { - dryModeResult = BAKA_EFFECT_GOOD; - dryModeResultSet = 1; - break; - } - unsigned int end = s.find(")", found+8); - if (end != string::npos){ - lordTargetsString = s.substr(found+8,end-found-8).c_str(); - lordType = PARSER_FOREACH; - } - } - found = s.find("aslongas("); - if (found != string::npos){ - if (dryMode) { - dryModeResult = BAKA_EFFECT_GOOD; - dryModeResultSet = 1; - break; - } - unsigned int end = s.find(")", found+9); - if (end != string::npos){ - lordTargetsString = s.substr(found+9,end-found-9).c_str(); - lordType = PARSER_ASLONGAS; - } - } - if (lordTargetsString.size()){ - TargetChooserFactory tcf; - lordTargets = tcf.createTargetChooser(lordTargetsString, card); - if (s.find("other") != string::npos) lordIncludeSelf = 0; - } - - - //Fizzle (counterspell...) - found = s.find("fizzle"); - if (found != string::npos){ - if (dryMode) { - dryModeResult = BAKA_EFFECT_BAD; - dryModeResultSet = 1; - break; - } - if (tc){ - //TODO - }else{ - Spell * starget = spell->getNextSpellTarget(); - if (starget) game->mLayers->stackLayer()->Fizzle(starget); - } - result++; - continue; - } - - - //Untapper (Ley Druid...) - found = s.find("untap"); - if (found != string::npos){ - if (dryMode) { - dryModeResult = BAKA_EFFECT_GOOD; - dryModeResultSet = 1; - break; - } - if (tc){ - if (all){ - UntapAll(tc); - delete tc; - }else{ - game->addObserver(NEW AUntaper(id, card, cost, tc)); - } - }else{ - if (cost){ - game->addObserver(NEW AUntapManaBlocker(id, card, cost)); - }else{ - target->untap(); - } - } - result++; - continue; - } - - - //Regeneration - found = s.find("}:regenerate"); - if (found != string::npos){ - if (dryMode) { - dryModeResult = BAKA_EFFECT_GOOD; - dryModeResultSet = 1; - break; - } - - if (lordTargets){ - game->addObserver(NEW ALord(id,card,lordTargets,lordIncludeSelf,0,0,-1,cost)); - }else{ - if (tc){ - //TODO - }else{ - game->addObserver(NEW AStandardRegenerate(id, card, target, cost)); - //TODO death ward ! - } - } - result++; - continue; - } - - - //Token creator. Name, type, p/t, abilities - found = s.find("token("); - if (found != string::npos){ - if (dryMode) { - dryModeResult = BAKA_EFFECT_GOOD; - dryModeResultSet = 1; - break; - } - int end = s.find(",", found); - string sname = s.substr(found + 6,end - found - 6); - int previous = end+1; - end = s.find(",",previous); - string stypes = s.substr(previous,end - previous); - previous = end+1; - end = s.find(",",previous); - string spt = s.substr(previous,end - previous); - int power, toughness; - parsePowerToughness(spt,&power, &toughness); - string sabilities = s.substr(end+1); - int multiplier = 1; - found = s.find("*"); - if (found != string::npos)multiplier = atoi(s.substr(found+1).c_str()); - if (lordType == PARSER_FOREACH){ - int nbtoken = countCards(lordTargets); - ATokenCreator * tok = NEW ATokenCreator(id,card,cost,sname,stypes,power,toughness,sabilities,doTap); - for (int i=0; i < nbtoken; i++){ - tok->resolve(); - } - delete tok; - }else{ - if(cost || doTap){ - game->addObserver(NEW ATokenCreator(id,card,cost,sname,stypes,power,toughness,sabilities,doTap)); - }else{ - ATokenCreator * tok = NEW ATokenCreator(id,card,cost,sname,stypes,power,toughness,sabilities,doTap); - for (int i=0; i < multiplier; i++){ - tok->resolve(); - } - delete tok; - } - } - result++; - continue; - } - - //MoveTo Move a card from a zone to another - found = s.find("moveto("); - if (found != string::npos){ - if (dryMode) { - dryModeResult = BAKA_EFFECT_BAD; - dryModeResultSet = 1; - break; - } //TODO : depends on where from, where to... - int end = s.find(")",found+1); - string szone = s.substr(found + 7,end - found - 7); - if (tc){ - if (all){ - moveAll(tc,szone); - delete(tc); - }else{ - AZoneMover * a = NEW AZoneMover(id,card,tc,szone,cost,doTap); - if (may){ - game->addObserver(NEW MayAbility(id,a,card)); - }else{ - game->addObserver(a); - } - } - }else{ - if (cost){ - MTGAbility * a = NEW AZoneSelfMover(id,card,szone,cost,doTap); - if (may){ - game->addObserver(NEW MayAbility(id,a,card)); - }else{ - game->addObserver(a); - } - }else{ - AZoneMover::moveTarget(target,szone,card); - } - } - result++; - continue; - } - - //Copy a target - found = s.find("copy "); - if (found != string::npos){ - if (dryMode) { - dryModeResult = BAKA_EFFECT_GOOD; - dryModeResultSet = 1; - break; - } //TODO : - if (tc){ - ACopier * a = NEW ACopier(id,card,tc,cost); - if (may){ - game->addObserver(NEW MayAbility(id,a,card)); - OutputDebugString("may!\n"); - }else{ - game->addObserver(a); - } - }else{ - //TODO - } - result++; - continue; - } - - //Bury - found = s.find("bury"); - if (found != string::npos){ - if (trigger){ - if (dryMode) { - dryModeResult = BAKA_EFFECT_BAD; - dryModeResultSet = 1; - break; - } - BuryEvent * action = NEW BuryEvent(); - game->addObserver(NEW GenericTriggeredAbility(id, card,trigger,action)); - }else{ - if (all){ - if (dryMode){ - int myNbCards = countCards(tc,card->controller()); - int opponentNbCards = countCards(tc, card->controller()->opponent()); - int myCardsPower = countCards(tc,card->controller(),COUNT_POWER); - int opponentCardsPower = countCards(tc, card->controller()->opponent(),COUNT_POWER); - SAFE_DELETE(tc); - if (myNbCards < opponentNbCards || myCardsPower < opponentCardsPower) dryModeResult = BAKA_EFFECT_GOOD; - else dryModeResult = BAKA_EFFECT_BAD; - break; - }else{ - if (cost){ - game->addObserver(NEW AAllDestroyer(id, card,tc,1,cost,doTap)); - }else{ - this->destroyAllInPlay(tc,1); - SAFE_DELETE(tc); - } - } - }else{ - if (dryMode){ - dryModeResult = BAKA_EFFECT_BAD; - break; - } - if (tc){ - game->addObserver(NEW ABurier(id, card,tc)); - }else{ - target->bury(); - } - } - } - result++; - continue; - } - - //Destroy - found = s.find("destroy"); - if (found != string::npos){ - - if (all){ - if (dryMode){ - int myNbCards = countCards(tc,card->controller()); - int opponentNbCards = countCards(tc, card->controller()->opponent()); - int myCardsPower = countCards(tc,card->controller(),COUNT_POWER); - int opponentCardsPower = countCards(tc, card->controller()->opponent(),COUNT_POWER); - SAFE_DELETE(tc); - if (myNbCards < opponentNbCards || myCardsPower < opponentCardsPower) dryModeResult = BAKA_EFFECT_GOOD; - else dryModeResult = BAKA_EFFECT_BAD; - break; - }else{ - if (cost){ - game->addObserver(NEW AAllDestroyer(id, card,tc,0,cost,doTap)); - }else{ - this->destroyAllInPlay(tc); - SAFE_DELETE(tc); - } - } - }else{ - if (dryMode){ - dryModeResult = BAKA_EFFECT_BAD; - break; - } - if (tc){ - game->addObserver(NEW ADestroyer(id, card,tc,0,cost)); - }else{ - target->destroy(); - } - } - result++; - continue; - } - - //Damage - found = s.find("damage"); - if (found != string::npos){ - unsigned int start = s.find(":",found); - if (start == string::npos) start = s.find(" ",found); - unsigned int end = s.find(" ",start); - int damage; - if (end != string::npos){ - damage = atoi(s.substr(start+1,end-start-1).c_str()); - }else{ - damage = atoi(s.substr(start+1).c_str()); - } - if (dryMode){ - dryModeResult = BAKA_EFFECT_BAD; - break; - } - if (lordType == PARSER_FOREACH){ - int multiplier = countCards(lordTargets); - game->mLayers->stackLayer()->addDamage(card,spell->getNextDamageableTarget(),(damage*multiplier)); - }else{ - if (tc){ - if (all){ - if (cost){ - MTGAbility * a = NEW AAllDamager(id, card, cost, damage, tc,doTap); - game->addObserver(a); - }else{ - damageAll(tc,damage); - delete tc; - } - }else{ - MTGAbility * a = NEW ADamager(id, card, cost, damage, tc,doTap); - if (multi){ - multi->Add(a); - }else{ - game->addObserver(a); - } - } - }else{ - if (multi){ - Damageable * target = parseCollateralTarget(card, s); - if (!target) target = spell->getNextDamageableTarget(); - multi->Add(NEW DamageEvent(card,target,damage)); - }else{ - game->mLayers->stackLayer()->addDamage(card,spell->getNextDamageableTarget(), damage); - } - } - } - result++; - continue; - } - - //gain/lose life - found = s.find("life:"); - if (found != string::npos){ - unsigned int start = found+4; - unsigned int end = s.find(" ",start); - int life; - if (end != string::npos){ - life = atoi(s.substr(start+1,end-start-1).c_str()); - }else{ - life = atoi(s.substr(start+1).c_str()); - } - if (dryMode){ - dryModeResult = BAKA_EFFECT_GOOD; - break; - } - if (lordType == PARSER_FOREACH){ - int multiplier = countCards(lordTargets); - card->controller()->life+=multiplier; - }else{ - if (tc){ - //TODO ? - }else{ - if (!cost && !doTap){ - card->controller()->life+=life; - }else{ - game->addObserver(NEW ALifeGiver(id, card,cost, life, doTap)); - } - } - } - result++; - continue; - } - - //Draw - found = s.find("draw:"); - if (found != string::npos){ - unsigned int start = s.find(":",found); - unsigned int end = s.find(" ",start); - int nbcards; - 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_GOOD; - break; - } - if (lordType == PARSER_FOREACH){ - int multiplier = countCards(lordTargets); - game->mLayers->stackLayer()->addDraw(card->controller(),multiplier);; - }else{ - if (trigger){ - DrawEvent * action = NEW DrawEvent(card->controller(),nbcards); - game->addObserver(NEW GenericTriggeredAbility(id, card,trigger,action)); - }else{ - if (tc){ - //TODO ? - }else{ - if (cost || doTap){ - game->addObserver(NEW ADrawer(id,card,cost,nbcards,doTap)); - }else{ - game->mLayers->stackLayer()->addDraw(card->controller(),nbcards); - } - } - } - } - result++; - continue; - } - - //Deplete - found = s.find("deplete:"); - 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){ - game->addObserver (NEW ADeplete(id,card,cost,nbcards,tc,doTap)); - }else{ - Player * player = spell->getNextPlayerTarget(); - MTGLibrary * library = player->game->library; - for (int i = 0; i < nbcards; i++){ - if (library->nb_cards) - player->game->putInZone(library->cards[library->nb_cards-1],library, player->game->graveyard); - } - } - } - result++; - continue; - } - - //CannotBeBlockedBy - found = s.find("cantbeblockedby("); - if (found != string::npos){ - int end = s.find(")",found); - string starget = s.substr(16, end - 16); - TargetChooserFactory tcf; - tc = tcf.createTargetChooser(starget,card); - CantBlock(tc); - result++; - 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){ - game->addObserver (NEW ADiscard(id,card,cost,nbcards,tc,doTap)); - }else{ - Player * player = spell->getNextPlayerTarget(); - if(player){ - for (int i=0; igame->discardRandom(player->game->hand); - } - }else{ - for (int i=0; icurrentlyActing()->game->discardRandom(game->currentlyActing()->game->hand); - } - } - } - } - result++; - continue; - } - - //rampage - found = s.find("rampage("); - if (found != string::npos){ - if (dryMode) { - dryModeResult = BAKA_EFFECT_GOOD; - dryModeResultSet = 1; - break; - } - int end = s.find(",", found); - string spt = s.substr(8,end - 1); - int power, toughness; - if ( parsePowerToughness(spt,&power, &toughness)){ - if (dryMode){ - if (power >=0 && toughness >= 0 ) { - dryModeResult = BAKA_EFFECT_GOOD; - }else{ - dryModeResult = BAKA_EFFECT_BAD; - } - break; - } - int MaxOpponent = atoi(s.substr(end+1,end+2).c_str()); - if(tc){ - //TODO?? - }else{ - game->addObserver(NEW ARampageAbility(id,card,power,toughness,MaxOpponent)); - - } - result++; - continue; - } - } - - - //counter - found = s.find("counter("); - if (found != string::npos){ - if (dryMode) { - dryModeResult = BAKA_EFFECT_GOOD; - dryModeResultSet = 1; - break; - } - int end = s.find(")", found); - string spt = s.substr(9,end - 1); - int power, toughness; - if ( parsePowerToughness(spt,&power, &toughness)){ - if (dryMode){ - if (power >=0 && toughness >= 0 ) { - dryModeResult = BAKA_EFFECT_GOOD; - }else{ - dryModeResult = BAKA_EFFECT_BAD; - } - break; - } - if(tc){ - //TODO - - }else{ - game->addObserver(NEW ACounters(id,card,target,power,toughness)); - - } - result++; - continue; - } - } - - - //Change Power/Toughness - int power, toughness; - if ( parsePowerToughness(s,&power, &toughness)){ - if (dryMode){ - if (power >=0 && toughness >= 0 ) { - dryModeResult = BAKA_EFFECT_GOOD; - }else{ - dryModeResult = BAKA_EFFECT_BAD; - } - break; - } - int limit = 0; - unsigned int limit_str = s.find("limit:"); - if (limit_str != string::npos){ - limit = atoi(s.substr(limit_str+6).c_str()); - } - - - if (lordType == PARSER_LORD){ - if (!cost){ - if(card->hasType("instant") || card->hasType("sorcery")){ - game->addObserver(NEW ALordUEOT(id,card,lordTargets,lordIncludeSelf,power,toughness)); - }else{ - game->addObserver(NEW ALord(id,card,lordTargets,lordIncludeSelf,power,toughness)); - } - }else{ - //TODO - } - }else{ - if(tc){ - game->addObserver(NEW ATargetterPowerToughnessModifierUntilEOT(id, card,power,toughness, cost, tc,doTap)); - }else{ - if (lordType == PARSER_FOREACH){ - game->addObserver(NEW AForeach(id,card,target,lordTargets,lordIncludeSelf,power,toughness)); - }else if (lordType == PARSER_ASLONGAS){ - game->addObserver(NEW AKirdApe(id,card,lordTargets,lordIncludeSelf,power,toughness)); - }else{ - if (!cost){ - if(card->hasType("enchantment")){ - game->addObserver(NEW APowerToughnessModifier(id, card, target,power,toughness)); - }else{ - game->addObserver(NEW AInstantPowerToughnessModifierUntilEOT(id, card, target,power,toughness)); - } - }else{ - game->addObserver(NEW APowerToughnessModifierUntilEndOfTurn(id, card, target,power,toughness, cost, limit)); - } - } - } - } - result++; - continue; - } - - //Mana Producer - found = s.find("add"); - if (found != string::npos){ - if (dryMode){ - dryModeResult = BAKA_EFFECT_GOOD; - break; - } - ManaCost * input = ManaCost::parseManaCost(s.substr(0,found)); - ManaCost * output = ManaCost::parseManaCost(s.substr(found)); - if (!input->isNull() || doTap){ - SAFE_DELETE(cost); //erk - if (input->isNull()){ - SAFE_DELETE(input); - } - MTGAbility * a = NEW AManaProducer(id, target, output, input,doTap); - - if (lordType == PARSER_FOREACH){ - ManaCost * FinalOutput = NEW ManaCost(); - int multiplier = countCards(lordTargets); - for (int i = 0; i < Constants::MTG_NB_COLORS; i++){ - if (output->hasColor(i)){ - FinalOutput->add(i,multiplier); - } - } - game->addObserver (NEW AManaProducer(id, target,FinalOutput, input,doTap)); - }else{ - if (multi){ - multi->Add(a); - }else{ - game->addObserver(a); - } - } - }else{ - OutputDebugString ("uh oh\n"); - if (lordType == PARSER_FOREACH){ - ManaCost * FinalOutput = NEW ManaCost(); - int multiplier = countCards(lordTargets); - for (int i = 0; i < Constants::MTG_NB_COLORS; i++){ - if (output->hasColor(i)){ - FinalOutput->add(i,multiplier); - } - } - card->controller()->getManaPool()->add(FinalOutput); - delete FinalOutput; - }else{ - card->controller()->getManaPool()->add(output); - delete output; - } - } - result++; - continue; - } - - //Gain/loose Ability - for (int j = 0; j < Constants::NB_BASIC_ABILITIES; j++){ - found = s.find(Constants::MTGBasicAbilities[j]); - if (found!= string::npos){ - int modifier = 1; - if (found > 0 && s[found-1] == '-') modifier = 0; - if (dryMode){ - if (j == Constants::DEFENDER){ - if (modifier == 1) dryModeResult = BAKA_EFFECT_BAD; - else dryModeResult = BAKA_EFFECT_GOOD; - }else{ - if (modifier == 1) dryModeResult = BAKA_EFFECT_GOOD; - else dryModeResult = BAKA_EFFECT_BAD; - } - dryModeResultSet = 1; - break; - }else{ - if (lordType == PARSER_LORD){ - if(card->hasType("instant") || card->hasType("sorcery")){ - game->addObserver(NEW ALordUEOT(id,card,lordTargets,lordIncludeSelf,0,0,j,0,modifier)); - }else{ - game->addObserver(NEW ALord(id,card,lordTargets,lordIncludeSelf,0,0,j,0,modifier)); - } - }else if (lordType == PARSER_ASLONGAS){ - game->addObserver(NEW AKirdApe(id,card,lordTargets,lordIncludeSelf,0,0,j,modifier)); - }else{ - if (tc){ - game->addObserver(NEW ABasicAbilityModifierUntilEOT(id, card, j, cost,tc, modifier,doTap)); - }else{ - if (!cost){ - if(card->hasType("enchantment")){ - game->addObserver(NEW ABasicAbilityModifier(id, card,target, j,modifier)); - }else{ - game->addObserver(NEW AInstantBasicAbilityModifierUntilEOT(id, card,target, j,modifier)); - } - }else{ - game->addObserver(NEW ABasicAbilityAuraModifierUntilEOT(id, card,target, cost,j,modifier)); - } - } - } - result++; - continue; - } - } - } - if (dryModeResultSet) break; - - //Tapper (icy manipulator) - found = s.find("tap"); - if (found != string::npos){ - if (dryMode){ - dryModeResult = BAKA_EFFECT_GOOD; - break; - } - if (tc){ - if (all){ - TapAll(tc); - delete tc; - }else{ - game->addObserver(NEW ATapper(id, card, cost, tc)); - } - }else{ - target->tap(); - } - result++; - continue; - } - -#if defined (WIN32) || defined (LINUX) - char buf[4096]; - sprintf(buf, "AUTO ACTION PARSED: %s\n", line.c_str()); - OutputDebugString(buf); -#endif - } + MTGAbility * a = parseMagicLine(line, result, spell, card); if (dryMode){ - SAFE_DELETE(tc); - SAFE_DELETE(lordTargets); - SAFE_DELETE(multi); - SAFE_DELETE(cost); - SAFE_DELETE(trigger); - return dryModeResult; + result = abilityEfficiency(a, card->controller(),MODE_PUTINTOPLAY); + SAFE_DELETE(a); + return result; + } + + if (a){ + if (a->oneShot){ + a->resolve(); + delete(a); + }else{ + a->addToGame(); + } + result++; + }else{ + OutputDebugString("ERROR: Parser returned NULL\n"); + //return result; } } - return result; + } void AbilityFactory::addAbilities(int _id, Spell * spell){ @@ -1229,12 +916,6 @@ void AbilityFactory::addAbilities(int _id, Spell * spell){ game->addObserver(ability); break; } - case 1151: //Deathgrip - { - int _cost[] = {Constants::MTG_COLOR_BLACK, 2}; - game->addObserver(NEW ASpellCounterEnchantment(_id, card, NEW ManaCost(_cost, 1),Constants::MTG_COLOR_GREEN)); - break; - } case 1152: //Deathlace { if (card->target){ @@ -1341,12 +1022,6 @@ void AbilityFactory::addAbilities(int _id, Spell * spell){ game->addObserver(NEW AKudzu(id, card, card->target)); break; } - case 1256: //LifeForce - { - int _cost[] = {Constants::MTG_COLOR_GREEN, 2}; - game->addObserver(NEW ASpellCounterEnchantment(_id, card, NEW ManaCost(_cost, 1),Constants::MTG_COLOR_BLACK)); - break; - } case 1257: //Lifelace { if (card->target){ @@ -1581,7 +1256,7 @@ void AbilityFactory::addAbilities(int _id, Spell * spell){ case 1214: //Pirate Ship { game->addObserver(NEW AStrongLandLinkCreature(_id, card, "island")); - game->addObserver(NEW ADamager(_id+1, card, NEW ManaCost(), 1)); + game->addObserver(NEW TADamager(_id+1, card, NEW ManaCost(), 1)); break; } case 1218: //Psychic Venom @@ -1984,7 +1659,6 @@ void AbilityFactory::addAbilities(int _id, Spell * spell){ int x = spell->cost->getConvertedCost() - 4; TargetChooserFactory tcf; lordTargets = tcf.createTargetChooser("creature", card); - game->addObserver (NEW ALordUEOT(id,card,lordTargets,0,x,-x)); break; } case 129523: //Demon's Horn @@ -2285,21 +1959,33 @@ MTGAbility::MTGAbility(int id, MTGCardInstance * card):ActionElement(id){ aType = MTGAbility::UNKNOWN; cost = NULL; forceDestroy = 0; + oneShot = 0; } -MTGAbility::MTGAbility(int id, MTGCardInstance * _source,Damageable * _target ):ActionElement(id){ +MTGAbility::MTGAbility(int id, MTGCardInstance * _source,Targetable * _target ):ActionElement(id){ game = GameObserver::GetInstance(); source = _source; target = _target; aType = MTGAbility::UNKNOWN; cost = NULL; forceDestroy = 0; + oneShot = 0; } MTGAbility::~MTGAbility(){ SAFE_DELETE(cost); } +int MTGAbility::addToGame(){ + GameObserver::GetInstance()->addObserver(this); + return 1; +} + +int MTGAbility::removeFromGame(){ + GameObserver::GetInstance()->removeObserver(this); + return 1; +} + //returns 1 if this ability needs to be removed from the list of active abilities int MTGAbility::testDestroy(){ if (game->mLayers->stackLayer()->has(this)) return 0; @@ -2413,10 +2099,12 @@ ostream& ActivatedAbility::toString(ostream& out) const TargetAbility::TargetAbility(int id, MTGCardInstance * card, TargetChooser * _tc,ManaCost * _cost, int _playerturnonly,int tap):ActivatedAbility(id, card,_cost,_playerturnonly, tap){ tc = _tc; + ability = NULL; } TargetAbility::TargetAbility(int id, MTGCardInstance * card,ManaCost * _cost, int _playerturnonly,int tap):ActivatedAbility(id, card,_cost,_playerturnonly, tap){ tc = NULL; + ability = NULL; } void TargetAbility::Update(float dt){ @@ -2472,6 +2160,24 @@ void TargetAbility::Render(){ //TODO ? } +int TargetAbility::resolve(){ + Targetable * t = tc->getNextTarget(); + if (t && ability){ + ability->target = t; + return ability->resolve(); + } + return 0; +} + +const char * TargetAbility::getMenuText(){ + if (ability) return ability->getMenuText(); + return ActivatedAbility::getMenuText(); +} + +TargetAbility::~TargetAbility(){ + if (!isClone) SAFE_DELETE(ability); +} + ostream& TargetAbility::toString(ostream& out) const { out << "TargetAbility ::: ("; @@ -2481,7 +2187,7 @@ ostream& TargetAbility::toString(ostream& out) const // -TriggeredAbility::TriggeredAbility(int id, MTGCardInstance * card, Damageable * _target):MTGAbility(id,card, _target){ +TriggeredAbility::TriggeredAbility(int id, MTGCardInstance * card, Targetable * _target):MTGAbility(id,card, _target){ } @@ -2543,47 +2249,61 @@ ostream& InstantAbility::toString(ostream& out) const } -void ListMaintainerAbility::Update(float dt){ - map::iterator it=cards.begin(); - while(it != cards.end()){ +void ListMaintainerAbility::updateTargets(){ + //remove invalid ones + map temp; + for (map::iterator it=cards.begin(); it != cards.end(); ++it){ MTGCardInstance * card = (*it).first; - it++; - int doDelete = 1; - for (int i = 0; i < 2; i++){ - Player * p = game->players[i]; - MTGGameZone * zones[] = {p->game->inPlay,p->game->graveyard,p->game->hand}; - for (int k = 0; k < 3; k++){ - //MTGGameZone * zones[] = {p->game->inPlay}; - //for (int k = 0; k < 1; k++){ - MTGGameZone * zone = zones[k]; - if (zone->hasCard(card)){ - doDelete = 0; - break; - } - } - } - if (doDelete || !canBeInList(card)){ - cards.erase(card); - removed(card); - } + if (!canBeInList(card)) temp[card] = true; } + + for (map::iterator it=temp.begin(); it != temp.end(); ++it){ + MTGCardInstance * card = (*it).first; + cards.erase(card); + removed(card); + } + + temp.clear(); + + //add new valid ones for (int i = 0; i < 2; i++){ Player * p = game->players[i]; MTGGameZone * zones[] = {p->game->inPlay,p->game->graveyard,p->game->hand}; for (int k = 0; k < 3; k++){ - // MTGGameZone * zones[] = {p->game->inPlay}; - // for (int k = 0; k < 1; k++){ MTGGameZone * zone = zones[k]; for (int j = 0; j < zone->nb_cards; j++){ - if (canBeInList(zone->cards[j])){ - if(cards.find(zone->cards[j]) == cards.end()){ - cards[zone->cards[j]] = true; - added(zone->cards[j]); - } - } + if (canBeInList(zone->cards[j])){ + if(cards.find(zone->cards[j]) == cards.end()){ + temp[zone->cards[j]] = true; + } + } } } } + + for (map::iterator it=temp.begin(); it != temp.end(); ++it){ + MTGCardInstance * card = (*it).first; + cards[card] = true; + added(card); + } + + temp.clear(); + + for (int i = 0; i < 2; ++i){ + Player * p = game->players[i]; + if (!players[p] && canBeInList(p)){ + players[p] = true; + added(p); + }else if (players[p] && !canBeInList(p)){ + players[p] = false; + removed(p); + } + } + +} + +void ListMaintainerAbility::Update(float dt){ + updateTargets(); } //Destroy the spell -> remove all targets @@ -2611,11 +2331,11 @@ ostream& ListMaintainerAbility::toString(ostream& out) const MTGAbilityBasicFeatures::MTGAbilityBasicFeatures(){ game = GameObserver::GetInstance(); } -MTGAbilityBasicFeatures::MTGAbilityBasicFeatures(MTGCardInstance * _source, Damageable * _target):target(_target),source(_source){ +MTGAbilityBasicFeatures::MTGAbilityBasicFeatures(MTGCardInstance * _source, Targetable * _target):target(_target),source(_source){ if (!target) target = source; game = GameObserver::GetInstance(); } -void MTGAbilityBasicFeatures::init(MTGCardInstance * _source, Damageable * _target){ +void MTGAbilityBasicFeatures::init(MTGCardInstance * _source, Targetable * _target){ source = source; target=_target; if (!target) target = source; @@ -2652,13 +2372,14 @@ int TriggerNextPhase::testDestroy(){ TriggeredEvent::TriggeredEvent():MTGAbilityBasicFeatures(){} -TriggeredEvent::TriggeredEvent(MTGCardInstance * _source, Damageable * _target):MTGAbilityBasicFeatures(_source, _target){} +TriggeredEvent::TriggeredEvent(MTGCardInstance * _source, Targetable * _target):MTGAbilityBasicFeatures(_source, _target){} DamageEvent::DamageEvent(MTGCardInstance * _source, Damageable * _target, int _damage):TriggeredEvent(_source,_target),damage(_damage){ } int DamageEvent::resolve(){ - game->mLayers->stackLayer()->addDamage(source,target, damage); + Damageable * _target = (Damageable *)target; + game->mLayers->stackLayer()->addDamage(source,_target, damage); return damage; } @@ -2689,7 +2410,7 @@ int DestroyCondition::testDestroy(){ -GenericTriggeredAbility::GenericTriggeredAbility(int id, MTGCardInstance * _source, Trigger * _t, TriggeredEvent * _te, DestroyCondition * _dc , Damageable * _target ): TriggeredAbility(id, _source,_target){ +GenericTriggeredAbility::GenericTriggeredAbility(int id, MTGCardInstance * _source, Trigger * _t, TriggeredEvent * _te, DestroyCondition * _dc , Targetable * _target ): TriggeredAbility(id, _source,_target){ if (!target) target = source; t = _t; te = _te; @@ -2719,6 +2440,11 @@ GenericTriggeredAbility::~GenericTriggeredAbility(){ SAFE_DELETE(dc); } +GenericTriggeredAbility* GenericTriggeredAbility::clone() const{ + GenericTriggeredAbility * a = NEW GenericTriggeredAbility(*this); + a->isClone = 1; + return a; +} /*Mana Producers (lands) //These have a reactToClick function, and therefore two manaProducers on the same card conflict with each other @@ -2891,6 +2617,7 @@ other solutions need to be provided for abilities that add mana (ex: mana flare) } AManaProducer::~AManaProducer(){ + if (isClone) return; LOG("==Destroying ManaProducer Object"); SAFE_DELETE(cost); SAFE_DELETE(output); @@ -2898,6 +2625,12 @@ other solutions need to be provided for abilities that add mana (ex: mana flare) LOG("==Destroying ManaProducer Object Successful!"); } + AManaProducer * AManaProducer::clone() const{ + AManaProducer * a = NEW AManaProducer(*this); + a->isClone = 1; + return a; + } + int AManaProducer::currentlyTapping = 0; ostream& AManaProducer::toString(ostream& out) const diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index 817853fb2..0244e680b 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -135,7 +135,7 @@ int MTGCardInstance::afterDamage(){ if (!doDamageTest) return 0; doDamageTest = 0; if (!isACreature()) return 0; - if (life <=0 && isInPlay() && !basicAbilities[Constants::INDESTRUCTIBLE]){ + if (life <=0 && isInPlay()){ return destroy(); } return 0; @@ -145,11 +145,12 @@ int MTGCardInstance::bury(){ Player * p = controller(); if (!basicAbilities[Constants::INDESTRUCTIBLE]){ p->game->putInZone(this,p->game->inPlay,owner->game->graveyard); + return 1; } - return 1; + return 0; } int MTGCardInstance::destroy(){ - if (!triggerRegenerate() || !basicAbilities[Constants::INDESTRUCTIBLE]) return bury(); + if (!triggerRegenerate()) return bury(); return 0; } diff --git a/projects/mtg/src/MTGGamePhase.cpp b/projects/mtg/src/MTGGamePhase.cpp index 67b134358..b8f53a8d7 100644 --- a/projects/mtg/src/MTGGamePhase.cpp +++ b/projects/mtg/src/MTGGamePhase.cpp @@ -54,6 +54,12 @@ bool MTGGamePhase::CheckUserInput(u32 key){ return false; } + MTGGamePhase * MTGGamePhase::clone() const{ + MTGGamePhase * a = NEW MTGGamePhase(*this); + a->isClone = 1; + return a; + } + ostream& MTGGamePhase::toString(ostream& out) const { return out << "MTGGamePhase ::: animation " << animation << " ; currentState : " << currentState; diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index aea626e2f..cce77d272 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -84,6 +84,12 @@ ostream& MTGPutInPlayRule::toString(ostream& out) const return MTGAbility::toString(out) << ")"; } + MTGPutInPlayRule * MTGPutInPlayRule::clone() const{ + MTGPutInPlayRule * a = NEW MTGPutInPlayRule(*this); + a->isClone = 1; + return a; + } + MTGAttackRule::MTGAttackRule(int _id):MTGAbility(_id,NULL){ aType=MTGAbility::MTG_ATTACK_RULE; @@ -126,6 +132,13 @@ ostream& MTGAttackRule::toString(ostream& out) const return MTGAbility::toString(out) << ")"; } + MTGAttackRule * MTGAttackRule::clone() const{ + MTGAttackRule * a = NEW MTGAttackRule(*this); + a->isClone = 1; + return a; + } + + MTGBlockRule::MTGBlockRule(int _id):MTGAbility(_id,NULL){ aType=MTGAbility::MTG_BLOCK_RULE; } @@ -167,7 +180,11 @@ ostream& MTGBlockRule::toString(ostream& out) const return MTGAbility::toString(out) << ")"; } - + MTGBlockRule * MTGBlockRule::clone() const{ + MTGBlockRule * a = NEW MTGBlockRule(*this); + a->isClone = 1; + return a; + } // // Attacker chooses blockers order // @@ -295,6 +312,12 @@ ostream& MTGMomirRule::toString(ostream& out) const } + MTGMomirRule * MTGMomirRule::clone() const{ + MTGMomirRule * a = NEW MTGMomirRule(*this); + a->isClone = 1; + return a; + } + //HUDDisplay int HUDDisplay::testDestroy(){ return 0; @@ -383,4 +406,125 @@ HUDDisplay::~HUDDisplay(){ delete hs; } events.clear(); -} \ No newline at end of file +} + + HUDDisplay * HUDDisplay::clone() const{ + HUDDisplay * a = NEW HUDDisplay(*this); + a->isClone = 1; + return a; + } + + + /* Persist */ + MTGPersistRule::MTGPersistRule(int _id):MTGAbility(_id,NULL){}; + + int MTGPersistRule::receiveEvent(WEvent * event){ + if (event->type == WEvent::CHANGE_ZONE){ + WEventZoneChange * e = (WEventZoneChange *) event; + MTGCardInstance * card = e->card->previous; + if (card && card->basicAbilities[Constants::PERSIST] && !card->counters->hasCounter(-1,-1)){ + int ok = 0; + for (int i = 0; i < 2 ; i++){ + Player * p = game->players[i]; + if (e->from == p->game->inPlay) ok = 1; + } + if (!ok) return 0; + for (int i = 0; i < 2 ; i++){ + Player * p = game->players[i]; + if (e->to == p->game->graveyard){ + //p->game->putInZone(card, p->game->graveyard, card->owner->game->hand); + MTGCardInstance * copy = p->game->putInZone(e->card, p->game->graveyard, e->card->owner->game->stack); + Spell * spell = NEW Spell(copy); + spell->resolve(); + spell->source->counters->addCounter(-1,-1); + game->mLayers->playLayer()->forceUpdateCards(); + delete spell; + return 1; + } + } + } + } + return 0; + } + + ostream& MTGPersistRule::toString(ostream& out) const + { + out << "MTGPersistRule ::: ("; + return MTGAbility::toString(out) << ")"; + } + int MTGPersistRule::testDestroy(){return 0;} + MTGPersistRule * MTGPersistRule::clone() const{ + MTGPersistRule * a = NEW MTGPersistRule(*this); + a->isClone = 1; + return a; + } + + + /* Legend Rule */ + MTGLegendRule::MTGLegendRule(int _id):ListMaintainerAbility(_id){}; + + int MTGLegendRule::canBeInList(MTGCardInstance * card){ + if (card->basicAbilities[Constants::LEGENDARY] && game->isInPlay(card)){ + return 1; + } + return 0; + } + + int MTGLegendRule::added(MTGCardInstance * card){ + map::iterator it; + int destroy = 0; + for ( it=cards.begin() ; it != cards.end(); it++ ){ + MTGCardInstance * comparison = (*it).first; + if (comparison!= card && !strcmp(comparison->getName(), card->getName())){ + comparison->owner->game->putInGraveyard(comparison); + destroy = 1; + } + } + if (destroy){ + card->owner->game->putInGraveyard(card); + } + return 1; + } + + int MTGLegendRule::removed(MTGCardInstance * card){return 0;} + + int MTGLegendRule::testDestroy(){return 0;} + + ostream& MTGLegendRule::toString(ostream& out) const + { + return out << "MTGLegendRule :::"; + } + MTGLegendRule * MTGLegendRule::clone() const{ + MTGLegendRule * a = NEW MTGLegendRule(*this); + a->isClone = 1; + return a; + } + + /* Lifelink */ + MTGLifelinkRule::MTGLifelinkRule(int _id):MTGAbility(_id,NULL){}; + + int MTGLifelinkRule::receiveEvent(WEvent * event){ + if (event->type == WEvent::DAMAGE){ + WEventDamage * e = (WEventDamage *) event; + Damage * d = e->damage; + MTGCardInstance * card = d->source; + if (d->damage>0 && card && card->basicAbilities[Constants::LIFELINK]){ + card->controller()->life+= d->damage; + return 1; + } + } + return 0; + } + + int MTGLifelinkRule::testDestroy(){return 0;} + + ostream& MTGLifelinkRule::toString(ostream& out) const + { + out << "MTGLifelinkRule ::: ("; + return MTGAbility::toString(out) << ")"; + } + MTGLifelinkRule * MTGLifelinkRule::clone() const{ + MTGLifelinkRule * a = NEW MTGLifelinkRule(*this); + a->isClone = 1; + return a; + } \ No newline at end of file diff --git a/projects/mtg/src/ManaCost.cpp b/projects/mtg/src/ManaCost.cpp index 88a0db847..e32c10adc 100644 --- a/projects/mtg/src/ManaCost.cpp +++ b/projects/mtg/src/ManaCost.cpp @@ -282,9 +282,6 @@ int ManaCost::canAfford(ManaCost * _cost){ int positive = diff->isPositive(); delete diff; if (positive){ -#if defined (WIN32) || defined (LINUX) - OutputDebugString("can afford\n"); -#endif return 1; } return 0; diff --git a/projects/mtg/src/TargetsList.cpp b/projects/mtg/src/TargetsList.cpp index 6c1143f8b..4df1a055a 100644 --- a/projects/mtg/src/TargetsList.cpp +++ b/projects/mtg/src/TargetsList.cpp @@ -58,11 +58,11 @@ int TargetsList::toggleTarget(Targetable * target){ } -Targetable * TargetsList::getNextTarget(Targetable * previous, int type){ +Targetable * TargetsList::getNextTarget(Targetable * previous , int type){ int found = 0; if (!previous) found = 1; for (int i = 0; i < cursor; i++){ - if (found && targets[i]->typeAsTarget() == type){ + if (found && (type == -1 || targets[i]->typeAsTarget() == type)){ return (targets[i]); } if (targets[i] == previous) found = 1; diff --git a/projects/mtg/src/TestSuiteAI.cpp b/projects/mtg/src/TestSuiteAI.cpp index d812a4b30..c88cfd43e 100644 --- a/projects/mtg/src/TestSuiteAI.cpp +++ b/projects/mtg/src/TestSuiteAI.cpp @@ -119,6 +119,11 @@ int TestSuiteAI::Act(float dt){ MTGMomirRule * a = ((MTGMomirRule *)g->mLayers->actionLayer()->getAbility(MTGAbility::MOMIR)); a->reactToClick(suite->getCardByMTGId(cardIdHand), cardId); g->mLayers->actionLayer()->stuffHappened = 1; + }else if(action.find("p1")!=string::npos || action.find("p2")!=string::npos){ + Player * p = g->players[1]; + int start = action.find("p1"); + if (start != string::npos) p = g->players[0]; + g->cardClick(NULL, p); }else{ int mtgid = suite->getMTGId(action); if (mtgid){