Files
wagic/projects/mtg/src/CardDescriptor.cpp
T
solo81@web.de 07361b19f5 This is another patch by the great newcomer salmelo.
Salmelo:"Here is another patch, this time adding counters to target specifications, so now you should be able to target things with counters on them as well as use counters for criterion for Lord, aslongas, foreach, etc.
I had to muddle the syntax a little bit though, so heres an example, taken from gwafa hazid, whom I added to the primitives to test with.

lord(creature[counter{0/0.1.Bribe}]|opponentbattlefield) cantattack

obviously the part we are worried about is the counter part, note that those are curly braces { } and periods . instead of parentheses ( ) and commas , this is so that it does not conflict with how targets are normally parsed, which it did before I changed those. Counters still work the same way everywhere else though, you only need to use { } and periods in target code.

Also, you can use counter{any} to specify that it should look for things with any kind of counter on them, not just specific ones, this is used by Kulrath Knight, for example.

I also consolidated most of the code used to parse counter specifications, as it seemed unnecessary duplicating it three times.

Anyway, aside from this major addition, I also added Gwafa Hazid, Profiteer; and Kulrath Knight to the primitives, as well as a test file for each to make sure it worked.

Hopefully y'all will find this patch useful.

Oh, and I should point out that it only works with one Counter in the target specification, i imagine if you put two in the same one then it would either overwrite the first with the second or merge them into some sort of hybrid counter monstrosity, either way, I wouldn't suggest it. "

Cards with vanishing are also codable now. Have a look at the comments for explanation.

daily_build.
2010-03-24 21:15:34 +00:00

226 lines
6.2 KiB
C++

#include "../include/config.h"
#include "../include/CardDescriptor.h"
#include "../include/Subtypes.h"
#include "../include/Counters.h"
CardDescriptor::CardDescriptor(): MTGCardInstance(){
init();
counterName = "";
counterPower = 0;
counterToughness = 0;
counterNB = 0;
mode = CD_AND;
powerComparisonMode = COMPARISON_NONE;
toughnessComparisonMode = COMPARISON_NONE;
manacostComparisonMode = COMPARISON_NONE;
counterComparisonMode = COMPARISON_NONE;
convertedManacost = -1;
}
int CardDescriptor::init(){
int result = MTGCardInstance::init();
attacker = 0;
defenser = NULL;
banding = NULL;
anyCounter = 0;
//Remove unnecessary pointers
SAFE_DELETE(counters);
SAFE_DELETE(previous);
return result;
}
void CardDescriptor::unsecureSetTapped(int i){
tapped = i;
}
void CardDescriptor::setNegativeSubtype( string value){
int id = Subtypes::subtypesList->find(value);
addType(-id);
}
// Very generic function to compare a value to a criterion.
// Should be easily transferable to a more generic class if desired.
bool CardDescriptor::valueInRange(int comparisonMode, int value, int criterion){
switch (comparisonMode){
case COMPARISON_AT_MOST:
return (value <= criterion);
case COMPARISON_AT_LEAST:
return (value >= criterion);
case COMPARISON_EQUAL:
return (value == criterion);
case COMPARISON_GREATER:
return (value > criterion);
case COMPARISON_LESS:
return (value < criterion);
case COMPARISON_UNEQUAL:
return (value != criterion);
}
return false;
}
MTGCardInstance * CardDescriptor::match_or(MTGCardInstance * card){
int found = 1;
for (size_t i = 0; i< types.size(); i++){
found = 0;
if (types[i] >= 0){
if (card->hasSubtype(types[i]) || (Subtypes::subtypesList->find(card->getLCName(),false) == types[i])){
found = 1;
break;
}
}else{
if (!card->hasSubtype(-types[i]) && (Subtypes::subtypesList->find(card->getLCName(), false) != -types[i])){
found = 1;
break;
}
}
}
if (!found) return NULL;
for (int i = 0; i< Constants::MTG_NB_COLORS; i++){
if (colors[i] == 1){
found = 0;
if(card->hasColor(i)){
found = 1;
break;
}
}
else if (colors[i] == -1){
found = 0;
if(!card->hasColor(i)){
found = 1;
break;
}
}
}
if (!found) return NULL;
// Quantified restrictions are always AND-ed:
if (powerComparisonMode && !valueInRange(powerComparisonMode, card->getPower(), power) ) return NULL;
if (toughnessComparisonMode && !valueInRange(toughnessComparisonMode, card->getToughness(), toughness) ) return NULL;
if (manacostComparisonMode && !valueInRange(manacostComparisonMode, card->getManaCost()->getConvertedCost(), convertedManacost) ) return NULL;
return card;
}
MTGCardInstance * CardDescriptor::match_and(MTGCardInstance * card){
MTGCardInstance * match = card;
for (size_t i = 0; i< types.size(); i++){
if (types[i] >= 0){
if (!card->hasSubtype(types[i]) && !(Subtypes::subtypesList->find(card->getLCName(),false) == types[i])){
match = NULL;
}
}else{
if(card->hasSubtype(-types[i]) || (Subtypes::subtypesList->find(card->getLCName(),false) == -types[i])){
match = NULL;
}
}
}
for (int i = 0; i< Constants::MTG_NB_COLORS; i++){
if ((colors[i] == 1 && !card->hasColor(i))||(colors[i] == -1 && card->hasColor(i))){
match = NULL;
}
}
if (powerComparisonMode && !valueInRange(powerComparisonMode, card->getPower(), power) ) match = NULL;
if (toughnessComparisonMode && !valueInRange(toughnessComparisonMode, card->getToughness(), toughness) ) match = NULL;
if (manacostComparisonMode && !valueInRange(manacostComparisonMode, card->getManaCost()->getConvertedCost(), convertedManacost) ) match = NULL;
return match;
}
MTGCardInstance * CardDescriptor::match(MTGCardInstance * card){
MTGCardInstance * match = card;
if (mode == CD_AND){
match = match_and(card);
}else{
match=match_or(card);
}
//Abilities
for(map<int,int>::const_iterator it = basicAbilities.begin(); it != basicAbilities.end(); ++it){
int j = it->first;
if ((basicAbilities[j] == 1 && !card->basicAbilities[j]) || (basicAbilities[j] == -1 && card->basicAbilities[j])){
match = NULL;
}
}
if ((tapped == -1 && card->isTapped()) || (tapped == 1 && !card->isTapped())){
match = NULL;
}
if ((isToken== -1 && card->isToken) || (isToken == 1 && !card->isToken)){
match = NULL;
}
if (attacker == 1){
if (defenser == &AnyCard){
if (!card->attacker && !card->defenser) match = NULL;
}else{
if (!card->attacker) match = NULL;
}
}else if (attacker == -1){
if (defenser == &NoCard){
if (card->attacker || card->defenser) match = NULL;
}else{
if (card->attacker) match = NULL;
}
}else{
if (defenser == &NoCard){
if (card->defenser) match = NULL;
}else if (defenser == &AnyCard){
if (!card->defenser) match = NULL;
}else{
// we don't care about the attack/blocker state
}
}
//Counters
if (anyCounter) {
if (!(card->counters->mCount)) {
match = NULL;
}else{
int hasCounter = 0;
for (int i = 0; i < card->counters->mCount; i++) {
if (card->counters->counters[i]->nb > 0) hasCounter = 1;
}
if (!hasCounter) match = NULL;
}
}else{
if (counterComparisonMode) {
Counter * targetCounter = card->counters->hasCounter(counterName.c_str(),counterPower,counterToughness);
if (targetCounter) {
if (!valueInRange(counterComparisonMode,targetCounter->nb,counterNB)) match = NULL;
} else {
if (counterComparisonMode != COMPARISON_LESS && counterComparisonMode != COMPARISON_AT_MOST) match = NULL;
}
}
}
return match;
}
MTGCardInstance * CardDescriptor::match(MTGGameZone * zone){
return (nextmatch(zone, NULL));
}
MTGCardInstance * CardDescriptor::nextmatch(MTGGameZone * zone, MTGCardInstance * previous){
int found = 0;
if (NULL == previous) found = 1;
for(int i=0; i < zone->nb_cards; i++){
if(found && match(zone->cards[i])){
return zone->cards[i];
}
if (zone->cards[i] == previous){
found = 1;
}
}
return NULL;
}