From a06980a19766f405053d460a446488be15c3d0a1 Mon Sep 17 00:00:00 2001 From: salmelo16 Date: Sun, 28 Mar 2010 02:21:25 +0000 Subject: [PATCH] added new auto keys, this and thisforeach, functionallity similair to aslongas and foreach, but for properties of the card as opposed to cards on the field. More details in first comment. --- projects/mtg/bin/Res/sets/primitives/mtg.txt | 53 +++++ projects/mtg/bin/Res/test/_tests.txt | 9 +- .../mtg/bin/Res/test/aven_riftwatcher.txt | 2 +- .../mtg/bin/Res/test/aven_riftwatcher2.txt | 2 +- projects/mtg/bin/Res/test/black_market.txt | 21 ++ .../mtg/bin/Res/test/generic/level_up.txt | 35 +++ .../mtg/bin/Res/test/generic/level_up2.txt | 33 +++ .../mtg/bin/Res/test/generic/thisforeach.txt | 26 +++ .../mtg/bin/Res/test/goblin_razerunners.txt | 26 +++ .../mtg/bin/Res/test/thelon_of_havenwood.txt | 31 +++ projects/mtg/include/AllAbilities.h | 141 ++++++++++++ projects/mtg/include/ThisDescriptor.h | 53 +++++ projects/mtg/src/MTGAbility.cpp | 83 ++++++- projects/mtg/src/ManaCost.cpp | 2 +- projects/mtg/src/TargetChooser.cpp | 4 +- projects/mtg/src/ThisDescriptor.cpp | 212 ++++++++++++++++++ projects/mtg/template.vcproj | 8 + 17 files changed, 728 insertions(+), 13 deletions(-) create mode 100644 projects/mtg/bin/Res/test/black_market.txt create mode 100644 projects/mtg/bin/Res/test/generic/level_up.txt create mode 100644 projects/mtg/bin/Res/test/generic/level_up2.txt create mode 100644 projects/mtg/bin/Res/test/generic/thisforeach.txt create mode 100644 projects/mtg/bin/Res/test/goblin_razerunners.txt create mode 100644 projects/mtg/bin/Res/test/thelon_of_havenwood.txt create mode 100644 projects/mtg/include/ThisDescriptor.h create mode 100644 projects/mtg/src/ThisDescriptor.cpp diff --git a/projects/mtg/bin/Res/sets/primitives/mtg.txt b/projects/mtg/bin/Res/sets/primitives/mtg.txt index c5a006f37..51de9bc01 100644 --- a/projects/mtg/bin/Res/sets/primitives/mtg.txt +++ b/projects/mtg/bin/Res/sets/primitives/mtg.txt @@ -2887,6 +2887,14 @@ power=1 toughness=1 [/card] [card] +name=Barrin's Codex +auto=@each my upkeep:may counter(0/0,1,Page) +auto={4}{T}{S}:thisforeach(counter{0/0.1.Page}) draw:1 controller +text=At the beginning of your upkeep, you may put a page counter on Barrin's Codex. -- {4}, {T}, Sacrifice Barrin's Codex: Draw X cards, where X is the number of page counters on Barrin's Codex. +mana={4} +type=Artifact +[/card] +[card] name=Basal Sliver auto=lord(sliver) {S}:Add {B}{B} text=All Slivers have "Sacrifice this permanent: Add {B}{B} to your mana pool." @@ -3517,6 +3525,14 @@ mana={0} type=Artifact [/card] [card] +name=Black Market +auto=@movedTo(creature|graveyard) from(battlefield):counter(0/0,1,Charge) +auto=@each my firstmain:thisforeach(counter{0/0.1.Charge}) add{B} controller +text=Whenever a creature is put into a graveyard from the battlefield, put a charge counter on Black Market. -- At the beginning of your precombat main phase, add Black to your mana pool for each charge counter on Black Market. +mana={3}{B}{B} +type=Enchantment +[/card] +[card] name=Black Poplar Shaman auto={2}{B}:regenerate target(treefolk) text={2}{B}: Regenerate target Treefolk. @@ -15974,6 +15990,17 @@ power=2 toughness=2 [/card] [card] +name=Goblin Razerunners +auto={1}{R}{S(land|myBattlefield?)}:counter(1/1,1) +auto=@each my endofturn:may thisforeach(counter{1/1,1}) damage:1 target(player) +text={1}{R}, Sacrifice a land: Put a +1/+1 counter on Goblin Razerunners. -- At the beginning of your end step, you may have Goblin Razerunners deal damage equal to the number of +1/+1 counters on it to target player. +mana={2}{R}{R} +type=Creature +subtype=Goblin Warrior +power=3 +toughness=4 +[/card] +[card] name=Goblin Replica auto={3}{R}{S}:destroy target(artifact) text={3}{R}, Sacrifice Goblin Replica: Destroy target artifact. @@ -21233,6 +21260,21 @@ subtype=Human Knight power=2 toughness=2 [/card] +####Preemptive addition for Rise of the Eldrazi and to test new counter functions. +[card] +name=Knight of Cliffhaven +auto={3}:counter(0/0,1,Level Up) asSorcery +auto=this(counter{0/0,1,Level Up}) flying +auto=this(counter{0/0,1,Level Up}) 0/1 +auto=this(counter{0/0,4,Level Up}) vigilance +auto=this(counter{0/0,4,Level Up}) 2/1 +text=Level up 3 -- [Level 1-3] Flying (2/3) -- [Level 4+] Flying, vigilance (4/4) +mana={1}{W} +type=Creature +subtype=Kor Knight +power=2 +toughness=2 +[/card] [card] name=Knight of Dawn abilities=first strike @@ -39958,6 +40000,17 @@ mana={2}{U} type=Sorcery [/card] [card] +name=Thelon of Havenwood +auto={B}{G}:moveTo(exile) target(fungus|mygraveyard) && counter(0/0,1,Spore) all(fungus) +auto=lord(fungus) thisforeach(counter{0/0,1,Spore}) 1/1 +text=Each Fungus creature gets +1/+1 for each spore counter on it. -- {B}{G}, Exile a Fungus card from a graveyard: Put a spore counter on each Fungus on the battlefield. +mana={G}{G} +type=Legendary Creature +subtype=Elf Druid +power=2 +toughness=2 +[/card] +[card] name=Thelonite Druid auto={1}{G}{T}{S(creature|myBattlefield)}:lord(forest|myBattlefield) becomes(Creature,2/3) ueot text={1}{G}, {T}, Sacrifice a creature: Forests you control become 2/3 creatures until end of turn. They're still lands. diff --git a/projects/mtg/bin/Res/test/_tests.txt b/projects/mtg/bin/Res/test/_tests.txt index 6279ab559..5b33103f4 100644 --- a/projects/mtg/bin/Res/test/_tests.txt +++ b/projects/mtg/bin/Res/test/_tests.txt @@ -31,6 +31,9 @@ generic/kicker.txt generic/kicker2.txt generic/landwalk.txt generic/legendary.txt +###Level up tests disabled until knight of cliffhaven has an id +###generic/level_up.txt +###generic/level_up2.txt generic/lord_counter.txt generic/lord_counter_any.txt generic/lifelink.txt @@ -55,6 +58,7 @@ generic/summoning_sickness.txt generic/targetController_life.txt generic/targetController_life2.txt generic/targetController_damage.txt +generic/thisforeach.txt generic/tokens.txt generic/tokens2.txt generic/trample.txt @@ -121,6 +125,7 @@ behemoth_sledge4.txt behemoth_sledge5.txt belligerent_hatchling.txt benalish_knight.txt +black_market.txt black_vise.txt blessed_wine.txt blinking_spirit.txt @@ -246,6 +251,7 @@ goblin_lackey2.txt goblin_lackey3.txt goblin_lackey4.txt goblin_offensive.txt +goblin_razerunners.txt golgari_germination_i153.txt gravedigger.txt great_defender.txt @@ -399,9 +405,10 @@ tanglesap.txt telekinetic_sliver.txt terror.txt terror2.txt +thallid.txt +thellon_of_havenwood.txt threaten.txt throne_of_bone.txt -thallid.txt titanic_ultimatum.txt torture.txt tranquil_domain.txt diff --git a/projects/mtg/bin/Res/test/aven_riftwatcher.txt b/projects/mtg/bin/Res/test/aven_riftwatcher.txt index fd27e2c6b..64f9679cc 100644 --- a/projects/mtg/bin/Res/test/aven_riftwatcher.txt +++ b/projects/mtg/bin/Res/test/aven_riftwatcher.txt @@ -2,7 +2,7 @@ FIRSTMAIN [PLAYER1] hand:Aven Riftwatcher -manapool:{G} +manapool:{2}{W} [PLAYER2] [DO] Aven Riftwatcher diff --git a/projects/mtg/bin/Res/test/aven_riftwatcher2.txt b/projects/mtg/bin/Res/test/aven_riftwatcher2.txt index 4fee20560..9fd8d9d7e 100644 --- a/projects/mtg/bin/Res/test/aven_riftwatcher2.txt +++ b/projects/mtg/bin/Res/test/aven_riftwatcher2.txt @@ -2,7 +2,7 @@ FIRSTMAIN [PLAYER1] hand:Aven Riftwatcher -manapool:{G} +manapool:{2}{W} [PLAYER2] [DO] aven riftwatcher diff --git a/projects/mtg/bin/Res/test/black_market.txt b/projects/mtg/bin/Res/test/black_market.txt new file mode 100644 index 000000000..7ae20db92 --- /dev/null +++ b/projects/mtg/bin/Res/test/black_market.txt @@ -0,0 +1,21 @@ +[init] +draw +[player1] +inplay:Brass Secretary,Heart Warden,Limestone Golem,Black Market +manapool:{6} +[player2] +[do] +Heart Warden +choice 1 +Brass Secretary +Limestone Golem +p1 +next +[assert] +firstmain +[player1] +inplay:Black Market +graveyard:Brass Secretary,Heart Warden,Limestone Golem +manapool:{B}{B}{B} +[player2] +[end] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/generic/level_up.txt b/projects/mtg/bin/Res/test/generic/level_up.txt new file mode 100644 index 000000000..384888898 --- /dev/null +++ b/projects/mtg/bin/Res/test/generic/level_up.txt @@ -0,0 +1,35 @@ +[init] +firstmain +[player1] +inplay:Knight of Cliffhaven +manapool:{12} +[player2] +inplay:island,forest,swamp,moat +hand:assassinate +[do] +Knight of Cliffhaven +Knight of Cliffhaven +Knight of Cliffhaven +Knight of Cliffhaven +next +next +Knight of Cliffhaven +eot +next +next +next +island +forest +swamp +assassinate +Knight of Cliffhaven +[assert] +firstmain +[player1] +inplay:Knight of Cliffhaven +[player2] +inplay:island,forest,swamp,moat +hand:assassinate +manapool:{G}{U}{B} +life:16 +[end] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/generic/level_up2.txt b/projects/mtg/bin/Res/test/generic/level_up2.txt new file mode 100644 index 000000000..09b9e0252 --- /dev/null +++ b/projects/mtg/bin/Res/test/generic/level_up2.txt @@ -0,0 +1,33 @@ +[init] +firstmain +[player1] +inplay:Knight of Cliffhaven +manapool:{9} +[player2] +inplay:island,forest,swamp,moat +hand:assassinate +[do] +Knight of Cliffhaven +Knight of Cliffhaven +Knight of Cliffhaven +next +next +Knight of Cliffhaven +eot +next +next +next +island +forest +swamp +assassinate +Knight of Cliffhaven +[assert] +firstmain +[player1] +graveyard:Knight of Cliffhaven +[player2] +inplay:island,forest,swamp,moat +graveyard:assassinate +life:18 +[end] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/generic/thisforeach.txt b/projects/mtg/bin/Res/test/generic/thisforeach.txt new file mode 100644 index 000000000..163a2f410 --- /dev/null +++ b/projects/mtg/bin/Res/test/generic/thisforeach.txt @@ -0,0 +1,26 @@ +[init] +untap +[player1] +inplay:Urza's Mine,Urza's Tower,Urza's Power Plant,Barrin's Codex +library:forest,mountain,island,swamp +[player2] +[do] +next +choice 0 +eot +eot +next +choice 0 +next +next +Urza's Mine +Urza's Power Plant +Barrin's Codex +[assert] +firstmain +[player1] +inplay:Urza's Mine,Urza's Tower,Urza's Power Plant +graveyard:Barrin's Codex +hand:forest,mountain,island,swamp +[player2] +[end] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/goblin_razerunners.txt b/projects/mtg/bin/Res/test/goblin_razerunners.txt new file mode 100644 index 000000000..8a601f4d7 --- /dev/null +++ b/projects/mtg/bin/Res/test/goblin_razerunners.txt @@ -0,0 +1,26 @@ +[init] +firstmain +[player1] +inplay:Goblin Razerunners,Forest,Island +manapool:{R}{R}{R}{R} +[player2] +[do] +goblin razerunners +forest +goblin razerunners +island +next +next +next +next +next +choice 0 +p2 +[assert] +endofturn +[player1] +inplay:Goblin Razerunners +graveyard:forest,island +[player2] +life:18 +[end] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/thelon_of_havenwood.txt b/projects/mtg/bin/Res/test/thelon_of_havenwood.txt new file mode 100644 index 000000000..5d1853199 --- /dev/null +++ b/projects/mtg/bin/Res/test/thelon_of_havenwood.txt @@ -0,0 +1,31 @@ +[init] +untap +[player1] +inplay:Thelon Of Havenwood,Thallid,Deathspore Thallid,forest,swamp +graveyard:fungusaur +[player2] +[do] +next +next +next +forest +swamp +Thelon of Havenwood +fungusaur +next +next +Thallid +choice 0 +Deathspore thallid +choice 0 +next +next +next +next +[assert] +secondmain +[player1] +inplay:Thelon Of Havenwood,Thallid,Deathspore Thallid,forest,swamp +[player2] +life:14 +[end] \ No newline at end of file diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index d91caec5b..731d44c4a 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -14,6 +14,7 @@ #include "WEvent.h" #include "GuiStatic.h" #include "GameObserver.h" +#include "ThisDescriptor.h" #include #include @@ -1875,8 +1876,148 @@ class AForeach:public ListMaintainerAbility{ }; + +class AThis:public MTGAbility{ + public: + MTGAbility * ability; + MTGAbility * a; + ThisDescriptor * td; + AThis(int _id, MTGCardInstance * _source, Damageable * _target, ThisDescriptor * _td, MTGAbility * ability):MTGAbility(_id, _source,_target),ability(ability){ + td = _td; + ability->source = source; + ability->target = target; + a = NULL; + SAFE_DELETE(tc); + } + int removeFromGame(){ + return removeAbilityFromGame(); + } + + int addToGame(){ + return MTGAbility::addToGame(); + } + + void Update(float dt){ + resolve(); + } + + int resolve(){ + //TODO check if ability is oneShot ? + if (td->match(source) > 0){ + addAbilityToGame(); + } + if (ability->oneShot) a = NULL; //allows to call the effect several times + return 1; + } + + int addAbilityToGame(){ + if (a) return 0; + a = ability->clone(); + if (a->oneShot){ + a->resolve(); + delete(a); + }else{ + a->addToGame(); + } + return 1; + } + + int removeAbilityFromGame(){ + if (!a) return 0; + game->removeObserver(a); + a = NULL; + return 1; + } + + ~AThis(){ + if (!isClone) SAFE_DELETE(ability); SAFE_DELETE(td); + } + AThis * clone() const{ + AThis * a = NEW AThis(*this); + a->isClone = 1; + return a; + } +}; + +class AThisForEach:public MTGAbility{ + public: + MTGAbility * ability; + ThisDescriptor * td; + vector abilities; + AThisForEach(int _id, MTGCardInstance * _source, Damageable * _target, ThisDescriptor * _td, MTGAbility * ability):MTGAbility(_id, _source,_target),ability(ability){ + td = _td; + ability->source = source; + ability->target = target; + SAFE_DELETE(tc); + } + + int removeFromGame(){ + return removeAbilityFromGame(); + } + + int addToGame(){ + return MTGAbility::addToGame(); + } + + void Update(float dt){ + resolve(); + } + + int resolve(){ + //TODO check if ability is oneShot ? + int matches = td->match(source); + if (matches > 0) { + if (abilities.size()){ + removeAbilityFromGame(); + } + for (int i = 0; i < matches; i++) { + addAbilityToGame(); + } + } + return 1; + } + + int addAbilityToGame(){ + MTGAbility * a = ability->clone(); + a->target = target; + if (a->oneShot){ + a->resolve(); + delete(a); + }else{ + a->addToGame(); + abilities.push_back(a); + //abilities[abilities.size()] = a; + } + return 1; + } + + int removeAbilityFromGame(){ + for (int i = abilities.size(); i > 0; i--){ + game->removeObserver(abilities[i-1]); + } + abilities.clear(); + return 1; + } + + ~AThisForEach(){ + if (!isClone){ + SAFE_DELETE(ability); + SAFE_DELETE(td); + } + if (abilities.size()){ + removeAbilityFromGame(); + } + } + + + AThisForEach * clone() const{ + AThisForEach * a = NEW AThisForEach(*this); + a->isClone = 1; + return a; + } +}; class AADamager:public ActivatedAbilityTP{ public: diff --git a/projects/mtg/include/ThisDescriptor.h b/projects/mtg/include/ThisDescriptor.h new file mode 100644 index 000000000..007f8fdeb --- /dev/null +++ b/projects/mtg/include/ThisDescriptor.h @@ -0,0 +1,53 @@ +/* + Filter-like system for determining if a card meats certain criteria, for this and thisforeach autos +*/ + +#ifndef _THISDESCRIPTOR_H_ +#define _THISDESCRIPTOR_H_ + +#include "Counters.h" +#include "MTGGameZones.h" +#include "MTGCardInstance.h" +#include "CardDescriptor.h" + +class ThisDescriptor{ + public: + int comparisonMode; + int comparisonCriterion; + virtual int match(MTGCardInstance * card) = 0; + int matchValue(int value); +}; + +class ThisDescriptorFactory{ +public: + ThisDescriptor * createThisDescriptor(string s); +}; + +class ThisCounter:public ThisDescriptor{ + public: + Counter * counter; + virtual int match(MTGCardInstance * card); + ThisCounter(Counter * _counter); + ThisCounter(int power, int toughness, int nb, const char * name); + ~ThisCounter(); +}; + +class ThisCounterAny:public ThisDescriptor{ + public: + virtual int match(MTGCardInstance *card); + ThisCounterAny(int nb); +}; + +class ThisPower:public ThisDescriptor{ + public: + virtual int match(MTGCardInstance * card); + ThisPower(int power); +}; + +class ThisToughness:public ThisDescriptor{ + public: + virtual int match(MTGCardInstance * card); + ThisToughness(int toughness); +}; + +#endif \ No newline at end of file diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 670391a38..f787fe845 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -8,6 +8,7 @@ #include "../include/CardGui.h" #include "../include/MTGDeck.h" #include "../include/Translate.h" +#include "../include/ThisDescriptor.h" int AbilityFactory::countCards(TargetChooser * tc, Player * player, int option){ @@ -38,8 +39,8 @@ int AbilityFactory::countCards(TargetChooser * tc, Player * player, int option){ Counter * AbilityFactory::parseCounter(string s, MTGCardInstance * target) { int nb = 1; string name = ""; - size_t start = s.find("(") + 1; - size_t end = s.find(")", start); + size_t start = 0; + size_t end = s.length(); size_t separator = s.find(",", start); if (separator == string::npos) separator = s.find(".", start); if (separator != string::npos){ @@ -362,11 +363,79 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG multi->oneShot=1; return multi; } - - //Lord, foreach, aslongas - string lords[] = {"lord(","foreach(", "aslongas(", "all("}; + + //rather dirty way to stop thises and lords from conflicting with each other. + string prelords[] = {"foreach(","lord(","aslongas(", "all("}; + size_t lord = string::npos; + for (int j = 0; j < 4; ++j){ + size_t found2 = s.find(prelords[j]); + if (found2!=string::npos && ((found == string::npos) || found2 < found)){ + lord = found2; + } + } + + //This, ThisForEach; + string thises[] = {"this(","thisforeach("}; found = string::npos; int i = -1; + for (int j = 0; j < 2; ++j){ + size_t found2 = s.find(thises[j]); + if (found2!=string::npos && ((found == string::npos) || found2 < found)){ + found = found2; + i = j; + } + } + if (found != string::npos && found < lord) { + size_t header = thises[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){ + string thisDescriptorString = s.substr(found+header,end-found-header); + ThisDescriptorFactory tdf; + ThisDescriptor * td = tdf.createThisDescriptor(thisDescriptorString); + + if (!td){ + OutputDebugString("MTGABILITY: Parsing Error:"); + OutputDebugString(s.c_str()); + OutputDebugString("\n"); + return NULL; + } + + MTGAbility * a = parseMagicLine(s1,id,spell, card,0,activated); + if (!a){ + SAFE_DELETE(td); + return NULL; + } + MTGAbility * result = NULL; + int oneShot = 0; + if (activated) oneShot = 1; + if (card->hasType("sorcery") || card->hasType("instant")) oneShot = 1; + if (a->oneShot) oneShot = 1; + Damageable * _target = NULL; + if (spell) _target = spell->getNextDamageableTarget(); + if (!_target) _target = target; + + switch(i){ + case 0: result = NEW AThis(id, card, _target, td, a); break; + case 1: result = NEW AThisForEach(id, card, _target, td, a); break; + default: result = NULL; + } + if (result) result->oneShot = oneShot; + return result; + } + return NULL; + } + + + //Lord, foreach, aslongas + string lords[] = {"lord(","foreach(","aslongas(", "all("}; + found = string::npos; + i = -1; for (int j = 0; j < 4; ++j){ size_t found2 = s.find(lords[j]); if (found2!=string::npos && ((found == string::npos) || found2 < found)){ @@ -451,6 +520,8 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG SAFE_DELETE(tc); + + //Cycling found = s.find("cycling"); if (found != string::npos){ @@ -730,7 +801,7 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG if (found != string::npos){ size_t start = s.find("("); size_t end = s.find(")"); - string counterString = s.substr(start,end-start+1); + string counterString = s.substr(start+1,end-start-1); Counter * counter = parseCounter(counterString,target); if (counter){ MTGAbility * a = NEW AACounter(id,card,target,counter->name.c_str(),counter->power,counter->toughness,counter->nb); diff --git a/projects/mtg/src/ManaCost.cpp b/projects/mtg/src/ManaCost.cpp index 6ae2c4f22..a12cff174 100644 --- a/projects/mtg/src/ManaCost.cpp +++ b/projects/mtg/src/ManaCost.cpp @@ -71,7 +71,7 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan size_t counter_start = value.find("("); size_t counter_end = value.find(")", counter_start); AbilityFactory * abf = NEW AbilityFactory(); - string counterString = value.substr(counter_start,counter_end-counter_start); + string counterString = value.substr(counter_start+1,counter_end-counter_start-1); Counter * counter = abf->parseCounter(counterString,c); size_t separator = value.find(",",counter_start); size_t separator2 = string::npos; diff --git a/projects/mtg/src/TargetChooser.cpp b/projects/mtg/src/TargetChooser.cpp index af4d61f17..cf60de4ae 100644 --- a/projects/mtg/src/TargetChooser.cpp +++ b/projects/mtg/src/TargetChooser.cpp @@ -204,9 +204,7 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta }else{ size_t start = attribute.find("{"); size_t end = attribute.find("}"); - string counterString = attribute.substr(start,end-start+1); - counterString.replace(0,1,"("); - counterString.replace(counterString.length() - 1,1,")"); + string counterString = attribute.substr(start+1,end-start-1); AbilityFactory * abf = NEW AbilityFactory(); Counter * counter = abf->parseCounter(counterString,card); if (counter) { diff --git a/projects/mtg/src/ThisDescriptor.cpp b/projects/mtg/src/ThisDescriptor.cpp new file mode 100644 index 000000000..7265259b0 --- /dev/null +++ b/projects/mtg/src/ThisDescriptor.cpp @@ -0,0 +1,212 @@ +#include "../include/config.h" +#include "../include/ThisDescriptor.h" +#include "../include/Counters.h" +#include "../include/MTGCardInstance.h" +#include "../include/CardDescriptor.h" + + +//Returns the amount by which a value passes the comparison. +int ThisDescriptor::matchValue(int value){ + switch (comparisonMode){ + case COMPARISON_AT_MOST: + return (comparisonCriterion - value + 1); + case COMPARISON_AT_LEAST: + return (value - comparisonCriterion + 1); + case COMPARISON_EQUAL: + return (comparisonCriterion == value); + case COMPARISON_GREATER: + return (value - comparisonCriterion); + case COMPARISON_LESS: + return (comparisonCriterion - value); + case COMPARISON_UNEQUAL: + return (comparisonCriterion != value); + } + return 0; +} + +ThisDescriptor * ThisDescriptorFactory::createThisDescriptor(string s){ + size_t found; + + string whitespaces (" \t\f\v\n\r"); + + found=s.find_last_not_of(whitespaces); + if (found!=string::npos) + s.erase(found+1); + else return NULL; + + found=s.find_first_not_of(whitespaces); + if (found!=string::npos) + s.erase(0,found); + else return NULL; + + //set comparison mode + //equal, greater, and less must remain above the others, otherwise the others may never be used. + int mode = 0; + size_t found2 = string::npos; + int opLength = 0; + + found = s.find("="); + if (found != string::npos){ + mode = COMPARISON_EQUAL; + found2 = found + 1; + opLength = 1; + } + found = s.find(">"); + if (found != string::npos){ + mode = COMPARISON_GREATER; + found2 = found + 1; + opLength = 1; + } + found = s.find("<"); + if (found != string::npos){ + mode = COMPARISON_LESS; + found2 = found + 1; + opLength = 1; + } + found = s.find("<="); + if (found != string::npos){ + mode = COMPARISON_AT_MOST; + found2 = found + 2; + opLength = 2; + } + found = s.find(">="); + if (found != string::npos){ + mode = COMPARISON_AT_LEAST; + found2 = found + 2; + opLength = 2; + } + found = s.find("!="); + if (found != string::npos){ + mode = COMPARISON_UNEQUAL; + found2 = found + 2; + opLength = 2; + } + if (!mode) mode = COMPARISON_AT_LEAST; + + //get comparison criterion + int criterionFound = 0; + int criterion = 1; + if ((found2 != string::npos) && (found2 < s.length())){ + criterion = atoi(s.substr(found2).c_str()); + criterionFound = 1; + } + if (found2 != string::npos) s.erase(found2 - opLength); + + //counters + found = s.find("counter{"); + if (found != string::npos) { + size_t start = s.find("{"); + size_t end = s.find("}"); + string counterString = s.substr(start+1,end-start-1); + AbilityFactory * abf = NEW AbilityFactory(); + Counter * counter = abf->parseCounter(counterString,NULL); + if (counter) { + if (criterionFound) counter->nb = criterion; + ThisCounter * td = NEW ThisCounter(counter); + if (td) { + td->comparisonMode = mode; + return td; + } + } + return NULL; + } + + //any counter + found = s.find("counters"); + if (found != string::npos) { + ThisCounterAny * td = NEW ThisCounterAny(criterion); + if (td) { + td->comparisonMode = mode; + return td; + } + return NULL; + } + + //power + found = s.find("power"); + if (found != string::npos) { + ThisPower * td = NEW ThisPower(criterion); + if (td) { + td->comparisonMode = mode; + return td; + } + return NULL; + } + + //toughness + found = s.find("toughness"); + if (found != string::npos) { + ThisToughness * td = NEW ThisToughness(criterion); + if (td) { + td->comparisonMode = mode; + return td; + } + return NULL; + } + + return NULL; +} + +ThisCounter::ThisCounter(Counter * _counter){ + counter = _counter; + comparisonCriterion = counter->nb; +} + +ThisCounter::ThisCounter(int power, int toughness, int nb, const char * name){ + counter = NEW Counter(NULL,name,power,toughness); + comparisonCriterion = nb; +} + +int ThisCounter::match(MTGCardInstance * card){ + Counter * targetCounter = card->counters->hasCounter(counter->name.c_str(),counter->power,counter->toughness); + if (targetCounter){ + return matchValue(targetCounter->nb); + }else{ + switch (comparisonMode) { + case COMPARISON_LESS: + return comparisonCriterion; + case COMPARISON_AT_MOST: + return comparisonCriterion + 1; + case COMPARISON_UNEQUAL: + if (comparisonCriterion) return 1; + else return 0; + case COMPARISON_EQUAL: + if (comparisonCriterion) return 0; + else return 1; + default : + return 0; + } + } +} + +ThisCounter::~ThisCounter() { + SAFE_DELETE(counter); +} + +ThisPower::ThisPower(int power){ + comparisonCriterion = power; +} + +int ThisPower::match(MTGCardInstance * card){ + return matchValue(card->power); +} + +ThisToughness::ThisToughness(int toughness){ + comparisonCriterion = toughness; +} + +int ThisToughness::match(MTGCardInstance * card){ + return matchValue(card->toughness); +} + +ThisCounterAny::ThisCounterAny(int nb){ + comparisonCriterion = nb; +} + +int ThisCounterAny::match(MTGCardInstance * card){ + int result = 0; + for (int i = 0; i < card->counters->mCount; i++) { + result += card->counters->counters[i]->nb; + } + return matchValue(result); +} \ No newline at end of file diff --git a/projects/mtg/template.vcproj b/projects/mtg/template.vcproj index c7d3ca745..9346dc4c7 100644 --- a/projects/mtg/template.vcproj +++ b/projects/mtg/template.vcproj @@ -792,6 +792,10 @@ RelativePath=".\src\TextScroller.cpp" > + + @@ -1185,6 +1189,10 @@ RelativePath=".\include\TextScroller.h" > + +