Added MH2 set, improved Android downloader, added/fixed primitives, improved coin flip event trigger, improved discarded attribute, improved castcard keyword (now it's possible to specify the x value in cost), improved add/remove/mod counter trigger, improved the "spent" and "converge" keyword for spell still in the stack.

This commit is contained in:
Vittorio Alfieri
2021-06-16 17:07:44 +02:00
parent 55edfc6374
commit 9df5bb29ab
19 changed files with 5222 additions and 347 deletions

View File

@@ -2334,7 +2334,9 @@ public class ImgDownloader {
tokenurl = "https://c1.scryfall.com/file/scryfall-cards/large/front/3/d/3d0b9b88-705e-4df0-8a93-3e240b81355b.jpg?1617626092";
else if(id.equals("513663t"))
tokenurl = "https://c1.scryfall.com/file/scryfall-cards/large/front/1/a/1a2d027f-8996-4761-a776-47cd428f6779.jpg?1618766925";
else if(id.equals("522245t"))
tokenurl = "https://c1.scryfall.com/file/scryfall-cards/large/front/3/7/37e32ba6-108a-421f-9dad-3d03f7ebe239.jpg?1623113548";
return tokenurl;
}
@@ -2355,7 +2357,7 @@ public class ImgDownloader {
id.equals("293198") || id.equals("479634") || id.equals("479702") || id.equals("489837") || id.equals("489861") || id.equals("491359") ||
id.equals("294872") || id.equals("295110") || id.equals("294842") || id.equals("295067") || id.equals("491767") || id.equals("295386") ||
id.equals("295229") || id.equals("295387") || id.equals("295206") || id.equals("295706") || id.equals("497549") || id.equals("497666") ||
id.equals("503860"))
id.equals("503860") || id.equals("522280") || id.equals("522111"))
return false;
return true;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
#Primitives Pack for Wagic the Homebrew.
#Please keep these card alphabetized, and try to have the "name=" line at the top of each card
#I sorted this programatically so the other comments are removed except for AUTO_DEFINE - Vitty85 25-04-2021
#I sorted this programatically so the other comments are removed except for AUTO_DEFINE - Vitty85 16-06-2021
[card]
name=Abandon Reason
target=<upto:2>creature
@@ -40161,7 +40161,7 @@ subtype=Aura
[/card]
[card]
name=Field of Souls
auto=@movedTo(creature[-token]|mygraveyard) from(battlefield):token(Spirit,Creature Spirit, 1/1,flying white)
auto=@movedTo(creature[-token]|mygraveyard) from(battlefield):token(Spirit,Creature Spirit,1/1,flying,white)
text=Whenever a nontoken creature is put into your graveyard from the battlefield, put a 1/1 white Spirit creature token with flying onto the battlefield.
mana={2}{W}{W}
type=Enchantment
@@ -65219,7 +65219,7 @@ toughness=4
[/card]
[card]
name=Lair Delve
aicode=activate target(<2>*[zpos<=2]|mylibrary) name(revealed card) moveto(myhand) name(revealed card) and!(if cantargetcard(*[-creature;-land]|*) then bottomoflibrary))!
aicode=activate target(<2>*[zpos<=2]|mylibrary) name(revealed card) moveto(myhand) name(revealed card) and!(if cantargetcard(*[-creature;-land]|*) then bottomoflibrary)!
auto=reveal:2 optionone name(Get creature and land) target(<2>*[creature,land]|reveal) moveto(myhand) optiononeend optiontwo name(put on bottom) all(*|reveal) bottomoflibrary optiontwoend revealend
text=Reveal the top two cards of your library. Put all creature and land cards revealed this way into your hand and the rest on the bottom of your library in any order.
mana={2}{G}
@@ -117784,7 +117784,7 @@ toughness=7
[/card]
[card]
name=Tarmogoyf
anyzone=gravecardtypes/gravecardtypesplus1plusend cdaactive
anyzone=allgravecardtypes/allgravecardtypesplus1plusend cdaactive
text=Tarmogoyf's power is equal to the number of card types among cards in all graveyards and its toughness is equal to that number plus 1. (The card types are artifact, creature, enchantment, instant, land, planeswalker, sorcery, and tribal.)
mana={1}{G}
type=Creature

View File

@@ -1,7 +1,7 @@
grade=borderline
#Planeswalkers Primitives Pack for Wagic the Homebrew.
#Please keep these card alphabetized, and try to have the "name=" line at the top of each card
#We sorted this in alphabetical order - Luruz & Vitty85 25-04-2021
#We sorted this in alphabetical order - Luruz & Vitty85 16-06-2021
[card]
name=Abian, Luvion Usurper
auto=counter(0/0,5,loyalty)
@@ -601,6 +601,18 @@ type=Legendary Planeswalker
subtype=Dack
[/card]
[card]
name=Dakkon, Shadow Slayer
auto=counter(0/0,type:land:myBattlefield,loyalty)
aicode=activate transforms((,newability[surveil],newability[all(*[zpos<=psurveiloffsetplus1plusend]|mylibrary) transforms((,newability[if compare(genrand2)~equalto~1 then moveto(mygraveyard)])) oneshot])) oneshot
auto={C(0/0,1,Loyalty)}:name(+1: Surveil 1) reveal:psurveiloffsetplus1plusend optionone name(put in graveyard) target(<upto:psurveiloffsetplus1plusend>*|reveal) moveto(ownergraveyard) optiononeend optiontwo name(put in library) target(<psurveiloffsetplus1plusend>*|reveal) moveto(ownerlibrary) optiontwoend afterrevealed surveil afterrevealedend revealend
auto={C(0/0,-3,Loyalty)}:name(-3: Exile creature) target(creature|battlefield) moveto(exile)
auto={C(0/0,-6,Loyalty)}:name(-6: Put artifact in play) target(artifact|myHand,myGraveyard) moveto(myBattlefield)
text=Dakkon, Shadow Slayer enters the battlefield with a number of loyalty counters on him equal to the number of lands you control. -- +1: Surveil 2. -- -3: Exile target creature. -- -6: You may put an artifact card from your hand or graveyard onto the battlefield.
mana={W}{U}{B}
type=Legendary Planeswalker
subtype=Dakkon
[/card]
[card]
name=Daretti, Ingenious Iconoclast
auto=counter(0/0,3,loyalty)
auto={C(0/0,1,Loyalty)}:name(+1: Create a 1/1 colorless Construct) token(Construct,Artifact Creature Construct,1/1,defender)
@@ -909,6 +921,19 @@ type=Legendary Planeswalker
subtype=Garruk
[/card]
[card]
name=Geyadrone Dihada
auto=counter(0/0,4,loyalty)
auto=protection from(*[-instant;-sorcery;counter{0/0.1.corruption}])
auto={C(0/0,1,Loyalty)}:name(+1: Gain 2 life) life:2 controller && life:-2 opponent
auto={C(0/0,1,Loyalty)}:name(+1: Gain 2 life and put counter) target(*[creature;planeswalker]|battlefield) counter(0/0,1,corruption) && life:2 controller && life:-2 opponent
auto={C(0/0,-3,Loyalty)}:name(-3: Gain control of creature or planeswalker) target(*[creature;planeswalker]|battlefield) moveto(mybattlefield) and!(transforms((,newability[phaseaction[endofturn once sourceinplay] moveTo(previousbattlefield)],newability[counter(0/0.1.corruption)],newability[untap],haste)) ueot)!
auto={C(0/0,-7,Loyalty)}:name(-7: Gain control of all corrupted) all(*[counter{0/0.1.corruption}]|battlefield) moveto(mybattlefield)
text=Protection from permanents with corruption counters on them -- +1: Each opponent loses 2 life and you gain 2 life. Put a corruption counter on up to one other target creature or planeswalker. -- 3: Gain control of target creature or planeswalker until end of turn. Untap it and put a corruption counter on it. It gains haste until end of turn. -- 7: Gain control of each permanent with a corruption counter on it.
mana={1}{U}{B}{R}
type=Legendary Planeswalker
subtype=Dihada
[/card]
[card]
name=Gideon, Ally of Zendikar
auto=counter(0/0,4,loyalty)
auto={C(0/0,1,Loyalty)}:name(+1: Transforms Gideon 5/5 indestructible) transforms((Human Soldier Ally Creature Planeswalker,setpower=5,settoughness=5,indestructible)) ueot && transforms((,newability[preventAllDamage to(this)])) ueot
@@ -999,10 +1024,27 @@ subtype=Gideon
color=white
[/card]
[card]
name=Grist, the Hunger Tide
auto=counter(0/0,3,loyalty)
auto=transforms((removealltypes,newability[becomes(Legendary Planeswalker Grist)])) forever
auto=@counteradded(0/0,1,GristEffect) from(insect|mygraveyard):name(Repeat process) name(Repeat process) all(this) counter(0/0,1,loyalty) && all(insect[counter{0/0.1.GristEffect}]|mygraveyard) removeallcounters(0/0,1,GristEffect) && token(Insect,Creature Insect,1/1,black,green) and!( transforms((,newability[all(*[zpos=1]|mylibrary) moveto(mygraveyard) and!( if cantargetcard(*[insect]|*) then counter(0/0.1.GristEffect) )!])) oneshot )!
auto={C(0/0,1,Loyalty)}:name(+1: Create 1/1 insect) token(Insect,Creature Insect,1/1,black,green) and!( transforms((,newability[all(*[zpos=1]|mylibrary) moveto(mygraveyard) and!( if cantargetcard(*[insect]|*) then counter(0/0.1.GristEffect) )!])) oneshot )!
auto={C(0/0,-2,Loyalty)}:name(-2: Sacrifice and destroy) target(creature|mybattlefield) sacrifice and!( transforms((,newability[name(Destroy creature or planeswalker) target(*[creature;planeswalker]|battlefield) destroy])) oneshot )!
auto={C(0/0,-2,Loyalty)}:name(-2: Don't sacrifice any creature) donothing
auto={C(0/0,-5,Loyalty)}:name(-5: Opponent lose life) life:-type:creature:mygraveyard opponent
text=As long as Grist, the Hunger Tide isn't on the battlefield, it's a 1/1 Insect creature in addition to its other types. -- +1: Create a 1/1 black and green Insect creature token, then mill a card. If an Insect card was milled this way, put a loyalty counter on Grist and repeat this process. -- 2: You may sacrifice a creature. When you do, destroy target creature or planeswalker. -- 5: Each opponent loses life equal to the number of creature cards in your graveyard.
mana={1}{B}{G}
type=Legendary Planeswalker Creature
subtype=Grist Insect
power=1
toughness=1
[/card]
[card]
name=Huatli, Dinosaur Knight
auto=counter(0/0,4,loyalty)
auto={C(0/0,2,Loyalty)}:name(+2: Put two +1/+1 counters on a Dinosaur) target(<upto:1>dinosaur|mybattlefield) counter(1/1,2)
auto={C(0/0,-3,Loyalty)}:name(-3: Dinosaur deals damage) target(dinosaur|mybattlefield) transforms((,newability[dynamicability<!powerstrike!> target(creature|opponentbattlefield)
auto={C(0/0,2,Loyalty)}:name(+2: Don't put counters) donothing
auto={C(0/0,2,Loyalty)}:name(+2: Put two +1/+1 counters on a Dinosaur) target(dinosaur|mybattlefield) counter(1/1,2)
auto={C(0/0,-3,Loyalty)}:name(-3: Dinosaur deals damage) target(dinosaur|mybattlefield) transforms((,newability[dynamicability<!powerstrike!> target(creature|opponentbattlefield)])) oneshot
auto={C(0/0,-7,Loyalty)}:name(-7: Dinosaurs gets +4/+4) all(dinosaur|mybattlefield) 4/4 ueot
text=+2: Put two +1/+1 counters on up to one target Dinosaur you control. -- -3: Target Dinosaur you control deals damage equal to its power to target creature you don't control. -- -7: Dinosaurs you control get +4/+4 until end of turn.
mana={4}{R}{W}

View File

@@ -2,7 +2,7 @@ grade=unsupported
#The cards in this file are not implemented/incomplete yet.
#Updated Card lists not in primitives (Borderline, Crappy, Unsupported and Missing Cards up to Aether Revolt) as of 3/14/2017
#Please keep these card alphabetized, and try to have the "name=" line at the top of each card
#I sorted this programatically - Vitty85 25-04-2021
#I sorted this programatically - Vitty85 16-06-2021
[card]
name="Ach! Hans, Run!"
text=At the beginning of your upkeep, you may say "Ach Hans, run It's the . . ." and name a creature card. If you do, search your library for the named card, put it into play, then shuffle your library. That creature has haste. Remove it from the game at end of turn.
@@ -1795,6 +1795,12 @@ mana={2}{U}
type=Enchantment
[/card]
[card]
name=Chef's Kiss
text=Gain control of target spell that targets only a single permanent or player. Copy it, then reselect the targets at random for the spell and the copy. The new targets can't be you or a permanent you control.
mana={1}{R}{R}
type=Instant
[/card]
[card]
name=Chipper Chopper
text=Flying -- When Chipper Chopper enters the battlefield, you may sacrifice another artifact. If you do, put two +1/+1 counters on Chipper Chopper and it assembles a Contraption. (Put the top card of your Contraption deck face up onto one of your sprockets.)
mana={3}{U}
@@ -5202,12 +5208,6 @@ text=Hidden agenda (Start the game with this conspiracy face down in the command
type=Conspiracy
[/card]
[card]
name=Hive Mind
text=Whenever a player casts an instant or sorcery spell, each other player copies that spell. Each of those players may choose new targets for his or her copy.
mana={5}{U}
type=Enchantment
[/card]
[card]
name=Hixus, Prison Warden
abilities=flash
text=Flash (You may cast this spell any time you could cast an instant.) -- Whenever a creature deals combat damage to you, if Hixus, Prison Warden entered the battlefield this turn, exile that creature until Hixus leaves the battlefield. (That creature returns under its owner's control.)
@@ -8596,13 +8596,6 @@ power=3
toughness=4
[/card]
[card]
name=Petrified Plating
text=Enchant creature -- Enchanted creature gets +2/+2. -- Suspend 2—{G} (Rather than cast this card from your hand, you may pay {G} and exile it with two time counters on it. At the beginning of your upkeep, remove a time counter. When the last is removed, cast it without paying its mana cost.)
mana={2}{G}
type=Enchantment
subtype=Aura
[/card]
[card]
name=Phantasmagorian
text=When you cast Phantasmagorian, any player may discard three cards. If a player does, counter Phantasmagorian. -- Discard three cards: Return Phantasmagorian from your graveyard to your hand.
mana={5}{B}{B}
@@ -9958,15 +9951,6 @@ mana={1}{W}
type=Instant
[/card]
[card]
name=Sanctum Prelate
text=As Sanctum Prelate enters the battlefield, choose a number. -- Noncreature spells with converted mana cost equal to the chosen number can't be cast.
mana={1}{W}{W}
type=Creature
subtype=Human Cleric
power=2
toughness=2
[/card]
[card]
name=Sanctum of Serra
text=When you planeswalk away from Sanctum of Serra, destroy all nonland permanents. -- Whenever you roll {C}, you may have your life total become 20.
type=Plane
@@ -13586,6 +13570,15 @@ power=1
toughness=1
[/card]
[card]
name=Yusri, Fortune's Flame
text=Flying -- Whenever Yusri, Fortune's Flame attacks, choose a number between 1 and 5. Flip that many coins. For each flip you win, draw a card. For each flip you lose, Yusri deals 2 damage to you. If you won five flips this way, you may cast spells from your hand this turn without paying their mana costs.
mana={1}{U}{R}
type=Legendary Creature
subtype=Efreet
power=2
toughness=3
[/card]
[card]
name=Zada, Hedron Grinder
text=Whenever you cast an instant or sorcery spell that targets only Zada, Hedron Grinder, copy that spell for each other creature you control that the spell could target. Each copy targets a different one of those creatures.
mana={3}{R}

View File

@@ -780,7 +780,11 @@ public:
if (!e) return 0;
if (limitOnceATurn && triggeredTurn == game->turn)
return 0;
if (flipresult > -1 && flipresult != e->card->lastFlipResult)
if ((flipresult == 0 || flipresult == 1) && flipresult != e->card->lastFlipResult)
return 0;
if (flipresult == 2 && e->card->coinSide != e->card->lastFlipResult)
return 0;
if (flipresult == 3 && e->card->coinSide == e->card->lastFlipResult)
return 0;
if (playerName != "" && playerName != e->playerName)
return 0;
@@ -1079,16 +1083,21 @@ public:
Counter * counter;
int type;
bool duplicate;
bool limitOnceATurn;
int triggeredTurn;
MTGCardInstance * counterException; //added exception to avid a counter loop (eg. Doubling Season)
TrCounter(GameObserver* observer, int id, MTGCardInstance * source, Counter * counter, TargetChooser * tc, int type = 0, bool once = false, bool duplicate = false, MTGCardInstance * counterException = NULL) :
Trigger(observer, id, source, once, tc), counter(counter), type(type), duplicate(duplicate), counterException(counterException)
TrCounter(GameObserver* observer, int id, MTGCardInstance * source, Counter * counter, TargetChooser * tc, int type = 0, bool once = false, bool duplicate = false, bool limitOnceATurn = false, MTGCardInstance * counterException = NULL) :
Trigger(observer, id, source, once, tc), counter(counter), type(type), duplicate(duplicate), limitOnceATurn(limitOnceATurn), counterException(counterException)
{
triggeredTurn = -1;
}
int triggerOnEventImpl(WEvent * event)
{
WEventCounters * e = dynamic_cast<WEventCounters *> (event);
if (!e) return 0;
if (limitOnceATurn && triggeredTurn == game->turn)
return 0;
if (type == 0 && !e->removed) return 0;
if (type == 1 && !e->added) return 0;
if (counterException && e->source && !strcmp(counterException->data->name.c_str(), e->source->data->name.c_str())) return 0; //If the source of counter gain/loss it's the exception card it doesn't have effect (loop avoidance);
@@ -1100,6 +1109,7 @@ public:
else
e->targetCard->counters->removeCounter(e->name.c_str(),e->power,e->toughness,true,true,e->source);
}
triggeredTurn = game->turn;
return 1;
}
@@ -3275,8 +3285,10 @@ public:
andAbilityClone->addToGame();
}
}
WEvent * e = NEW WEventTokenCreated(myToken);
spell->getObserver()->receiveEvent(e); // triggers the @tokencreated event for any other listener.
if(sabilities.find("notrigger") == string::npos){ // check if the @tokencreated trigger has to be activated or not
WEvent * e = NEW WEventTokenCreated(myToken);
spell->getObserver()->receiveEvent(e); // triggers the @tokencreated event for any other listener.
}
delete spell;
}
return 1;
@@ -6346,8 +6358,9 @@ public:
bool asNormalMadness;
bool alternative;
int kicked;
int costx;
bool flipped;
AACastCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target,bool restricted,bool copied,bool _asNormal,string nameCard,string abilityName,bool _noEvent, bool putinplay,bool asNormalMadness = false,bool alternative = false,int kicked = 0,bool flipped = false);
AACastCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target,bool restricted,bool copied,bool _asNormal,string nameCard,string abilityName,bool _noEvent, bool putinplay,bool asNormalMadness = false,bool alternative = false,int kicked = 0,int costx = 0,bool flipped = false);
int testDestroy(){return 0;};
void Update(float dt);

View File

@@ -79,6 +79,7 @@ class CardDescriptor: public MTGCardInstance
int CDcontrollerDamaged;
int CDdamager;
int CDgeared;
int CDdiscarded;
int CDattached;
int CDblocked;
int CDcanProduceC;

View File

@@ -2,6 +2,7 @@ class WParsedInt
{
private:
void init(string s, Spell * spell, MTGCardInstance * card);
void extendedParse(string type, Spell * spell, MTGCardInstance * card);
public:
int intValue;

View File

@@ -488,7 +488,7 @@ int Spell::resolve()
if(observer->getResourceManager())
observer->getResourceManager()->PlaySample(source->getSample());
}
if(this->cost)
if(this->cost && !source->getManaCost()->getManaUsedToCast())
{
source->getManaCost()->setManaUsedToCast(NEW ManaCost(this->cost));
}

View File

@@ -9234,8 +9234,8 @@ AEquip * AEquip::clone() const
}
// casting a card for free, or casting a copy of a card.
AACastCard::AACastCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target,bool _restricted,bool _copied,bool asNormal,string _namedCard,string _name,bool _noEvent,bool putinplay,bool madness, bool alternative, int kicked, bool flipped) :
MTGAbility(observer, _id, _source),restricted(_restricted),asCopy(_copied),normal(asNormal),cardNamed(_namedCard),nameThis(_name),noEvent(_noEvent),putinplay(putinplay), asNormalMadness(madness), alternative(alternative), kicked(kicked), flipped(flipped)
AACastCard::AACastCard(GameObserver* observer, int _id, MTGCardInstance * _source, MTGCardInstance * _target,bool _restricted,bool _copied,bool asNormal,string _namedCard,string _name,bool _noEvent,bool putinplay,bool madness, bool alternative, int kicked, int costx, bool flipped) :
MTGAbility(observer, _id, _source),restricted(_restricted),asCopy(_copied),normal(asNormal),cardNamed(_namedCard),nameThis(_name),noEvent(_noEvent),putinplay(putinplay), asNormalMadness(madness), alternative(alternative), kicked(kicked), costx(costx), flipped(flipped)
{
target = _target;
andAbility = NULL;
@@ -9441,6 +9441,18 @@ int AACastCard::resolveSpell()
Spell * spell = NULL;
MTGCardInstance * copy = source->controller()->game->putInZone(theNamedCard, theNamedCard->currentZone, source->controller()->game->stack);
if(alternative)
copy->alternateCostPaid[ManaCost::MANA_PAID_WITH_ALTERNATIVE] = 1;
if(kicked > 0){
copy->alternateCostPaid[ManaCost::MANA_PAID_WITH_KICKER] = 1;
copy->kicked = kicked;
}
if(costx > 0){
copy->castX = costx;
copy->setX = costx;
copy->X = costx;
}
if (game->targetChooser)
{
game->targetChooser->Owner = source->controller();
@@ -9464,8 +9476,10 @@ int AACastCard::resolveSpell()
}
if (!copy->has(Constants::STORM))
{
copy->X = 0;
copy->castX = copy->X;
if(costx <= 0){
copy->X = 0;
copy->castX = copy->X;
}
}
if(andAbility)
{
@@ -9514,6 +9528,11 @@ int AACastCard::resolveSpell()
copy->alternateCostPaid[ManaCost::MANA_PAID_WITH_KICKER] = 1;
copy->kicked = kicked;
}
if(costx > 0){
copy->castX = costx;
copy->setX = costx;
copy->X = costx;
}
if (game->targetChooser)
{
game->targetChooser->Owner = source->controller();
@@ -9549,8 +9568,10 @@ int AACastCard::resolveSpell()
}
if (!copy->has(Constants::STORM))
{
copy->X = _target->X;
copy->castX = copy->X;
if(costx <= 0){
copy->X = _target->X;
copy->castX = copy->X;
}
}
if(andAbility)
{

View File

@@ -32,6 +32,7 @@ CardDescriptor::CardDescriptor()
CDcontrollerDamaged = 0;
CDdamager = 0;
CDgeared = 0;
CDdiscarded = 0;
CDattached = 0;
CDblocked = 0;
CDcanProduceC = 0;
@@ -291,6 +292,11 @@ MTGCardInstance * CardDescriptor::match(MTGCardInstance * card)
match = NULL;
}
if ((CDdiscarded == -1 && card->discarded) || (CDdiscarded == 1 && !card->discarded))
{
match = NULL;
}
if ((fresh == -1 && card->fresh) || (fresh == 1 && !card->fresh))
{
match = NULL;

View File

@@ -1568,6 +1568,18 @@ bool CardGui::FilterCard(MTGCard * _card,string filter)
cd.hasXCost = 1;
}
}
//has been discarded
else if (attribute.find("discarded") != string::npos)
{
if (minus)
{
cd.CDdiscarded = -1;
}
else
{
cd.CDdiscarded = 1;
}
}
//put in its zone this turn
else if (attribute.find("fresh") != string::npos)
{

View File

@@ -1035,6 +1035,7 @@ void GameObserver::gameStateBasedEffects()
{
MTGCardInstance * card = fg->cards[k];
card->fresh = 0; // Remove fresh attribute to cards put in graveyard last turn
card->discarded = false; // Remove discarded attribute to cards put in graveyard last turn
}
MTGGameZone * fe = p->game->exile;
for (int k = 0; k < fe->nb_cards; k++)

View File

@@ -1270,6 +1270,10 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
flipresult = 0;
} else if(res.size() && (res[1] == "tails" || res[1] == "tail")){
flipresult = 1;
} else if(res.size() && res[1] == "won"){
flipresult = 2;
} else if(res.size() && res[1] == "lost"){
flipresult = 3;
}
string playerName = "";
vector<string>from = parseBetween(s, "from(",")");
@@ -1452,9 +1456,9 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
TargetChooser * tc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a counter add/remove exception in order to avoid counter loop (eg. Doubling Season)
if(exception)
return NEW TrCounter(observer, id, card, counter, tc, 1, once, duplicate, exception->source);
return NEW TrCounter(observer, id, card, counter, tc, 1, once, duplicate, limitOnceATurn, exception->source);
else
return NEW TrCounter(observer, id, card, counter, tc, 1, once, duplicate);
return NEW TrCounter(observer, id, card, counter, tc, 1, once, duplicate, limitOnceATurn);
}
if (s.find("counterremoved(") != string::npos)
@@ -1469,9 +1473,23 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
TargetChooser * tc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a counter add/remove exception in order to avoid counter loop (eg. Doubling Season)
if(exception)
return NEW TrCounter(observer, id, card, counter, tc, 0, once, duplicate, exception->source);
return NEW TrCounter(observer, id, card, counter, tc, 0, once, duplicate, limitOnceATurn, exception->source);
else
return NEW TrCounter(observer, id, card, counter, tc, 0, once, duplicate);
return NEW TrCounter(observer, id, card, counter, tc, 0, once, duplicate, limitOnceATurn);
}
if (s.find("countermod(") != string::npos)
{
vector<string>splitCounter = parseBetween(s,"countermod(",")");
Counter * counter = NULL;
if(s.find("(any)") == string::npos)
counter = parseCounter(splitCounter[1],card,NULL);
TargetChooser * tc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a counter add/remove exception in order to avoid counter loop (eg. Doubling Season)
if(exception)
return NEW TrCounter(observer, id, card, counter, tc, 2, once, false, limitOnceATurn, exception->source);
else
return NEW TrCounter(observer, id, card, counter, tc, 2, once, false, limitOnceATurn);
}
int who = 0;
@@ -3353,8 +3371,8 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return a;
}
//cast a card without paying it's manacost
vector<string> splitCastCard = parseBetween(s, "castcard(", ")");
//cast a card without paying it's manacost
vector<string> splitCastCard = parseBetween(s, "castcard(", ")");
if (splitCastCard.size())
{
string builtHow = splitCastCard[1];
@@ -3381,10 +3399,21 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
vector<string> splitCastKicked = parseBetween(splitCastCard[1], "kicked!:", ":!");
if(splitCastKicked.size())
{
kicked = atoi(splitCastKicked[1].c_str());
WParsedInt * val = NEW WParsedInt(splitCastKicked[1], NULL, card);
kicked = val->getValue();
}
}
MTGAbility *a = NEW AACastCard(observer, id, card, target,withRestrictions,asCopy,asNormal,nameCard,newName,sendNoEvent,putinplay, asNormalMadness, alternative, kicked, flipped);
int costx = 0;
if(splitCastCard[1].find("costx!:") != string::npos)
{
vector<string> splitCastCostX = parseBetween(splitCastCard[1], "costx!:", ":!");
if(splitCastCostX.size())
{
WParsedInt * val = NEW WParsedInt(splitCastCostX[1], NULL, card);
costx = val->getValue();
}
}
MTGAbility *a = NEW AACastCard(observer, id, card, target,withRestrictions,asCopy,asNormal,nameCard,newName,sendNoEvent,putinplay, asNormalMadness, alternative, kicked, costx, flipped);
a->oneShot = false;
if(splitCastCard[1].find("trigger[to]") != string::npos)
{
@@ -4360,37 +4389,6 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
}
}
//Change Power/Toughness
WParsedPT * wppt = NEW WParsedPT(s, spell, card);
bool nonstatic = false;
if (wppt->ok)
{
if(s.find("nonstatic") != string::npos)
nonstatic = true;
if (!activated)
{
if (card->hasType(Subtypes::TYPE_INSTANT) || card->hasType(Subtypes::TYPE_SORCERY) || forceUEOT)
{
return NEW PTInstant(observer, id, card, target, wppt,s,nonstatic);
}
else if(s.find("cdaactive") != string::npos)
{
MTGAbility * a = NEW APowerToughnessModifier(observer, id, card, target, wppt,s,true);
a->forcedAlive = 1;
//a->forceDestroy = -1;
return a;
//return NEW APowerToughnessModifier(observer, id, card, target, wppt,s,true);
}
else
return NEW APowerToughnessModifier(observer, id, card, target, wppt,s,nonstatic);
}
return NEW PTInstant(observer, id, card, target, wppt,s,nonstatic);
}
else
{
delete wppt;
}
//Mana Producer
found = s.find("add");
if (found != string::npos)
@@ -4505,7 +4503,36 @@ MTGAbility * AbilityFactory::parseMagicLine(string s, int id, Spell * spell, MTG
return NULL;
}
//Change Power/Toughness
WParsedPT * wppt = NEW WParsedPT(s, spell, card);
bool nonstatic = false;
if (wppt->ok)
{
if(s.find("nonstatic") != string::npos)
nonstatic = true;
if (!activated)
{
if (card->hasType(Subtypes::TYPE_INSTANT) || card->hasType(Subtypes::TYPE_SORCERY) || forceUEOT)
{
return NEW PTInstant(observer, id, card, target, wppt,s,nonstatic);
}
else if(s.find("cdaactive") != string::npos)
{
MTGAbility * a = NEW APowerToughnessModifier(observer, id, card, target, wppt,s,true);
a->forcedAlive = 1;
//a->forceDestroy = -1;
return a;
//return NEW APowerToughnessModifier(observer, id, card, target, wppt,s,true);
}
else
return NEW APowerToughnessModifier(observer, id, card, target, wppt,s,nonstatic);
}
return NEW PTInstant(observer, id, card, target, wppt,s,nonstatic);
}
else
{
delete wppt;
}
//affinity based on targetchooser
vector<string> splitNewAffinity = parseBetween(s, "affinity(", ")");

View File

@@ -525,6 +525,12 @@ MTGCardInstance * MTGPlayerCards::putInZone(MTGCardInstance * card, MTGGameZone
if (!(copy = from->removeCard(card, doCopy)))
return NULL; //ERROR
// Set the mana value used to cast this spell
if((to == g->players[0]->game->stack || to == g->players[1]->game->stack) && card->getManaCost() && card->getManaCost()->getManaUsedToCast()){
copy->getManaCost()->setManaUsedToCast(NEW ManaCost());
copy->getManaCost()->getManaUsedToCast()->copy(card->getManaCost()->getManaUsedToCast());
}
if(!card->hasType(Subtypes::TYPE_LEGENDARY) && copy->hasType(Subtypes::TYPE_LEGENDARY)) // This fix issue when cloning a card with nolegend option (e.g. Double Major)
copy->removeType(Subtypes::TYPE_LEGENDARY);

View File

@@ -571,6 +571,10 @@ int MTGPutInPlayRule::reactToClick(MTGCardInstance * card)
else
{
Spell * spell = NULL;
if (spellCost && !card->getManaCost()->getManaUsedToCast()){
card->getManaCost()->setManaUsedToCast(NEW ManaCost());
card->getManaCost()->getManaUsedToCast()->copy(spellCost);
}
MTGCardInstance * copy = player->game->putInZone(card, card->currentZone, player->game->stack);
if (game->targetChooser)
{
@@ -744,6 +748,10 @@ int MTGKickerRule::reactToClick(MTGCardInstance * card)
else
{
Spell * spell = NULL;
if (spellCost && !card->getManaCost()->getManaUsedToCast()){
card->getManaCost()->setManaUsedToCast(NEW ManaCost());
card->getManaCost()->getManaUsedToCast()->copy(spellCost);
}
MTGCardInstance * copy = player->game->putInZone(card, card->currentZone, player->game->stack);
if (game->targetChooser)
{
@@ -1040,7 +1048,11 @@ int MTGAlternativeCostRule::reactToClick(MTGCardInstance * card, ManaCost *alter
SAFE_DELETE(spell);
}
else
{
{
if (spellCost && !card->getManaCost()->getManaUsedToCast()){
card->getManaCost()->setManaUsedToCast(NEW ManaCost());
card->getManaCost()->getManaUsedToCast()->copy(spellCost);
}
MTGCardInstance * copy = player->game->putInZone(card, card->currentZone, player->game->stack);
game->mLayers->stackLayer()->addSpell(copy, game->targetChooser, spellCost, alternateCostType, 0);
game->targetChooser = NULL;
@@ -1531,6 +1543,10 @@ int MTGMorphCostRule::reactToClick(MTGCardInstance * card)
delete previousManaPool;
card->morphed = true;
card->isMorphed = true;
if (spellCost && !card->getManaCost()->getManaUsedToCast()){
card->getManaCost()->setManaUsedToCast(NEW ManaCost());
card->getManaCost()->getManaUsedToCast()->copy(spellCost);
}
MTGCardInstance * copy = player->game->putInZone(card, card->currentZone, player->game->stack);
copy->getManaCost()->resetCosts();//Morph has no ManaCost on stack
copy->setColor(0,1);

View File

@@ -614,6 +614,18 @@ TargetChooser * TargetChooserFactory::createTargetChooser(string s, MTGCardInsta
cd->hasXCost = 1;
}
}
//has been discarded
else if (attribute.find("discarded") != string::npos)
{
if (minus)
{
cd->CDdiscarded = -1;
}
else
{
cd->CDdiscarded = 1;
}
}
//put in its zone this turn
else if (attribute.find("fresh") != string::npos)
{

View File

@@ -374,8 +374,8 @@ void WParsedInt::init(string s, Spell * spell, MTGCardInstance * card)
for (int i = 0; i < 2; i++)
{
Player * p = card->getObserver()->players[i];
MTGGameZone * zones[] = { p->game->battlefield, p->game->graveyard, p->game->hand, p->game->library, p->game->exile };
for (int k = 0; k < 5; k++)
MTGGameZone * zones[] = { p->game->battlefield, p->game->graveyard, p->game->hand, p->game->library, p->game->exile, p->game->reveal };
for (int k = 0; k < 6; k++)
{
MTGGameZone * zone = zones[k];
if(tc->targetsZone(zone,target))
@@ -877,32 +877,6 @@ void WParsedInt::init(string s, Spell * spell, MTGCardInstance * card)
intValue += card->controller()->game->graveyard->cards[j]->myconvertedcost;
}
}
else if (s == "gravecardtypes")//Tarmogoyf
{
intValue = 0;
int pc = 0, tc = 0, sc = 0, lc = 0, ic = 0, ec = 0, cc = 0, ac = 0;
for (int j = 0; j < 2; j++)
{
MTGGameZone * checkZone = card->getObserver()->players[j]->game->graveyard;
if(cardHasTypeinZone("planeswalker",checkZone))
pc = 1;
if(cardHasTypeinZone("tribal",checkZone))
tc = 1;
if(cardHasTypeinZone("sorcery",checkZone))
sc = 1;
if(cardHasTypeinZone("land",checkZone))
lc = 1;
if(cardHasTypeinZone("instant",checkZone))
ic = 1;
if(cardHasTypeinZone("enchantment",checkZone))
ec = 1;
if(cardHasTypeinZone("creature",checkZone))
cc = 1;
if(cardHasTypeinZone("artifact",checkZone))
ac = 1;
}
intValue = pc+tc+sc+lc+ic+ec+cc+ac;
}
else if (s == "powertotalinplay")//Count Total Power of Creatures you control... Formidable
{
intValue = 0;
@@ -1035,10 +1009,6 @@ void WParsedInt::init(string s, Spell * spell, MTGCardInstance * card)
else
intValue = card->revealedLast->getManaCost()->getConvertedCost();
}
else if (s == "scryedcards")//returns how many card have been scryed from current card
{
intValue = card->scryedCards;
}
else if (s.find("findfirsttype") != string::npos)//find the index of first card with specified type in target player library
{
intValue = 0;
@@ -1068,9 +1038,33 @@ void WParsedInt::init(string s, Spell * spell, MTGCardInstance * card)
}
}
}
else if(!intValue)//found nothing, try parsing a atoi
else if (s == "scryedcards" || s == "numoftypes")//returns how many card have been scryed from current card -- returns the number of types of the card
{
intValue = atoi(s.c_str());
if(s == "scryedcards")
intValue = card->scryedCards;
else {
intValue = 0;
if(card->hasType(Subtypes::TYPE_PLANESWALKER))
intValue++;
if(card->hasType(Subtypes::TYPE_TRIBAL))
intValue++;
if(card->hasType(Subtypes::TYPE_SORCERY))
intValue++;
if(card->hasType(Subtypes::TYPE_LAND))
intValue++;
if(card->hasType(Subtypes::TYPE_INSTANT))
intValue++;
if(card->hasType(Subtypes::TYPE_ENCHANTMENT))
intValue++;
if(card->hasType(Subtypes::TYPE_CREATURE))
intValue++;
if(card->hasType(Subtypes::TYPE_ARTIFACT))
intValue++;
}
}
else //Continue parsing in another method to avoid compiler C1061 error.
{
extendedParse(s, spell, card);
}
if (intValue > 0)//dont divide by 0 the rest are valid.
{
@@ -1111,6 +1105,129 @@ void WParsedInt::init(string s, Spell * spell, MTGCardInstance * card)
intValue *= multiplier;
}
void WParsedInt::extendedParse(string s, Spell * spell, MTGCardInstance * card)
{
if (s == "mybattlefieldcardtypes" || s == "oppbattlefieldcardtypes" || s == "allbattlefieldcardtypes")//Count number of card types on battlefield
{
intValue = 0;
int pc = 0, tc = 0, sc = 0, lc = 0, ic = 0, ec = 0, cc = 0, ac = 0;
if(s == "allbattlefieldcardtypes") {
for (int j = 0; j < 2; j++) {
MTGGameZone * checkZone = card->getObserver()->players[j]->game->inPlay;
if(cardHasTypeinZone("planeswalker",checkZone))
pc = 1;
if(cardHasTypeinZone("tribal",checkZone))
tc = 1;
if(cardHasTypeinZone("sorcery",checkZone))
sc = 1;
if(cardHasTypeinZone("land",checkZone))
lc = 1;
if(cardHasTypeinZone("instant",checkZone))
ic = 1;
if(cardHasTypeinZone("enchantment",checkZone))
ec = 1;
if(cardHasTypeinZone("creature",checkZone))
cc = 1;
if(cardHasTypeinZone("artifact",checkZone))
ac = 1;
}
} else {
MTGGameZone * checkZone = (s.find("oppbattlefieldcardtypes")!=string::npos)?card->getObserver()->opponent()->game->inPlay:card->controller()->game->inPlay;
if(cardHasTypeinZone("planeswalker",checkZone))
pc = 1;
if(cardHasTypeinZone("tribal",checkZone))
tc = 1;
if(cardHasTypeinZone("sorcery",checkZone))
sc = 1;
if(cardHasTypeinZone("land",checkZone))
lc = 1;
if(cardHasTypeinZone("instant",checkZone))
ic = 1;
if(cardHasTypeinZone("enchantment",checkZone))
ec = 1;
if(cardHasTypeinZone("creature",checkZone))
cc = 1;
if(cardHasTypeinZone("artifact",checkZone))
ac = 1;
}
intValue = pc+tc+sc+lc+ic+ec+cc+ac;
}
else if (s == "mygravecardtypes" || s == "oppgravecardtypes" || s == "allgravecardtypes")//Count number of card types in graveyards
{
intValue = 0;
int pc = 0, tc = 0, sc = 0, lc = 0, ic = 0, ec = 0, cc = 0, ac = 0;
if(s == "allgravecardtypes") {
for (int j = 0; j < 2; j++) {
MTGGameZone * checkZone = card->getObserver()->players[j]->game->graveyard;
if(cardHasTypeinZone("planeswalker",checkZone))
pc = 1;
if(cardHasTypeinZone("tribal",checkZone))
tc = 1;
if(cardHasTypeinZone("sorcery",checkZone))
sc = 1;
if(cardHasTypeinZone("land",checkZone))
lc = 1;
if(cardHasTypeinZone("instant",checkZone))
ic = 1;
if(cardHasTypeinZone("enchantment",checkZone))
ec = 1;
if(cardHasTypeinZone("creature",checkZone))
cc = 1;
if(cardHasTypeinZone("artifact",checkZone))
ac = 1;
}
} else {
MTGGameZone * checkZone = (s.find("oppgravecardtypes")!=string::npos)?card->getObserver()->opponent()->game->graveyard:card->controller()->game->graveyard;
if(cardHasTypeinZone("planeswalker",checkZone))
pc = 1;
if(cardHasTypeinZone("tribal",checkZone))
tc = 1;
if(cardHasTypeinZone("sorcery",checkZone))
sc = 1;
if(cardHasTypeinZone("land",checkZone))
lc = 1;
if(cardHasTypeinZone("instant",checkZone))
ic = 1;
if(cardHasTypeinZone("enchantment",checkZone))
ec = 1;
if(cardHasTypeinZone("creature",checkZone))
cc = 1;
if(cardHasTypeinZone("artifact",checkZone))
ac = 1;
}
intValue = pc+tc+sc+lc+ic+ec+cc+ac;
}
else if (s.find("totcnt") != string::npos) //Return the total amount of all specific counters on each card (use "anycnt" to count all of them e.g. Deepwood Denizen)
{
intValue = 0;
for (int j = card->controller()->game->inPlay->nb_cards - 1; j >= 0; --j){
if ((s.find("totcntcre") != string::npos || s.find("totcntall") != string::npos) && card->controller()->game->inPlay->cards[j]->hasType(Subtypes::TYPE_CREATURE)){
if (card->controller()->game->inPlay->cards[j]->counters){
Counters * counters = card->controller()->game->inPlay->cards[j]->counters;
for(size_t i = 0; i < counters->counters.size(); ++i){
Counter * counter = counters->counters[i];
if(s.substr(9) == "anycnt"){
intValue += counter->nb;
} else if(counter->name == "" && (s.substr(9) == "11" || s.substr(9) == "-1-1")){
if((counter->power == 1 && counter->toughness == 1 && s.substr(9) == "11") || (counter->power == -1 && counter->toughness == -1 && s.substr(9) == "-1-1")){
intValue += counter->nb;
break;
}
} else if(counter->name == s.substr(9)){
intValue += counter->nb;
break;
}
}
}
}
}
}
else if(!intValue)//found nothing, try parsing a atoi
{
intValue = atoi(s.c_str());
}
}
int WParsedInt::countDevotionTo(MTGCardInstance * card, MTGGameZone * zone, int color1, int color2)
{
int counthybrid = 0;