- 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.
This commit is contained in:
wagic.the.homebrew
2011-05-04 04:04:03 +00:00
parent 494bcf3315
commit d922d4fe06
15 changed files with 250 additions and 118 deletions

View File

@@ -9,6 +9,14 @@ auto=draw:7
auto=@each my draw:draw:1 auto=@each my draw:draw:1
auto=maxPlay(land)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 #Mana Empties from manapool at the end of each phase
auto=@each untap:removeMana(*) auto=@each untap:removeMana(*)
auto=@each upkeep:removeMana(*) auto=@each upkeep:removeMana(*)

View File

@@ -7,6 +7,13 @@ life:20
auto=@each my draw:draw:1 auto=@each my draw:draw:1
auto=maxPlay(land)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 #Mana Empties from manapool at the end of each phase
auto=@each untap:removeMana(*) auto=@each untap:removeMana(*)
auto=@each upkeep:removeMana(*) auto=@each upkeep:removeMana(*)

View File

@@ -4269,8 +4269,6 @@ type=Land
[/card] [/card]
[card] [card]
name=Badlands name=Badlands
auto={T}:Add {R}
auto={T}:Add {B}
type=Land type=Land
subtype=Swamp Mountain subtype=Swamp Mountain
[/card] [/card]
@@ -5252,8 +5250,6 @@ toughness=1
[/card] [/card]
[card] [card]
name=Bayou name=Bayou
auto={T}:Add {B}
auto={T}:Add {G}
type=Land type=Land
subtype=Swamp Forest subtype=Swamp Forest
[/card] [/card]
@@ -6678,8 +6674,6 @@ toughness=2
name=Blood Crypt name=Blood Crypt
auto=tap auto=tap
auto=may untap && life:-2 controller 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. 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 type=Land
subtype=Swamp Mountain subtype=Swamp Mountain
@@ -8203,8 +8197,6 @@ type=Enchantment
name=Breeding Pool name=Breeding Pool
auto=tap auto=tap
auto=may untap && life:-2 controller 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. 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 type=Land
subtype=Forest Island subtype=Forest Island
@@ -17855,10 +17847,9 @@ type=Sorcery
[/card] [/card]
[card] [card]
name=Dryad Arbor 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. 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 color=green
type=Land Creature type=Creature Land
subtype=Forest Dryad subtype=Forest Dryad
power=1 power=1
toughness=1 toughness=1
@@ -20461,6 +20452,17 @@ power=6
toughness=3 toughness=3
[/card] [/card]
[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 name=Evincar's Justice
auto=damage:2 all(creature,player) auto=damage:2 all(creature,player)
buyback={2}{B}{B}{3} buyback={2}{B}{B}{3}
@@ -23529,7 +23531,6 @@ subtype=Aura
[/card] [/card]
[card] [card]
name=Forest name=Forest
auto={T}: Add {G}
text=G text=G
type=Basic Land type=Basic Land
subtype=Forest subtype=Forest
@@ -26788,8 +26789,6 @@ toughness=4
name=Godless Shrine name=Godless Shrine
auto=tap auto=tap
auto=may untap && life:-2 controller 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. 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 type=Land
subtype=Plains Swamp subtype=Plains Swamp
@@ -28498,8 +28497,6 @@ toughness=3
name=Hallowed Fountain name=Hallowed Fountain
auto=tap auto=tap
auto=may untap && life:-2 controller 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. 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 type=Land
subtype=Plains Island subtype=Plains Island
@@ -32457,7 +32454,6 @@ toughness=1
[/card] [/card]
[card] [card]
name=Island name=Island
auto={T}: Add {U}
text=U text=U
type=Basic Land type=Basic Land
subtype=Island subtype=Island
@@ -36645,7 +36641,6 @@ toughness=5
[card] [card]
name=Leechridden Swamp name=Leechridden Swamp
auto=tap auto=tap
auto={T}:Add {B}
auto=aslongas(*[black]|myBattlefield) {B}{T}:life:-1 opponent >1 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. 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 type=Land
@@ -42130,7 +42125,6 @@ toughness=2
[/card] [/card]
[card] [card]
name=Mountain name=Mountain
auto={T}: Add {R}
text=R text=R
type=Basic Land type=Basic Land
subtype=Mountain subtype=Mountain
@@ -42437,7 +42431,6 @@ toughness=4
name=Murmuring Bosk name=Murmuring Bosk
auto=tap auto=tap
auto=aslongas(treefolk|myhand) untap auto=aslongas(treefolk|myhand) untap
auto={T}:Add{G}
auto={T}:Add{W} && damage:1 controller auto={T}:Add{W} && damage:1 controller
auto={T}:Add{B} && 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. 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 name=Overgrown Tomb
auto=tap auto=tap
auto=may untap && life:-2 controller 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. 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 type=Land
subtype=Swamp Forest subtype=Swamp Forest
@@ -48100,7 +48091,6 @@ toughness=1
[/card] [/card]
[card] [card]
name=Plains name=Plains
auto={T}: Add {W}
text=W text=W
type=Basic Land type=Basic Land
subtype=Plains subtype=Plains
@@ -48185,8 +48175,6 @@ toughness=1
[/card] [/card]
[card] [card]
name=Plateau name=Plateau
auto={T}:Add {R}
auto={T}:Add {W}
type=Land type=Land
subtype=Mountain Plains subtype=Mountain Plains
[/card] [/card]
@@ -54017,8 +54005,6 @@ toughness=3
name=Sacred Foundry name=Sacred Foundry
auto=tap auto=tap
auto=may untap && life:-2 controller 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. 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 type=Land
subtype=Mountain Plains subtype=Mountain Plains
@@ -54662,7 +54648,6 @@ type=Land
[card] [card]
name=Sapseep Forest name=Sapseep Forest
auto=tap auto=tap
auto={T}:Add {G}
auto=aslongas(*[green]|myBattlefield) {G}{T}:life:1 controller >1 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. 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 type=Land
@@ -54844,8 +54829,6 @@ type=Sorcery
[/card] [/card]
[card] [card]
name=Savannah name=Savannah
auto={T}:Add {W}
auto={T}:Add {G}
type=Land type=Land
subtype=Forest Plains subtype=Forest Plains
[/card] [/card]
@@ -55540,8 +55523,6 @@ toughness=3
[/card] [/card]
[card] [card]
name=Scrubland name=Scrubland
auto={T}:Add {W}
auto={T}:Add {B}
type=Land type=Land
subtype=Plains Swamp subtype=Plains Swamp
[/card] [/card]
@@ -60057,35 +60038,30 @@ toughness=1
[/card] [/card]
[card] [card]
name=Snow-Covered Forest name=Snow-Covered Forest
auto={T}:Add {G}
text=G text=G
type=Basic Snow Land type=Basic Snow Land
subtype=Forest subtype=Forest
[/card] [/card]
[card] [card]
name=Snow-Covered Island name=Snow-Covered Island
auto={T}:Add {U}
text=U text=U
type=Basic Snow Land type=Basic Snow Land
subtype=Island subtype=Island
[/card] [/card]
[card] [card]
name=Snow-Covered Mountain name=Snow-Covered Mountain
auto={T}:Add {R}
text=R text=R
type=Basic Snow Land type=Basic Snow Land
subtype=Mountain subtype=Mountain
[/card] [/card]
[card] [card]
name=Snow-Covered Plains name=Snow-Covered Plains
auto={T}:Add {W}
text=W text=W
type=Basic Snow Land type=Basic Snow Land
subtype=Plains subtype=Plains
[/card] [/card]
[card] [card]
name=Snow-Covered Swamp name=Snow-Covered Swamp
auto={T}:Add {B}
text=B text=B
type=Basic Snow Land type=Basic Snow Land
subtype=Swamp subtype=Swamp
@@ -62691,8 +62667,6 @@ toughness=5
name=Steam Vents name=Steam Vents
auto=tap auto=tap
auto=may untap && life:-2 controller 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. 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 type=Land
subtype=Island Mountain subtype=Island Mountain
@@ -62995,8 +62969,6 @@ toughness=3
name=Stomping Ground name=Stomping Ground
auto=tap auto=tap
auto=may untap && life:-2 controller 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. 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 type=Land
subtype=Mountain Forest subtype=Mountain Forest
@@ -64418,7 +64390,6 @@ subtype=Arcane
[/card] [/card]
[card] [card]
name=Swamp name=Swamp
auto={T}: Add {B}
text=B text=B
type=Basic Land type=Basic Land
subtype=Swamp subtype=Swamp
@@ -64851,8 +64822,6 @@ toughness=5
[/card] [/card]
[card] [card]
name=Taiga name=Taiga
auto={T}:Add {G}
auto={T}:Add {R}
type=Land type=Land
subtype=Mountain Forest subtype=Mountain Forest
[/card] [/card]
@@ -65855,8 +65824,6 @@ toughness=2
name=Temple Garden name=Temple Garden
auto=tap auto=tap
auto=may untap && life:-2 controller 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. 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 type=Land
subtype=Forest Plains subtype=Forest Plains
@@ -69106,8 +69073,6 @@ toughness=3
[/card] [/card]
[card] [card]
name=Tropical Island name=Tropical Island
auto={T}:Add {G}
auto={T}:Add {U}
type=Land type=Land
subtype=Forest Island subtype=Forest Island
[/card] [/card]
@@ -69258,8 +69223,6 @@ type=Artifact
[/card] [/card]
[card] [card]
name=Tundra name=Tundra
auto={T}:Add {U}
auto={T}:Add {W}
type=Land type=Land
subtype=Plains Island subtype=Plains Island
[/card] [/card]
@@ -69690,8 +69653,6 @@ type=Land
[/card] [/card]
[card] [card]
name=Underground Sea name=Underground Sea
auto={T}:Add {B}
auto={T}:Add {U}
type=Land type=Land
subtype=Island Swamp subtype=Island Swamp
[/card] [/card]
@@ -72406,8 +72367,6 @@ type=Sorcery
[/card] [/card]
[card] [card]
name=Volcanic Island name=Volcanic Island
auto={T}:Add {U}
auto={T}:Add {R}
type=Land type=Land
subtype=Island Mountain subtype=Island Mountain
[/card] [/card]
@@ -73773,8 +73732,6 @@ type=Land
name=Watery Grave name=Watery Grave
auto=tap auto=tap
auto=may untap && life:-2 controller 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. 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 type=Land
subtype=Island Swamp subtype=Island Swamp

View File

@@ -6574,18 +6574,6 @@ power=2
toughness=2 toughness=2
[/card] [/card]
[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 name=Excavation
text={1}, Sacrifice a land: Draw a card. Any player may activate this ability. text={1}, Sacrifice a land: Draw a card. Any player may activate this ability.
mana={1}{U} mana={1}{U}

View File

@@ -257,6 +257,9 @@ enervate.txt
enchantress_s_presence.txt enchantress_s_presence.txt
Eradicate.txt Eradicate.txt
erg_raiders_i157.txt erg_raiders_i157.txt
evil_presence.txt
evil_presence2.txt
evil_presence3.txt
explore.txt explore.txt
Faceless_Butcher.txt Faceless_Butcher.txt
fangren_pathcutter.txt fangren_pathcutter.txt

View File

@@ -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]

View File

@@ -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]

View File

@@ -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]

View File

@@ -3617,6 +3617,18 @@ public:
ALoseAbilities * clone() const; ALoseAbilities * clone() const;
}; };
//Remove subtypes (of a given type) from target
class ALoseSubtypes: public MTGAbility
{
public:
int parentType;
vector <int> 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) //Adds types/abilities/P/T to a card (until end of turn)
class APreventDamageTypesUEOT: public InstantAbility class APreventDamageTypesUEOT: public InstantAbility
{ {

View File

@@ -19,20 +19,34 @@ public:
TYPE_LAND = 5, TYPE_LAND = 5,
TYPE_ARTIFACT = 6, TYPE_ARTIFACT = 6,
TYPE_LEGENDARY = 7, TYPE_LEGENDARY = 7,
TYPE_EQUIPMENT = 8, TYPE_SNOW = 8,
TYPE_AURA = 9, TYPE_BASIC = 9,
TYPE_PLANESWALKER = 10, TYPE_WORLD = 10,
LAST_TYPE = TYPE_PLANESWALKER, 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: protected:
map<string, int> values; map<string, int> values;
vector<string> valuesById; vector<string> valuesById;
map<int,int> subtypesToType;
public: public:
static Subtypes * subtypesList; static Subtypes * subtypesList;
Subtypes(); Subtypes();
int find(string subtype, bool forceAdd = true); int find(string subtype, bool forceAdd = true);
string find(unsigned int id); 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 #endif

View File

@@ -2857,6 +2857,51 @@ ALoseAbilities * ALoseAbilities::clone() const
return a; 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::APreventDamageTypes(int id, MTGCardInstance * source, string to, string from, int type) : APreventDamageTypes::APreventDamageTypes(int id, MTGCardInstance * source, string to, string from, int type) :
MTGAbility(id, source), to(to), from(from), type(type) MTGAbility(id, source), to(to), from(from), type(type)

View File

@@ -196,7 +196,17 @@ void CardPrimitive::addType(char * _type_text)
void CardPrimitive::setSubtype(const string& value) 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); addType(id);
} }

View File

@@ -1814,6 +1814,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return a; return a;
} }
//Lose subtypes of a given type
vector<string> splitLoseTypes = parseBetween(s, "losesubtypesof(", ")");
if (splitLoseTypes.size())
{
int parentType = Subtypes::subtypesList->find(splitLoseTypes[1]);
return NEW ALoseSubtypes(id, card, target, parentType);
}
//Cast/Play Restrictions //Cast/Play Restrictions
for (size_t i = 0; i < kMaxCastKeywordsCount; ++i) for (size_t i = 0; i < kMaxCastKeywordsCount; ++i)
{ {

View File

@@ -78,25 +78,13 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi
string value = val; string value = val;
//Specific Abilities //Specific Abilities
std::transform(value.begin(), value.end(), value.begin(), ::tolower); std::transform(value.begin(), value.end(), value.begin(), ::tolower);
while (value.size()) vector<string> 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) for (int j = Constants::NB_BASIC_ABILITIES - 1; j >= 0; --j)
{ {
size_t found = attribute.find(Constants::MTGBasicAbilities[j]); if (values[values_i].find(Constants::MTGBasicAbilities[j]) != string::npos)
if (found != string::npos)
{ {
primitive->basicAbilities[j] = 1; primitive->basicAbilities[j] = 1;
break; break;
@@ -249,7 +237,7 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi
card->setRarity(val[0]); card->setRarity(val[0]);
} }
break; break;
case 's': //subtype case 's': //subtype, suspend
{ {
if (s.find("suspend") != string::npos) if (s.find("suspend") != string::npos)
{ {
@@ -269,21 +257,9 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi
else else
{ {
if (!primitive) primitive = NEW CardPrimitive(); if (!primitive) primitive = NEW CardPrimitive();
while (true) vector<string> values = split(val, ' ');
{ for (size_t values_i = 0; values_i < values.size(); ++values_i)
char* found = strchr(val, ' '); primitive->setSubtype(values[values_i]);
if (found)
{
string value(val, found - val);
primitive->setSubtype(value);
val = found + 1;
}
else
{
primitive->setSubtype(val);
break;
}
}
} }
break; break;
} }
@@ -299,21 +275,9 @@ int MTGAllCards::processConfLine(string &s, MTGCard *card, CardPrimitive * primi
primitive->setText(val); primitive->setText(val);
else if (0 == strcmp("type", key)) else if (0 == strcmp("type", key))
{ {
while (true) vector<string> values = split(val, ' ');
{ for (size_t values_i = 0; values_i < values.size(); ++values_i)
char* found = strchr(val, ' '); primitive->setType(values[values_i]);
if (found)
{
string value(val, found - val);
primitive->setType(value);
val = found + 1;
}
else
{
primitive->setType(val);
break;
}
}
} }
else if (0 == strcmp("toughness", key)) primitive->setToughness(atoi(val)); else if (0 == strcmp("toughness", key)) primitive->setToughness(atoi(val));
break; break;

View File

@@ -15,9 +15,16 @@ Subtypes::Subtypes()
find("Land"); find("Land");
find("Artifact"); find("Artifact");
find("Legendary"); find("Legendary");
find("Snow");
find("Basic");
find("World");
find("Equipment"); find("Equipment");
find("Aura"); find("Aura");
find("Planeswalker"); find("Planeswalker");
find("Tribal");
find("Plane");
find("Scheme");
find("Vanguard");
} }
int Subtypes::find(string value, bool forceAdd) int Subtypes::find(string value, bool forceAdd)
@@ -32,8 +39,57 @@ int Subtypes::find(string value, bool forceAdd)
return id; 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) string Subtypes::find(unsigned int id)
{ {
if (valuesById.size() < id || !id) return ""; if (valuesById.size() < id || !id) return "";
return valuesById[id - 1]; 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));
}