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