- 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
+45
View File
@@ -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)
+11 -1
View File
@@ -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);
}
+8
View File
@@ -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)
{
+10 -46
View File
@@ -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;
+56
View File
@@ -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));
}