From d922d4fe06046a0bc6b9f8baa15299e7dc871b2e Mon Sep 17 00:00:00 2001 From: "wagic.the.homebrew" Date: Wed, 4 May 2011 04:04:03 +0000 Subject: [PATCH] - Added "loseSubtypesOf(type)" ability. For example, loseSubtypesOf(land) means "target loses all its land subtypes" - Added Evil Presence, as an example of the new keywords loseabilities and losesubtypes. It's quite experimental but I added 3 tests that cover the basics. Please report if you find bugs. - moved the "lands produce mana" rules outside of the primitives, and into the external rules. This was a necessary step to create cards such as Evil Presence. - real support for subtypes. Needs some more testing, but there are now functions in Subtypes.cpp to know if a given subtype is a creature subtype, or a land subtype, etc... - minor refactor of MTGDeck.cpp Notes: - I checked that the AI can still use lands - This change has a bad impact on primitives loading performance (thanks Wil for the loading time output). This is probably due to suboptimal algorithms and data structures for subtypes. If the impact is strong on lowend devices, I can probably optimize a bit (the map subtypesOf could be changed into a vector with some work) - The test suite passes, added 3 tests for evil presence. --- projects/mtg/bin/Res/rules/mtg.txt | 8 +++ projects/mtg/bin/Res/rules/testsuite.txt | 7 ++ projects/mtg/bin/Res/sets/primitives/mtg.txt | 67 ++++--------------- .../bin/Res/sets/primitives/unsupported.txt | 12 ---- projects/mtg/bin/Res/test/_tests.txt | 3 + projects/mtg/bin/Res/test/evil_presence.txt | 19 ++++++ projects/mtg/bin/Res/test/evil_presence2.txt | 22 ++++++ projects/mtg/bin/Res/test/evil_presence3.txt | 19 ++++++ projects/mtg/include/AllAbilities.h | 12 ++++ projects/mtg/include/Subtypes.h | 22 ++++-- projects/mtg/src/AllAbilities.cpp | 45 +++++++++++++ projects/mtg/src/CardPrimitive.cpp | 12 +++- projects/mtg/src/MTGAbility.cpp | 8 +++ projects/mtg/src/MTGDeck.cpp | 56 +++------------- projects/mtg/src/Subtypes.cpp | 56 ++++++++++++++++ 15 files changed, 250 insertions(+), 118 deletions(-) create mode 100644 projects/mtg/bin/Res/test/evil_presence.txt create mode 100644 projects/mtg/bin/Res/test/evil_presence2.txt create mode 100644 projects/mtg/bin/Res/test/evil_presence3.txt diff --git a/projects/mtg/bin/Res/rules/mtg.txt b/projects/mtg/bin/Res/rules/mtg.txt index efb760e7b..08f46a55b 100644 --- a/projects/mtg/bin/Res/rules/mtg.txt +++ b/projects/mtg/bin/Res/rules/mtg.txt @@ -9,6 +9,14 @@ auto=draw:7 auto=@each my draw:draw:1 auto=maxPlay(land)1 + +#Lands Mana Rules +auto=lord(Swamp|MyBattlefield) {T}:Add{B} +auto=lord(Forest|MyBattlefield) {T}:Add{G} +auto=lord(Island|MyBattlefield) {T}:Add{U} +auto=lord(Mountains|MyBattlefield) {T}:Add{R} +auto=lord(Plains|MyBattlefield) {T}:Add{W} + #Mana Empties from manapool at the end of each phase auto=@each untap:removeMana(*) auto=@each upkeep:removeMana(*) diff --git a/projects/mtg/bin/Res/rules/testsuite.txt b/projects/mtg/bin/Res/rules/testsuite.txt index 044e5f712..0852a1f00 100644 --- a/projects/mtg/bin/Res/rules/testsuite.txt +++ b/projects/mtg/bin/Res/rules/testsuite.txt @@ -7,6 +7,13 @@ life:20 auto=@each my draw:draw:1 auto=maxPlay(land)1 +#Lands Mana Rules +auto=lord(Swamp|MyBattlefield) {T}:Add{B} +auto=lord(Forest|MyBattlefield) {T}:Add{G} +auto=lord(Island|MyBattlefield) {T}:Add{U} +auto=lord(Mountains|MyBattlefield) {T}:Add{R} +auto=lord(Plains|MyBattlefield) {T}:Add{W} + #Mana Empties from manapool at the end of each phase auto=@each untap:removeMana(*) auto=@each upkeep:removeMana(*) diff --git a/projects/mtg/bin/Res/sets/primitives/mtg.txt b/projects/mtg/bin/Res/sets/primitives/mtg.txt index 0b244ca28..0aa405937 100644 --- a/projects/mtg/bin/Res/sets/primitives/mtg.txt +++ b/projects/mtg/bin/Res/sets/primitives/mtg.txt @@ -4269,8 +4269,6 @@ type=Land [/card] [card] name=Badlands -auto={T}:Add {R} -auto={T}:Add {B} type=Land subtype=Swamp Mountain [/card] @@ -5252,8 +5250,6 @@ toughness=1 [/card] [card] name=Bayou -auto={T}:Add {B} -auto={T}:Add {G} type=Land subtype=Swamp Forest [/card] @@ -6678,8 +6674,6 @@ toughness=2 name=Blood Crypt auto=tap auto=may untap && life:-2 controller -auto={T}:Add {B} -auto={T}:Add {R} text=({T}: Add {B} or {R} to your mana pool.) -- As Blood Crypt enters the battlefield, you may pay 2 life. If you don't, Blood Crypt enters the battlefield tapped. type=Land subtype=Swamp Mountain @@ -8203,8 +8197,6 @@ type=Enchantment name=Breeding Pool auto=tap auto=may untap && life:-2 controller -auto={T}:Add {G} -auto={T}:Add {U} text=({T}: Add {G} or {U} to your mana pool.) -- As Breeding Pool enters the battlefield, you may pay 2 life. If you don't, Breeding Pool enters the battlefield tapped. type=Land subtype=Forest Island @@ -17855,10 +17847,9 @@ type=Sorcery [/card] [card] name=Dryad Arbor -auto={T}:add{G} text=(Dryad Arbor isn't a spell, it's affected by summoning sickness, and it has "{T}: Add {G} to your mana pool.") -- Dryad Arbor is green. color=green -type=Land Creature +type=Creature Land subtype=Forest Dryad power=1 toughness=1 @@ -20461,6 +20452,17 @@ power=6 toughness=3 [/card] [card] +name=Evil Presence +text=Enchant land -- Enchanted land is a Swamp. +target=land +auto=loseabilities +auto=losesubtypesof(land) +auto=transforms((swamp,)) +mana={B} +type=Enchantment +subtype=Aura +[/card] +[card] name=Evincar's Justice auto=damage:2 all(creature,player) buyback={2}{B}{B}{3} @@ -23529,7 +23531,6 @@ subtype=Aura [/card] [card] name=Forest -auto={T}: Add {G} text=G type=Basic Land subtype=Forest @@ -26788,8 +26789,6 @@ toughness=4 name=Godless Shrine auto=tap auto=may untap && life:-2 controller -auto={T}:Add {W} -auto={T}:Add {B} text=({T}: Add {W} or {B} to your mana pool.) -- As Godless Shrine enters the battlefield, you may pay 2 life. If you don't, Godless Shrine enters the battlefield tapped. type=Land subtype=Plains Swamp @@ -28498,8 +28497,6 @@ toughness=3 name=Hallowed Fountain auto=tap auto=may untap && life:-2 controller -auto={T}:Add {W} -auto={T}:Add {U} text=({T}: Add {W} or {U} to your mana pool.) -- As Hallowed Fountain enters the battlefield, you may pay 2 life. If you don't, Hallowed Fountain enters the battlefield tapped. type=Land subtype=Plains Island @@ -32457,7 +32454,6 @@ toughness=1 [/card] [card] name=Island -auto={T}: Add {U} text=U type=Basic Land subtype=Island @@ -36645,7 +36641,6 @@ toughness=5 [card] name=Leechridden Swamp auto=tap -auto={T}:Add {B} auto=aslongas(*[black]|myBattlefield) {B}{T}:life:-1 opponent >1 text=({T}: Add {B} to your mana pool.) -- Leechridden Swamp enters the battlefield tapped. -- {B}, {T}: Each opponent loses 1 life. Activate this ability only if you control two or more black permanents. type=Land @@ -42130,7 +42125,6 @@ toughness=2 [/card] [card] name=Mountain -auto={T}: Add {R} text=R type=Basic Land subtype=Mountain @@ -42437,7 +42431,6 @@ toughness=4 name=Murmuring Bosk auto=tap auto=aslongas(treefolk|myhand) untap -auto={T}:Add{G} auto={T}:Add{W} && damage:1 controller auto={T}:Add{B} && damage:1 controller text=({T}: Add {G} to your mana pool.) -- As Murmuring Bosk enters the battlefield, you may reveal a Treefolk card from your hand. If you don't, Murmuring Bosk enters the battlefield tapped. -- {T}: Add {W} or {B} to your mana pool. Murmuring Bosk deals 1 damage to you. @@ -45853,8 +45846,6 @@ type=Enchantment name=Overgrown Tomb auto=tap auto=may untap && life:-2 controller -auto={T}:Add {B} -auto={T}:Add {G} text=({T}: Add {B} or {G} to your mana pool.) -- As Overgrown Tomb enters the battlefield, you may pay 2 life. If you don't, Overgrown Tomb enters the battlefield tapped. type=Land subtype=Swamp Forest @@ -48100,7 +48091,6 @@ toughness=1 [/card] [card] name=Plains -auto={T}: Add {W} text=W type=Basic Land subtype=Plains @@ -48185,8 +48175,6 @@ toughness=1 [/card] [card] name=Plateau -auto={T}:Add {R} -auto={T}:Add {W} type=Land subtype=Mountain Plains [/card] @@ -54017,8 +54005,6 @@ toughness=3 name=Sacred Foundry auto=tap auto=may untap && life:-2 controller -auto={T}:Add {R} -auto={T}:Add {W} text=({T}: Add {R} or {W} to your mana pool.) -- As Sacred Foundry enters the battlefield, you may pay 2 life. If you don't, Sacred Foundry enters the battlefield tapped. type=Land subtype=Mountain Plains @@ -54662,7 +54648,6 @@ type=Land [card] name=Sapseep Forest auto=tap -auto={T}:Add {G} auto=aslongas(*[green]|myBattlefield) {G}{T}:life:1 controller >1 text=({T}: Add {G} to your mana pool.) -- Sapseep Forest enters the battlefield tapped. -- {G}, {T}: You gain 1 life. Activate this ability only if you control two or more green permanents. type=Land @@ -54844,8 +54829,6 @@ type=Sorcery [/card] [card] name=Savannah -auto={T}:Add {W} -auto={T}:Add {G} type=Land subtype=Forest Plains [/card] @@ -55540,8 +55523,6 @@ toughness=3 [/card] [card] name=Scrubland -auto={T}:Add {W} -auto={T}:Add {B} type=Land subtype=Plains Swamp [/card] @@ -60057,35 +60038,30 @@ toughness=1 [/card] [card] name=Snow-Covered Forest -auto={T}:Add {G} text=G type=Basic Snow Land subtype=Forest [/card] [card] name=Snow-Covered Island -auto={T}:Add {U} text=U type=Basic Snow Land subtype=Island [/card] [card] name=Snow-Covered Mountain -auto={T}:Add {R} text=R type=Basic Snow Land subtype=Mountain [/card] [card] name=Snow-Covered Plains -auto={T}:Add {W} text=W type=Basic Snow Land subtype=Plains [/card] [card] name=Snow-Covered Swamp -auto={T}:Add {B} text=B type=Basic Snow Land subtype=Swamp @@ -62691,8 +62667,6 @@ toughness=5 name=Steam Vents auto=tap auto=may untap && life:-2 controller -auto={T}:Add {U} -auto={T}:Add {R} text=({T}: Add {U} or {R} to your mana pool.) -- As Steam Vents enters the battlefield, you may pay 2 life. If you don't, Steam Vents enters the battlefield tapped. type=Land subtype=Island Mountain @@ -62995,8 +62969,6 @@ toughness=3 name=Stomping Ground auto=tap auto=may untap && life:-2 controller -auto={T}:Add {R} -auto={T}:Add {G} text=({T}: Add {R} or {G} to your mana pool.) -- As Stomping Ground enters the battlefield, you may pay 2 life. If you don't, Stomping Ground enters the battlefield tapped. type=Land subtype=Mountain Forest @@ -64418,7 +64390,6 @@ subtype=Arcane [/card] [card] name=Swamp -auto={T}: Add {B} text=B type=Basic Land subtype=Swamp @@ -64851,8 +64822,6 @@ toughness=5 [/card] [card] name=Taiga -auto={T}:Add {G} -auto={T}:Add {R} type=Land subtype=Mountain Forest [/card] @@ -65855,8 +65824,6 @@ toughness=2 name=Temple Garden auto=tap auto=may untap && life:-2 controller -auto={T}:Add {G} -auto={T}:Add {W} text=({T}: Add {G} or {W} to your mana pool.) -- As Temple Garden enters the battlefield, you may pay 2 life. If you don't, Temple Garden enters the battlefield tapped. type=Land subtype=Forest Plains @@ -69106,8 +69073,6 @@ toughness=3 [/card] [card] name=Tropical Island -auto={T}:Add {G} -auto={T}:Add {U} type=Land subtype=Forest Island [/card] @@ -69258,8 +69223,6 @@ type=Artifact [/card] [card] name=Tundra -auto={T}:Add {U} -auto={T}:Add {W} type=Land subtype=Plains Island [/card] @@ -69690,8 +69653,6 @@ type=Land [/card] [card] name=Underground Sea -auto={T}:Add {B} -auto={T}:Add {U} type=Land subtype=Island Swamp [/card] @@ -72406,8 +72367,6 @@ type=Sorcery [/card] [card] name=Volcanic Island -auto={T}:Add {U} -auto={T}:Add {R} type=Land subtype=Island Mountain [/card] @@ -73773,8 +73732,6 @@ type=Land name=Watery Grave auto=tap auto=may untap && life:-2 controller -auto={T}:Add {U} -auto={T}:Add {B} text=({T}: Add {U} or {B} to your mana pool.) -- As Watery Grave enters the battlefield, you may pay 2 life. If you don't, Watery Grave enters the battlefield tapped. type=Land subtype=Island Swamp diff --git a/projects/mtg/bin/Res/sets/primitives/unsupported.txt b/projects/mtg/bin/Res/sets/primitives/unsupported.txt index c49238b80..be530e8d0 100644 --- a/projects/mtg/bin/Res/sets/primitives/unsupported.txt +++ b/projects/mtg/bin/Res/sets/primitives/unsupported.txt @@ -6574,18 +6574,6 @@ power=2 toughness=2 [/card] [card] -#Need a way for the target to lose its land subtypes. -#Need to move the {T}:Add{X} rules for basic lands outside of the cards and into the rules <-- easy? -name=Evil Presence -text=Enchant land -- Enchanted land is a Swamp. -target=land -auto=loseabilities -auto=transforms((swamp,)) -mana={B} -type=Enchantment -subtype=Aura -[/card] -[card] name=Excavation text={1}, Sacrifice a land: Draw a card. Any player may activate this ability. mana={1}{U} diff --git a/projects/mtg/bin/Res/test/_tests.txt b/projects/mtg/bin/Res/test/_tests.txt index 301288076..f4a3d0570 100644 --- a/projects/mtg/bin/Res/test/_tests.txt +++ b/projects/mtg/bin/Res/test/_tests.txt @@ -257,6 +257,9 @@ enervate.txt enchantress_s_presence.txt Eradicate.txt erg_raiders_i157.txt +evil_presence.txt +evil_presence2.txt +evil_presence3.txt explore.txt Faceless_Butcher.txt fangren_pathcutter.txt diff --git a/projects/mtg/bin/Res/test/evil_presence.txt b/projects/mtg/bin/Res/test/evil_presence.txt new file mode 100644 index 000000000..bf4774fc4 --- /dev/null +++ b/projects/mtg/bin/Res/test/evil_presence.txt @@ -0,0 +1,19 @@ +#Testing Evil Presence on Gaea's Cradle +[INIT] +FIRSTMAIN +[PLAYER1] +hand:Evil PResence +inplay:Gaea's Cradle,raging goblin, grizzly bears +manapool:{B} +[PLAYER2] +[DO] +Evil PResence +Gaea's Cradle +Gaea's Cradle +[ASSERT] +FIRSTMAIN +[PLAYER1] +inplay:Gaea's Cradle,raging goblin, grizzly bears,Evil PResence +manapool:{B} +[PLAYER2] +[END] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/evil_presence2.txt b/projects/mtg/bin/Res/test/evil_presence2.txt new file mode 100644 index 000000000..e181ba9cd --- /dev/null +++ b/projects/mtg/bin/Res/test/evil_presence2.txt @@ -0,0 +1,22 @@ +#Testing Evil Presence on Gaea's Cradle +[INIT] +FIRSTMAIN +[PLAYER1] +hand:Evil PResence, disenchant +inplay:Gaea's Cradle,raging goblin,grizzly bears +manapool:{B}{1}{W} +[PLAYER2] +[DO] +Evil PResence +Gaea's Cradle +Disenchant +Evil PResence +Gaea's Cradle +[ASSERT] +FIRSTMAIN +[PLAYER1] +inplay:Gaea's Cradle,raging goblin, grizzly bears +graveyard:Evil PResence,Disenchant +manapool:{G}{G} +[PLAYER2] +[END] \ No newline at end of file diff --git a/projects/mtg/bin/Res/test/evil_presence3.txt b/projects/mtg/bin/Res/test/evil_presence3.txt new file mode 100644 index 000000000..40bc62e9e --- /dev/null +++ b/projects/mtg/bin/Res/test/evil_presence3.txt @@ -0,0 +1,19 @@ +#Testing Evil Presence on a Forest +[INIT] +FIRSTMAIN +[PLAYER1] +hand:Evil PResence +inplay:Forest +manapool:{B} +[PLAYER2] +[DO] +Evil PResence +Forest +Forest +[ASSERT] +FIRSTMAIN +[PLAYER1] +inplay:Forest,Evil Presence +manapool:{B} +[PLAYER2] +[END] \ No newline at end of file diff --git a/projects/mtg/include/AllAbilities.h b/projects/mtg/include/AllAbilities.h index 4b84f923f..335040493 100644 --- a/projects/mtg/include/AllAbilities.h +++ b/projects/mtg/include/AllAbilities.h @@ -3617,6 +3617,18 @@ public: ALoseAbilities * clone() const; }; +//Remove subtypes (of a given type) from target +class ALoseSubtypes: public MTGAbility +{ +public: + int parentType; + vector storedSubtypes; + ALoseSubtypes(int id, MTGCardInstance * source, MTGCardInstance * target, int parentType); + int addToGame(); + int destroy(); + ALoseSubtypes * clone() const; +}; + //Adds types/abilities/P/T to a card (until end of turn) class APreventDamageTypesUEOT: public InstantAbility { diff --git a/projects/mtg/include/Subtypes.h b/projects/mtg/include/Subtypes.h index d4ebe4da6..b217e0533 100644 --- a/projects/mtg/include/Subtypes.h +++ b/projects/mtg/include/Subtypes.h @@ -19,20 +19,34 @@ public: TYPE_LAND = 5, TYPE_ARTIFACT = 6, TYPE_LEGENDARY = 7, - TYPE_EQUIPMENT = 8, - TYPE_AURA = 9, - TYPE_PLANESWALKER = 10, - LAST_TYPE = TYPE_PLANESWALKER, + TYPE_SNOW = 8, + TYPE_BASIC = 9, + TYPE_WORLD = 10, + TYPE_EQUIPMENT = 11, + TYPE_AURA = 12, + TYPE_PLANESWALKER = 13, + TYPE_TRIBAL = 14, + TYPE_PLANE = 15, + TYPE_SCHEME = 16, + TYPE_VANGUARD = 17, + LAST_TYPE = TYPE_VANGUARD, }; protected: map values; vector valuesById; + map subtypesToType; public: static Subtypes * subtypesList; Subtypes(); int find(string subtype, bool forceAdd = true); string find(unsigned int id); + bool isSubtypeOfType(string subtype, string type); + bool isSubtypeOfType(unsigned int subtype, unsigned int type); + bool isSuperType(int type); + bool isType(int type); + bool isSubType(int type); + int add(string value, int parentType); }; #endif diff --git a/projects/mtg/src/AllAbilities.cpp b/projects/mtg/src/AllAbilities.cpp index eeed6bee9..c3bd10b37 100644 --- a/projects/mtg/src/AllAbilities.cpp +++ b/projects/mtg/src/AllAbilities.cpp @@ -2857,6 +2857,51 @@ ALoseAbilities * ALoseAbilities::clone() const return a; } +//ALoseSubtypes +ALoseSubtypes::ALoseSubtypes(int id, MTGCardInstance * source, MTGCardInstance * _target, int parentType) : + MTGAbility(id, source), parentType(parentType) +{ + target = _target; +} + +int ALoseSubtypes::addToGame() +{ + if (storedSubtypes.size()) + { + DebugTrace("FATAL:storedSubtypes shouldn't be already set inALoseSubtypes\n"); + return 0; + } + MTGCardInstance * _target = (MTGCardInstance *)target; + + for (int i = ((int)_target->types.size())-1; i >= 0; --i) + { + int subtype = _target->types[i]; + if (Subtypes::subtypesList->isSubtypeOfType(subtype, parentType)) + { + storedSubtypes.push_back(subtype); + _target->removeType(subtype); + } + } + + return MTGAbility::addToGame(); +} + +int ALoseSubtypes::destroy() +{ + MTGCardInstance * _target = (MTGCardInstance *)target; + for (size_t i = 0; i < storedSubtypes.size(); ++i) + _target->addType(storedSubtypes[i]); + storedSubtypes.clear(); + return 1; +} + +ALoseSubtypes * ALoseSubtypes::clone() const +{ + ALoseSubtypes * a = NEW ALoseSubtypes(*this); + a->isClone = 1; + return a; +} + //APreventDamageTypes APreventDamageTypes::APreventDamageTypes(int id, MTGCardInstance * source, string to, string from, int type) : MTGAbility(id, source), to(to), from(from), type(type) diff --git a/projects/mtg/src/CardPrimitive.cpp b/projects/mtg/src/CardPrimitive.cpp index d1c188259..52c878f2f 100644 --- a/projects/mtg/src/CardPrimitive.cpp +++ b/projects/mtg/src/CardPrimitive.cpp @@ -196,7 +196,17 @@ void CardPrimitive::addType(char * _type_text) void CardPrimitive::setSubtype(const string& value) { - int id = Subtypes::subtypesList->find(value); + //find the parent type for this card + int parentType = 0; + for (size_t i = 0; i < types.size(); ++i) + { + if (Subtypes::subtypesList->isType(types[i])) + { + parentType = types[i]; + break; + } + } + int id = Subtypes::subtypesList->add(value, parentType); addType(id); } diff --git a/projects/mtg/src/MTGAbility.cpp b/projects/mtg/src/MTGAbility.cpp index 8ac0c21b3..a0ffe18d4 100644 --- a/projects/mtg/src/MTGAbility.cpp +++ b/projects/mtg/src/MTGAbility.cpp @@ -1814,6 +1814,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG return a; } + //Lose subtypes of a given type + vector splitLoseTypes = parseBetween(s, "losesubtypesof(", ")"); + if (splitLoseTypes.size()) + { + int parentType = Subtypes::subtypesList->find(splitLoseTypes[1]); + return NEW ALoseSubtypes(id, card, target, parentType); + } + //Cast/Play Restrictions for (size_t i = 0; i < kMaxCastKeywordsCount; ++i) { diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index 2a2d23757..395edb676 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -78,25 +78,13 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi string value = val; //Specific Abilities std::transform(value.begin(), value.end(), value.begin(), ::tolower); - while (value.size()) + vector values = split(value, ','); + for (size_t values_i = 0; values_i < values.size(); ++values_i) { - string attribute; - size_t found2 = value.find(','); - if (found2 != string::npos) - { - attribute = value.substr(0, found2); - value = value.substr(found2 + 1); - } - else - { - attribute = value; - value = ""; - } for (int j = Constants::NB_BASIC_ABILITIES - 1; j >= 0; --j) { - size_t found = attribute.find(Constants::MTGBasicAbilities[j]); - if (found != string::npos) + if (values[values_i].find(Constants::MTGBasicAbilities[j]) != string::npos) { primitive->basicAbilities[j] = 1; break; @@ -249,7 +237,7 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi card->setRarity(val[0]); } break; - case 's': //subtype + case 's': //subtype, suspend { if (s.find("suspend") != string::npos) { @@ -269,21 +257,9 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi else { if (!primitive) primitive = NEW CardPrimitive(); - while (true) - { - char* found = strchr(val, ' '); - if (found) - { - string value(val, found - val); - primitive->setSubtype(value); - val = found + 1; - } - else - { - primitive->setSubtype(val); - break; - } - } + vector values = split(val, ' '); + for (size_t values_i = 0; values_i < values.size(); ++values_i) + primitive->setSubtype(values[values_i]); } break; } @@ -299,21 +275,9 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi primitive->setText(val); else if (0 == strcmp("type", key)) { - while (true) - { - char* found = strchr(val, ' '); - if (found) - { - string value(val, found - val); - primitive->setType(value); - val = found + 1; - } - else - { - primitive->setType(val); - break; - } - } + vector values = split(val, ' '); + for (size_t values_i = 0; values_i < values.size(); ++values_i) + primitive->setType(values[values_i]); } else if (0 == strcmp("toughness", key)) primitive->setToughness(atoi(val)); break; diff --git a/projects/mtg/src/Subtypes.cpp b/projects/mtg/src/Subtypes.cpp index cf3666dfb..815d0aef6 100644 --- a/projects/mtg/src/Subtypes.cpp +++ b/projects/mtg/src/Subtypes.cpp @@ -15,9 +15,16 @@ Subtypes::Subtypes() find("Land"); find("Artifact"); find("Legendary"); + find("Snow"); + find("Basic"); + find("World"); find("Equipment"); find("Aura"); find("Planeswalker"); + find("Tribal"); + find("Plane"); + find("Scheme"); + find("Vanguard"); } int Subtypes::find(string value, bool forceAdd) @@ -32,8 +39,57 @@ int Subtypes::find(string value, bool forceAdd) return id; } +// Adds a subtype to the list, and associated it with a parent type. +//The association can happen only once, a subtype is then definitely associated to its parent type. +// If you associate "goblin" to "creature", trying to associate "goblin" to "land" afterwards will fail. "goblin" will stay associated to its first parent. +int Subtypes::add(string value, int parentType) +{ + int subtype = find(value); + if (parentType && isSubType(subtype) && !subtypesToType[subtype]) + subtypesToType[subtype] = parentType; + return subtype; +} + string Subtypes::find(unsigned int id) { if (valuesById.size() < id || !id) return ""; return valuesById[id - 1]; } + +bool Subtypes::isSubtypeOfType(string subtype, string type) +{ + unsigned int subtypeInt = find(subtype); + unsigned int typeInt = find(type); + return isSubtypeOfType(subtypeInt, typeInt); +} +bool Subtypes::isSubtypeOfType(unsigned int subtype, unsigned int type) +{ + return (subtypesToType[subtype] == type); +} + +bool Subtypes::isSuperType(int type) +{ + return (type == TYPE_BASIC || type == TYPE_WORLD || type == TYPE_SNOW || type == TYPE_LEGENDARY); +} + +bool Subtypes::isType(int type) +{ + return ( + type == TYPE_CREATURE || + type == TYPE_ENCHANTMENT || + type == TYPE_SORCERY || + type == TYPE_INSTANT || + type == TYPE_LAND || + type == TYPE_ARTIFACT || + type ==TYPE_PLANESWALKER || + type == TYPE_TRIBAL || + type == TYPE_PLANE || + type == TYPE_SCHEME || + type == TYPE_VANGUARD + ); +} + +bool Subtypes::isSubType(int type) +{ + return (!isSuperType(type) && !isType(type)); +} \ No newline at end of file