Fixed some primitives from issue #1085, fixed some primitives from Discord Channel, fixed "except" keyword for triggers, added "nocost" option for "totalcounteradded" event to avoid to trigger in case of counter cost (e.g. "Doubling Season"), added "removeallcolors" and "removeallsubtypes" options for "transforms" ability.

This commit is contained in:
Vittorio Alfieri
2023-07-25 17:38:25 +02:00
parent 751fda6521
commit 816c42b63b
9 changed files with 183 additions and 123 deletions
+23 -6
View File
@@ -2796,7 +2796,7 @@ AACounter::AACounter(GameObserver* observer, int id, MTGCardInstance * source, M
}
if (!noevent)
{
WEvent * w = NEW WEventTotalCounters(_target->counters, name.c_str(), power, toughness, true, false, totalcounters, source);
WEvent * w = NEW WEventTotalCounters(_target->counters, name.c_str(), power, toughness, true, false, totalcounters, false, source);
dynamic_cast<WEventTotalCounters*>(w)->targetCard = _target->counters->target;
_target->getObserver()->receiveEvent(w);
}
@@ -2812,7 +2812,7 @@ AACounter::AACounter(GameObserver* observer, int id, MTGCardInstance * source, M
}
if (!noevent)
{
WEvent * e = NEW WEventTotalCounters(_target->counters, name.c_str(), power, toughness, false, true, totalcounters, source);
WEvent * e = NEW WEventTotalCounters(_target->counters, name.c_str(), power, toughness, false, true, totalcounters, false, source);
dynamic_cast<WEventTotalCounters*>(e)->targetCard = _target->counters->target;
_target->getObserver()->receiveEvent(e);
}
@@ -7826,10 +7826,12 @@ ATransformer::ATransformer(GameObserver* observer, int id, MTGCardInstance * sou
myCurrentTurn = 1000;
//this subkeyword adds a color without removing the existing colors.
removemc = (sabilities.find("removemc") != string::npos);
removeAllColors = (sabilities.find("removeallcolors") != string::npos);
addNewColors = (sabilities.find("newcolors") != string::npos);
remove = (stypes.find("removealltypes") != string::npos);
removeCreatureSubtypes = (stypes.find("removecreaturesubtypes") != string::npos);
removeTypes = (stypes.find("removetypes") != string::npos);
removeAllSubtypes = (stypes.find("removeallsubtypes") != string::npos);
if (stypes.find("allsubtypes") != string::npos || stypes.find("removecreaturesubtypes") != string::npos)
{
@@ -7894,13 +7896,28 @@ int ATransformer::addToGame()
if(!addNewColors)
_target->setColor(0, 1);
}
if (removeAllColors)
{
for (it = oldcolors.begin(); it != oldcolors.end(); it++)
{
_target->removeColor(*it);
}
}
if (removeTypes)
{
//remove the main types from a card, ie: hidden enchantment cycle.
for (int i = 0; i < Subtypes::LAST_TYPE; ++ i)
_target->removeType(i,1);
}
else if (removeAllSubtypes)
{
//remove all the types from a card without removing official supertypes (e.g. Imprisoned in the Moon)
for (it = oldtypes.begin(); it != oldtypes.end(); it++)
{
if(*it != Subtypes::TYPE_LEGENDARY && *it != Subtypes::TYPE_BASIC && *it != Subtypes::TYPE_SNOW && *it != Subtypes::TYPE_WORLD)
_target->removeType(*it);
}
}
else if (remove)
{
for (it = oldtypes.begin(); it != oldtypes.end(); it++)
@@ -8133,7 +8150,7 @@ int ATransformer::destroy()
{
for (unsigned int i = 0;i < newAbilities[_target].size(); i++)
{
// The mutated cards probably cause a double free error and a crash in Wagic, so for now they have been exluded...
// The mutated cards probably cause a double free error and a crash, so for now they have been exluded...
if(newAbilities[_target].at(i) && !_target->mutation && _target->currentZone != _target->owner->game->library && !(_target->name == "" && (UYNT || UENT)))
{
newAbilities[_target].at(i)->forceDestroy = 1;
@@ -8145,7 +8162,7 @@ int ATransformer::destroy()
newAbilities.erase(_target);
}
}
if (remove || removeCreatureSubtypes)
if (remove || removeCreatureSubtypes || removeAllSubtypes)
{
for (it = oldtypes.begin(); it != oldtypes.end(); it++)
{
@@ -8691,7 +8708,7 @@ int AProduceMana::produce()
{
if(ManaDescription == "selectmana")
{
//I tried menu ability and vector<MTGAbility*abi> to have a shorter code but it crashes wagic at end of turn...
//I tried menu ability and vector<MTGAbility*abi> to have a shorter code but it crashes at end of turn...
//The may ability on otherhand works but the ability is cumulative...
//This must be wrapped on menuability so we can use it on successions...
AManaProducer *ap0 = NEW AManaProducer(game, game->mLayers->actionLayer()->getMaxId(), source, source->controller(), ManaCost::parseManaCost(mana[0],NULL,source), NULL, 0,"",false);
+27 -21
View File
@@ -472,6 +472,7 @@ MTGCardInstance * CardDescriptor::match(MTGCardInstance * card)
if (count)
match = NULL;
}
if (CDcanProduceC == 1)
{
int count = card->canproduceMana(Constants::MTG_COLOR_ARTIFACT) + card->canproduceMana(Constants::MTG_COLOR_WASTE);
@@ -519,24 +520,27 @@ MTGCardInstance * CardDescriptor::match(MTGCardInstance * card)
{
match = NULL;
}
if ((isLeveler == -1 && card->isLeveler) || (isLeveler == 1 && !card->isLeveler))
{
match = NULL;
}
if ((CDenchanted == -1 && card->enchanted) || (CDenchanted == 1 && !card->enchanted))
{
match = NULL;
}
if ((CDdamaged == -1 && card->wasDealtDamage > 0) || (CDdamaged == 1 && card->wasDealtDamage == 0))
{
match = NULL;
}
if ((CDdamager == -1 && (card->damageToOpponent > 0 || card->damageToController > 0 || card->damageToCreature > 0))
|| (CDdamager == 1 && !(card->damageToOpponent > 0 || card->damageToController > 0 || card->damageToCreature > 0)))
{
match = NULL;
}
if ((isLeveler == -1 && card->isLeveler) || (isLeveler == 1 && !card->isLeveler))
{
match = NULL;
}
if ((CDenchanted == -1 && card->enchanted) || (CDenchanted == 1 && !card->enchanted))
{
match = NULL;
}
if ((CDdamaged == -1 && card->wasDealtDamage > 0) || (CDdamaged == 1 && card->wasDealtDamage == 0))
{
match = NULL;
}
if ((CDdamager == -1 && (card->damageToOpponent > 0 || card->damageToController > 0 || card->damageToCreature > 0))
|| (CDdamager == 1 && !(card->damageToOpponent > 0 || card->damageToController > 0 || card->damageToCreature > 0)))
{
match = NULL;
}
if(CDopponentDamaged == -1 || CDopponentDamaged == 1 || CDcontrollerDamaged == -1 || CDcontrollerDamaged == 1)
{
@@ -556,10 +560,12 @@ MTGCardInstance * CardDescriptor::match(MTGCardInstance * card)
match = NULL;
}
}
if ((isToken == -1 && card->isToken) || (isToken == 1 && !card->isToken))
{
match = NULL;
}
if ((isToken == -1 && card->isToken) || (isToken == 1 && !card->isToken))
{
match = NULL;
}
if (attacker == 1)
{
if (defenser == &AnyCard)
+14 -3
View File
@@ -1560,12 +1560,18 @@ int CounterCost::doPay()
if (!target)
return 0;
//Add counters as a cost
if (counter->nb >= 0)
{ //Add counters as a cost
{
int totalcounters = 0;
for (int i = 0; i < counter->nb; i++)
{//send no event because its a cost not an effect... for doubling season
target->counters->addCounter(counter->name.c_str(), counter->power, counter->toughness, true);
{
target->counters->addCounter(counter->name.c_str(), counter->power, counter->toughness);
totalcounters++;
}
WEvent * w = NEW WEventTotalCounters(target->counters, counter->name.c_str(), counter->power, counter->toughness, true, false, totalcounters, true, source);
dynamic_cast<WEventTotalCounters*>(w)->targetCard = target->counters->target;
target->getObserver()->receiveEvent(w);
if (tc)
tc->initTargets();
target = NULL;
@@ -1575,10 +1581,15 @@ int CounterCost::doPay()
//remove counters as a cost
if (hasCounters)
{
int totalcounters = 0;
for (int i = 0; i < -counter->nb; i++)
{
target->counters->removeCounter(counter->name.c_str(), counter->power, counter->toughness);
totalcounters++;
}
WEvent * w = NEW WEventTotalCounters(target->counters, counter->name.c_str(), counter->power, counter->toughness, false, true, totalcounters, true, source);
dynamic_cast<WEventTotalCounters*>(w)->targetCard = target->counters->target;
target->getObserver()->receiveEvent(w);
hasCounters = 0;
if (tc)
tc->initTargets();
+42 -36
View File
@@ -1519,7 +1519,7 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "proliferateof", card)){
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify an exception in order to avoid proliferation loop (eg. Tekuthal, Inquiry Dominus)
if(exception)
return NEW TrplayerProliferated(observer, id, card, tc, once, true, false, exception->source);
return NEW TrplayerProliferated(observer, id, card, tc, once, true, false, exception);
else
return NEW TrplayerProliferated(observer, id, card, tc, once, true, false);
}
@@ -1528,7 +1528,7 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "proliferatefoeof", card)){
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify an exception in order to avoid proliferation loop (eg. Tekuthal, Inquiry Dominus)
if(exception)
return NEW TrplayerProliferated(observer, id, card, tc, once, false, true, exception->source);
return NEW TrplayerProliferated(observer, id, card, tc, once, false, true, exception);
else
return NEW TrplayerProliferated(observer, id, card, tc, once, false, true);
}
@@ -1769,9 +1769,9 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "lifeof", card))
{
TargetChooser *fromTc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop (eg. Angels of Vitality)
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop.
if(exception)
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0, sourceUntapped, once, true, false, limitOnceATurn, exception->source);
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0, sourceUntapped, once, true, false, limitOnceATurn, exception);
else
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0, sourceUntapped, once, true, false, limitOnceATurn);
}
@@ -1780,9 +1780,9 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "lifefoeof", card))
{
TargetChooser *fromTc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop (eg. Angels of Vitality)
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop.
if(exception)
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0, sourceUntapped,once, false, true, limitOnceATurn, exception->source);
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0, sourceUntapped,once, false, true, limitOnceATurn, exception);
else
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0, sourceUntapped,once, false, true, limitOnceATurn);
}
@@ -1791,9 +1791,9 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "lifed", card))
{
TargetChooser *fromTc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop (eg. Angels of Vitality)
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop.
if(exception)
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0, sourceUntapped, once, false, false, limitOnceATurn, exception->source);
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0, sourceUntapped, once, false, false, limitOnceATurn, exception);
else
return NEW TrLifeGained(observer, id, card, tc, fromTc, 0, sourceUntapped, once, false, false, limitOnceATurn);
}
@@ -1802,9 +1802,9 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "lifelostof", card))
{
TargetChooser *fromTc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop (eg. Angels of Vitality)
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop.
if(exception)
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1, sourceUntapped, once, true, false, limitOnceATurn, exception->source);
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1, sourceUntapped, once, true, false, limitOnceATurn, exception);
else
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1, sourceUntapped, once, true, false, limitOnceATurn);
}
@@ -1813,9 +1813,9 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "lifelostfoeof", card))
{
TargetChooser *fromTc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop (eg. Angels of Vitality)
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop.
if(exception)
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1, sourceUntapped, once, false, true, limitOnceATurn,exception->source);
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1, sourceUntapped, once, false, true, limitOnceATurn,exception);
else
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1, sourceUntapped, once, false, true, limitOnceATurn);
}
@@ -1824,9 +1824,9 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
if (TargetChooser * tc = parseSimpleTC(s, "lifeloss", card))
{
TargetChooser *fromTc = parseSimpleTC(s, "from", card);
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop (eg. Angels of Vitality)
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a life gain/loss card exception in order to avoid life gain loop.
if(exception)
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1, sourceUntapped, once, false, false, limitOnceATurn, exception->source);
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1, sourceUntapped, once, false, false, limitOnceATurn, exception);
else
return NEW TrLifeGained(observer, id, card, tc, fromTc, 1, sourceUntapped, once, false, false, limitOnceATurn);
}
@@ -1849,6 +1849,7 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
{
vector<string>splitCounter = parseBetween(s,"totalcounteradded(",")");
Counter * counter = NULL;
bool nocost = false;
bool duplicate = false;
bool half = false;
int plus = 0;
@@ -1862,24 +1863,27 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
plus = 4;
else if(s.find("plus(5)") != string::npos)
plus = 5;
else if(s.find("(duplicateall)") != string::npos)
else if(s.find("duplicate(all)") != string::npos)
duplicate = true;
else if(s.find("(halfall)") != string::npos)
else if(s.find("half(all)") != string::npos)
half = true;
else if(s.find("(any)") == string::npos)
if(s.find("(any)") == string::npos)
counter = parseCounter(splitCounter[1],card,NULL);
if(s.find("nocost") != string::npos)
nocost = true;
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)
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a counter add/remove exception in order to avoid counter loop.
if(exception)
return NEW TrTotalCounter(observer, id, card, counter, tc, 1, once, duplicate, half, plus, limitOnceATurn, exception->source);
return NEW TrTotalCounter(observer, id, card, counter, tc, 1, once, duplicate, half, plus, nocost, limitOnceATurn, exception);
else
return NEW TrTotalCounter(observer, id, card, counter, tc, 1, once, duplicate, half, plus, limitOnceATurn);
return NEW TrTotalCounter(observer, id, card, counter, tc, 1, once, duplicate, half, plus, nocost, limitOnceATurn);
}
if (s.find("totalcounterremoved(") != string::npos)
{
vector<string>splitCounter = parseBetween(s,"totalcounterremoved(",")");
Counter * counter = NULL;
bool nocost = false;
bool duplicate = false;
bool half = false;
int plus = 0;
@@ -1893,18 +1897,20 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
plus = 4;
else if(s.find("plus(5)") != string::npos)
plus = 5;
else if(s.find("(duplicateall)") != string::npos)
else if(s.find("duplicate(all)") != string::npos)
duplicate = true;
else if(s.find("(halfall)") != string::npos)
else if(s.find("half(all)") != string::npos)
half = true;
else if(s.find("(any)") == string::npos)
if(s.find("(any)") == string::npos)
counter = parseCounter(splitCounter[1],card,NULL);
if(s.find("nocost") != string::npos)
nocost = true;
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)
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a counter add/remove exception in order to avoid counter loop.
if(exception)
return NEW TrTotalCounter(observer, id, card, counter, tc, 0, once, duplicate, half, plus, limitOnceATurn, exception->source);
return NEW TrTotalCounter(observer, id, card, counter, tc, 0, once, duplicate, half, plus, nocost, limitOnceATurn, exception);
else
return NEW TrTotalCounter(observer, id, card, counter, tc, 0, once, duplicate, half, plus, limitOnceATurn);
return NEW TrTotalCounter(observer, id, card, counter, tc, 0, once, duplicate, half, plus, nocost, limitOnceATurn);
}
if (s.find("counteradded(") != string::npos)
@@ -1912,14 +1918,14 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
vector<string>splitCounter = parseBetween(s,"counteradded(",")");
Counter * counter = NULL;
bool duplicate = false;
if(s.find("(duplicateall)") != string::npos)
if(s.find("duplicate(all)") != string::npos)
duplicate = true;
else if(s.find("(any)") == string::npos)
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)
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a counter add/remove exception in order to avoid counter loop.
if(exception)
return NEW TrCounter(observer, id, card, counter, tc, 1, once, duplicate, limitOnceATurn, exception->source);
return NEW TrCounter(observer, id, card, counter, tc, 1, once, duplicate, limitOnceATurn, exception);
else
return NEW TrCounter(observer, id, card, counter, tc, 1, once, duplicate, limitOnceATurn);
}
@@ -1929,14 +1935,14 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
vector<string>splitCounter = parseBetween(s,"counterremoved(",")");
Counter * counter = NULL;
bool duplicate = false;
if(s.find("(duplicateall)") != string::npos)
if(s.find("duplicate(all)") != string::npos)
duplicate = true;
else if(s.find("(any)") == string::npos)
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)
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a counter add/remove exception in order to avoid counter loop.
if(exception)
return NEW TrCounter(observer, id, card, counter, tc, 0, once, duplicate, limitOnceATurn, exception->source);
return NEW TrCounter(observer, id, card, counter, tc, 0, once, duplicate, limitOnceATurn, exception);
else
return NEW TrCounter(observer, id, card, counter, tc, 0, once, duplicate, limitOnceATurn);
}
@@ -1948,9 +1954,9 @@ TriggeredAbility * AbilityFactory::parseTrigger(string s, string, int id, Spell
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)
TargetChooser *exception = parseSimpleTC(s, "except", card); // Added a new keyword except to specify a counter add/remove exception in order to avoid counter loop.
if(exception)
return NEW TrCounter(observer, id, card, counter, tc, 2, once, false, limitOnceATurn, exception->source);
return NEW TrCounter(observer, id, card, counter, tc, 2, once, false, limitOnceATurn, exception);
else
return NEW TrCounter(observer, id, card, counter, tc, 2, once, false, limitOnceATurn);
}
+2 -2
View File
@@ -48,8 +48,8 @@ WEvent(),counter(counter),name(name),power(power),toughness(toughness),added(add
{
}
WEventTotalCounters::WEventTotalCounters(Counters *counter, string name, int power, int toughness, bool added, bool removed, int totalamount, MTGCardInstance* source) :
WEvent(),counter(counter),name(name),power(power),toughness(toughness),added(added),removed(removed),totalamount(totalamount),source(source)
WEventTotalCounters::WEventTotalCounters(Counters *counter, string name, int power, int toughness, bool added, bool removed, int totalamount, bool iscost, MTGCardInstance* source) :
WEvent(),counter(counter),name(name),power(power),toughness(toughness),added(added),removed(removed),totalamount(totalamount),iscost(iscost),source(source)
{
}