- 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:
@@ -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(*)
|
||||
|
||||
@@ -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(*)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
19
projects/mtg/bin/Res/test/evil_presence.txt
Normal file
19
projects/mtg/bin/Res/test/evil_presence.txt
Normal 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]
|
||||
22
projects/mtg/bin/Res/test/evil_presence2.txt
Normal file
22
projects/mtg/bin/Res/test/evil_presence2.txt
Normal 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]
|
||||
19
projects/mtg/bin/Res/test/evil_presence3.txt
Normal file
19
projects/mtg/bin/Res/test/evil_presence3.txt
Normal 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]
|
||||
@@ -3617,6 +3617,18 @@ public:
|
||||
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)
|
||||
class APreventDamageTypesUEOT: public InstantAbility
|
||||
{
|
||||
|
||||
@@ -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<string, int> values;
|
||||
vector<string> valuesById;
|
||||
map<int,int> 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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -1814,6 +1814,14 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
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
|
||||
for (size_t i = 0; i < kMaxCastKeywordsCount; ++i)
|
||||
{
|
||||
|
||||
@@ -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<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)
|
||||
{
|
||||
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<string> 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<string> 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;
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
Reference in New Issue
Block a user