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.
This commit is contained in:
@@ -16556,15 +16556,6 @@ power=1
|
||||
toughness=1
|
||||
[/card]
|
||||
[card]
|
||||
name=Gwafa Hazid, Profiteer
|
||||
text={W}{U}, {T}: Put a bribery counter on target creature you don't control. Its controller draws a card. -- Creatures with bribery counters on them can't attack or block.
|
||||
mana={1}{W}{U}
|
||||
type=Legendary Creature
|
||||
subtype=Human Rogue
|
||||
power=2
|
||||
toughness=2
|
||||
[/card]
|
||||
[card]
|
||||
name=Gwyllion Hedge-Mage
|
||||
text=When Gwyllion Hedge-Mage enters the battlefield, if you control two or more Plains, you may put a 1/1 white Kithkin Soldier creature token onto the battlefield. -- When Gwyllion Hedge-Mage enters the battlefield, if you control two or more Swamps, you may put a -1/-1 counter on target creature.
|
||||
mana={2}{WB}
|
||||
@@ -20960,15 +20951,6 @@ power=4
|
||||
toughness=3
|
||||
[/card]
|
||||
[card]
|
||||
name=Kulrath Knight
|
||||
text=Flying -- Wither (This deals damage to creatures in the form of -1/-1 counters.) -- Creatures your opponents control with counters on them can't attack or block.
|
||||
mana={3}{BR}{BR}
|
||||
type=Creature
|
||||
subtype=Elemental Knight
|
||||
power=3
|
||||
toughness=3
|
||||
[/card]
|
||||
[card]
|
||||
name=Kumano's Blessing
|
||||
text=Flash -- Enchant creature -- If a creature dealt damage by enchanted creature this turn would be put into a graveyard, exile it instead.
|
||||
mana={2}{R}
|
||||
|
||||
@@ -2281,6 +2281,21 @@ power=2
|
||||
toughness=1
|
||||
[/card]
|
||||
[card]
|
||||
name=Aven Riftwatcher
|
||||
abilities=flying
|
||||
auto=counter(0/0,3,Time)
|
||||
auto=life:2
|
||||
auto=@movedTo(this|exile,graveyard,hand,library) from(myBattlefield):life:2
|
||||
auto=@each my upkeep:counter(0/0,-1,Time)
|
||||
auto=lord(aven riftwatcher[-counter{0/0.1.Time}]|myBattlefield) -99/-99
|
||||
text=Flying -- Vanishing 3 (This permanent enters the battlefield with three time counters on it. At the beginning of your upkeep, remove a time counter from it. When the last is removed, sacrifice it.) -- When Aven Riftwatcher enters the battlefield or leaves the battlefield, you gain 2 life.
|
||||
mana={G}
|
||||
type=Creature
|
||||
subtype=Bird rebel Soldier
|
||||
power=2
|
||||
toughness=3
|
||||
[/card]
|
||||
[card]
|
||||
name=Aven Smokeweaver
|
||||
abilities=flying,protection from red
|
||||
text=Flying, protection from red
|
||||
@@ -16905,6 +16920,18 @@ mana={RG}
|
||||
type=Instant
|
||||
[/card]
|
||||
[card]
|
||||
name=Gwafa Hazid, Profiteer
|
||||
mana={1}{W}{U}
|
||||
type=Creature
|
||||
subtpe=Legendary Human Rogue
|
||||
text={W}{U}, {T}: Put a bribery counter on target creature you don't control. Its controller draws a card. -- Creatures with bribery counters on them can't attack or block.
|
||||
power=2
|
||||
toughness=2
|
||||
auto={W}{U}{T}:counter(0/0,1,Bribe) target(creature|opponentbattlefield) && draw:1
|
||||
auto=lord(creature[counter{0/0.1.Bribe}]) cantattack
|
||||
auto=lord(creature[counter{0/0.1.Bribe}]) cantblock
|
||||
[/card]
|
||||
[card]
|
||||
name=Gwendlyn Di Corci
|
||||
auto={T}:discard:1 target(player) myTurnOnly
|
||||
text={T}: Target player discards a card at random. Activate this ability only during your turn.
|
||||
@@ -21548,6 +21575,18 @@ type=Enchantment
|
||||
subtype=Aura
|
||||
[/card]
|
||||
[card]
|
||||
name=Kulrath Knight
|
||||
mana={3}{BR}{BR}
|
||||
power=3
|
||||
toughness=3
|
||||
type=Creature
|
||||
subtype=Elemental Knight
|
||||
abilities=flying,wither
|
||||
text=Flying -- Wither (This deals damage to creatures in the form of -1/-1 counters.) -- Creatures your opponents control with counters on them can't attack or block.
|
||||
auto=lord(creature[counter{any}]|opponentbattlefield) cantattack
|
||||
auto=lord(creature[counter{any}]|opponentbattlefield) cantblock
|
||||
[/card]
|
||||
[card]
|
||||
name=Kurgadon
|
||||
auto=@movedTo(creature[manacost>=6]|mystack):counter(1/1,3)
|
||||
text=Whenever you cast a creature spell with converted mana cost 6 or more, put three +1/+1 counters on Kurgadon.
|
||||
|
||||
@@ -31,6 +31,8 @@ generic/kicker.txt
|
||||
generic/kicker2.txt
|
||||
generic/landwalk.txt
|
||||
generic/legendary.txt
|
||||
generic/lord_counter.txt
|
||||
generic/lord_counter_any.txt
|
||||
generic/lifelink.txt
|
||||
generic/m10_blockers.txt
|
||||
generic/m10_blockers2.txt
|
||||
@@ -101,6 +103,8 @@ ashen_firebeast.txt
|
||||
ashen_firebeast2.txt
|
||||
aura_mutation.txt
|
||||
avarice_totem.txt
|
||||
aven_riftwatcher.txt
|
||||
aven_riftwatcher2.txt
|
||||
aysen_bureaucrats.txt
|
||||
balduvian_conjurer.txt
|
||||
baneslayer_angel.txt
|
||||
|
||||
22
projects/mtg/bin/Res/test/aven_riftwatcher.txt
Normal file
22
projects/mtg/bin/Res/test/aven_riftwatcher.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
[INIT]
|
||||
FIRSTMAIN
|
||||
[PLAYER1]
|
||||
hand:Aven Riftwatcher
|
||||
manapool:{2}{W}
|
||||
[PLAYER2]
|
||||
[DO]
|
||||
aven riftwatcher
|
||||
eot
|
||||
eot
|
||||
eot
|
||||
eot
|
||||
eot
|
||||
eot
|
||||
eot
|
||||
[ASSERT]
|
||||
untap
|
||||
[PLAYER1]
|
||||
graveyard:Aven Riftwatcher
|
||||
life:24
|
||||
[PLAYER2]
|
||||
[END]
|
||||
16
projects/mtg/bin/Res/test/aven_riftwatcher2.txt
Normal file
16
projects/mtg/bin/Res/test/aven_riftwatcher2.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
[INIT]
|
||||
FIRSTMAIN
|
||||
[PLAYER1]
|
||||
hand:Aven Riftwatcher
|
||||
manapool:{2}{W}
|
||||
[PLAYER2]
|
||||
[DO]
|
||||
aven riftwatcher
|
||||
eot
|
||||
[ASSERT]
|
||||
untap
|
||||
[PLAYER1]
|
||||
inplay:Aven Riftwatcher
|
||||
life:22
|
||||
[PLAYER2]
|
||||
[END]
|
||||
28
projects/mtg/bin/Res/test/generic/lord_counter.txt
Normal file
28
projects/mtg/bin/Res/test/generic/lord_counter.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
[INIT]
|
||||
firstmain
|
||||
[PLAYER1]
|
||||
inplay:185811
|
||||
manapool:{W}{U}
|
||||
[PLAYER2]
|
||||
inplay:Shivan Dragon
|
||||
library:Forest,Island
|
||||
[DO]
|
||||
185811
|
||||
Shivan Dragon
|
||||
eot
|
||||
next
|
||||
next
|
||||
next
|
||||
next
|
||||
next
|
||||
Shivan Dragon
|
||||
eot
|
||||
[ASSERT]
|
||||
untap
|
||||
[PLAYER1]
|
||||
inplay:185811
|
||||
life:20
|
||||
[PLAYER2]
|
||||
inplay:Shivan Dragon
|
||||
hand:Forest,Island
|
||||
[END]
|
||||
29
projects/mtg/bin/Res/test/generic/lord_counter_any.txt
Normal file
29
projects/mtg/bin/Res/test/generic/lord_counter_any.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
[INIT]
|
||||
MAINPHASE
|
||||
[PLAYER1]
|
||||
inplay:Kulrath Knight,Cinderbones
|
||||
[PLAYER2]
|
||||
inplay:Shivan Dragon
|
||||
[DO]
|
||||
next
|
||||
next
|
||||
Cinderbones
|
||||
next
|
||||
Shivan Dragon
|
||||
eot
|
||||
next
|
||||
next
|
||||
next
|
||||
next
|
||||
next
|
||||
Shivan Dragon
|
||||
eot
|
||||
[ASSERT]
|
||||
UNTAP
|
||||
[PLAYER1]
|
||||
graveyard:Cinderbones
|
||||
inplay:Kulrath Knight
|
||||
life:20
|
||||
[PLAYER2]
|
||||
inplay:Shivan Dragon
|
||||
[END]
|
||||
Binary file not shown.
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "MTGCardInstance.h"
|
||||
#include "MTGGameZones.h"
|
||||
#include "Counters.h"
|
||||
|
||||
#define CD_OR 1
|
||||
#define CD_AND 2
|
||||
@@ -32,11 +33,17 @@ class CardDescriptor: public MTGCardInstance{
|
||||
int powerComparisonMode;
|
||||
int toughnessComparisonMode;
|
||||
int manacostComparisonMode;
|
||||
int counterComparisonMode;
|
||||
int convertedManacost; // might fit better into MTGCardInstance?
|
||||
int anyCounter;
|
||||
int init();
|
||||
CardDescriptor();
|
||||
void unsecureSetTapped(int i);
|
||||
void setNegativeSubtype( string value);
|
||||
int counterPower;
|
||||
int counterToughness;
|
||||
int counterNB;
|
||||
string counterName;
|
||||
MTGCardInstance * match(MTGCardInstance * card);
|
||||
MTGCardInstance * match(MTGGameZone * zone);
|
||||
MTGCardInstance * nextmatch(MTGGameZone * zone, MTGCardInstance * previous);
|
||||
|
||||
@@ -12,6 +12,7 @@ class MTGGameZone;
|
||||
class Player;
|
||||
class AManaProducer;
|
||||
class WEvent;
|
||||
class Counter;
|
||||
|
||||
#include "../include/GameObserver.h"
|
||||
#include "ActionElement.h"
|
||||
@@ -255,6 +256,7 @@ class AbilityFactory{
|
||||
TriggeredAbility * parseTrigger(string s, int id, Spell * spell, MTGCardInstance *card, Targetable * target);
|
||||
int parseRestriction(string s);
|
||||
public:
|
||||
Counter * parseCounter(string s, MTGCardInstance * target);
|
||||
int parsePowerToughness(string s, int *power, int *toughness);
|
||||
int getAbilities(vector<MTGAbility *> * v, Spell * spell, MTGCardInstance * card = NULL, int id = 0,MTGGameZone * dest = NULL);
|
||||
MTGAbility * parseMagicLine(string s, int id, Spell * spell, MTGCardInstance *card, int activated = 0, int forceUEOT = 0,MTGGameZone * dest = NULL);
|
||||
|
||||
@@ -6,10 +6,15 @@
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -18,6 +23,7 @@ int CardDescriptor::init(){
|
||||
attacker = 0;
|
||||
defenser = NULL;
|
||||
banding = NULL;
|
||||
anyCounter = 0;
|
||||
//Remove unnecessary pointers
|
||||
SAFE_DELETE(counters);
|
||||
SAFE_DELETE(previous);
|
||||
@@ -134,7 +140,7 @@ MTGCardInstance * CardDescriptor::match(MTGCardInstance * card){
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Abilities
|
||||
for(map<int,int>::const_iterator it = basicAbilities.begin(); it != basicAbilities.end(); ++it){
|
||||
@@ -175,6 +181,27 @@ MTGCardInstance * CardDescriptor::match(MTGCardInstance * card){
|
||||
}
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,34 @@ int AbilityFactory::countCards(TargetChooser * tc, Player * player, int option){
|
||||
return result;
|
||||
}
|
||||
|
||||
Counter * AbilityFactory::parseCounter(string s, MTGCardInstance * target) {
|
||||
int nb = 1;
|
||||
string name = "";
|
||||
size_t start = s.find("(") + 1;
|
||||
size_t end = s.find(")", start);
|
||||
size_t separator = s.find(",", start);
|
||||
if (separator == string::npos) separator = s.find(".", start);
|
||||
if (separator != string::npos){
|
||||
size_t separator2 = s.find(",", separator+1);
|
||||
if (separator2 == string::npos) separator2 = s.find(".", separator+1);
|
||||
if (separator2 != string::npos) {
|
||||
name = s.substr(separator2+1,end-separator2-1);
|
||||
}
|
||||
string nbstr = s.substr(separator+1,separator2-separator-1);
|
||||
nb = atoi(nbstr.c_str());
|
||||
end = separator;
|
||||
}
|
||||
|
||||
string spt = s.substr(start,end-start);
|
||||
int power, toughness;
|
||||
if ( parsePowerToughness(spt,&power, &toughness)){
|
||||
Counter * counter = NEW Counter(target,name.c_str(),power,toughness);
|
||||
counter->nb = nb;
|
||||
return counter;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int AbilityFactory::parsePowerToughness(string s, int *power, int *toughness){
|
||||
size_t found = s.find("/");
|
||||
if (found != string::npos){
|
||||
@@ -700,25 +728,12 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
|
||||
//counter
|
||||
found = s.find("counter(");
|
||||
if (found != string::npos){
|
||||
found+=8;
|
||||
int nb = 1;
|
||||
string name = "";
|
||||
size_t end = s.find(")", found);
|
||||
size_t separator = s.find(",", found);
|
||||
if (separator != string::npos){
|
||||
size_t separator2 = s.find(",", separator+1);
|
||||
if (separator2 != string::npos) {
|
||||
name = s.substr(separator2+1,end-separator2-1);
|
||||
}
|
||||
string nbstr = s.substr(separator+1,separator2-separator-1);
|
||||
nb = atoi(nbstr.c_str());
|
||||
end = separator;
|
||||
}
|
||||
|
||||
string spt = s.substr(found,end-found);
|
||||
int power, toughness;
|
||||
if ( parsePowerToughness(spt,&power, &toughness)){
|
||||
MTGAbility * a = NEW AACounter(id,card,target,name.c_str(),power,toughness,nb);
|
||||
size_t start = s.find("(");
|
||||
size_t end = s.find(")");
|
||||
string counterString = s.substr(start,end-start+1);
|
||||
Counter * counter = parseCounter(counterString,target);
|
||||
if (counter){
|
||||
MTGAbility * a = NEW AACounter(id,card,target,counter->name.c_str(),counter->power,counter->toughness,counter->nb);
|
||||
a->oneShot = 1;
|
||||
return a;
|
||||
}
|
||||
|
||||
@@ -69,29 +69,14 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan
|
||||
//Counters
|
||||
OutputDebugString("Counter\n");
|
||||
size_t counter_start = value.find("(");
|
||||
int nb = 1;
|
||||
string name = "";
|
||||
size_t counter_end = value.find(")", counter_start);
|
||||
size_t end = value.find(")", counter_start);
|
||||
size_t separator = value.find(",", counter_start);
|
||||
AbilityFactory * abf = NEW AbilityFactory();
|
||||
string counterString = value.substr(counter_start,counter_end-counter_start);
|
||||
Counter * counter = abf->parseCounter(counterString,c);
|
||||
size_t separator = value.find(",",counter_start);
|
||||
size_t separator2 = string::npos;
|
||||
if (separator != string::npos){
|
||||
separator2 = value.find(",", separator+1);
|
||||
if (separator2 != string::npos) {
|
||||
name = value.substr(separator2+1,counter_end-separator2-1);
|
||||
}
|
||||
string nbstr = value.substr(separator+1,separator2-separator-1);
|
||||
nb = atoi(nbstr.c_str());
|
||||
counter_end = separator;
|
||||
}
|
||||
|
||||
string spt = value.substr(counter_start+1,counter_end-counter_start-1);
|
||||
int power, toughness;
|
||||
Counter * counter = NULL;
|
||||
AbilityFactory abf;
|
||||
if ( abf.parsePowerToughness(spt,&power, &toughness)){
|
||||
counter = NEW Counter(c,name.c_str(),power,toughness);
|
||||
counter->nb = nb;
|
||||
if (separator != string::npos) {
|
||||
separator2 = value.find(",",separator + 1);
|
||||
}
|
||||
TargetChooserFactory tcf;
|
||||
TargetChooser * tc = NULL;
|
||||
@@ -99,7 +84,7 @@ ManaCost * ManaCost::parseManaCost(string s, ManaCost * _manaCost, MTGCardInstan
|
||||
if (separator2 != string::npos) {
|
||||
target_start = value.find(",",separator2+1);
|
||||
}
|
||||
size_t target_end = end;
|
||||
size_t target_end = counter_end;
|
||||
if (target_start!=string::npos && target_end!=string::npos){
|
||||
string target = value.substr(target_start+1, target_end-1 - target_start);
|
||||
tc = tcf.createTargetChooser(target,c);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "../include/MTGGameZones.h"
|
||||
#include "../include/GameObserver.h"
|
||||
#include "../include/Subtypes.h"
|
||||
#include "../include/Counters.h"
|
||||
|
||||
|
||||
|
||||
@@ -196,6 +197,30 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
|
||||
}else if (attribute.find("manacost") != string::npos){
|
||||
cd->convertedManacost = comparisonCriterion;
|
||||
cd->manacostComparisonMode = comparisonMode;
|
||||
//Counter Restrictions
|
||||
}else if (attribute.find("counter") != string::npos) {
|
||||
if (attribute.find("{any}") != string::npos) {
|
||||
cd->anyCounter = 1;
|
||||
}else{
|
||||
size_t start = attribute.find("{");
|
||||
size_t end = attribute.find("}");
|
||||
string counterString = attribute.substr(start,end-start+1);
|
||||
counterString.replace(0,1,"(");
|
||||
counterString.replace(counterString.length() - 1,1,")");
|
||||
AbilityFactory * abf = NEW AbilityFactory();
|
||||
Counter * counter = abf->parseCounter(counterString,card);
|
||||
if (counter) {
|
||||
cd->counterName = counter->name;
|
||||
cd->counterNB = counter->nb;
|
||||
cd->counterPower = counter->power;
|
||||
cd->counterToughness = counter->toughness;
|
||||
}
|
||||
if (minus) {
|
||||
cd->counterComparisonMode = COMPARISON_LESS;
|
||||
}else{
|
||||
cd->counterComparisonMode = COMPARISON_AT_MOST;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
int attributefound = 0;
|
||||
//Colors
|
||||
|
||||
Reference in New Issue
Block a user