Skip to content

Commit

Permalink
Fixed some primitives from issue #1085, fixed some primitives from Di…
Browse files Browse the repository at this point in the history
…scord 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.
  • Loading branch information
Vitty85 committed Jul 25, 2023
1 parent 751fda6 commit 816c42b
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 123 deletions.
81 changes: 43 additions & 38 deletions projects/mtg/bin/Res/sets/primitives/borderline.txt

Large diffs are not rendered by default.

16 changes: 13 additions & 3 deletions projects/mtg/bin/Res/sets/primitives/mtg.txt
Original file line number Diff line number Diff line change
@@ -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 programmatically so the other comments are removed except for AUTO_DEFINE - Vitty85 24-07-2023
#I sorted this programmatically so the other comments are removed except for AUTO_DEFINE - Vitty85 25-07-2023
[card]
name=Abandon Reason
target=<upto:2>creature
Expand Down Expand Up @@ -24482,7 +24482,16 @@ type=Land
[/card]
[card]
name=Crypt Rats
auto={X:black}:damage:X all(creature) && damage:X all(player)
auto={B}:name(X=1) damage:1 all(creature|battlefield) && damage:1 all(player)
auto={B}{B}:name(X=2) damage:2 all(creature|battlefield) && damage:2 all(player)
auto={B}{B}{B}:name(X=3) damage:3 all(creature|battlefield) && damage:3 all(player)
auto={B}{B}{B}{B}:name(X=4) damage:4 all(creature|battlefield) && damage:4 all(player)
auto={B}{B}{B}{B}{B}:name(X=5) damage:5 all(creature|battlefield) && damage:5 all(player)
auto={B}{B}{B}{B}{B}{B}:name(X=6) damage:6 all(creature|battlefield) && damage:6 all(player)
auto={B}{B}{B}{B}{B}{B}{B}:name(X=7) damage:7 all(creature|battlefield) && damage:7 all(player)
auto={B}{B}{B}{B}{B}{B}{B}{B}:name(X=8) damage:8 all(creature|battlefield) && damage:8 all(player)
auto={B}{B}{B}{B}{B}{B}{B}{B}{B}:name(X=9) damage:9 all(creature|battlefield) && damage:9 all(player)
auto={B}{B}{B}{B}{B}{B}{B}{B}{B}{B}{X:black}:name(X>=10) damage:Xplus10plusend all(creature|battlefield) && damage:Xplus10plusend all(player)
text={X}: Crypt Rats deals X damage to each creature and each player. Spend only black mana this way.
mana={2}{B}
type=Creature
Expand Down Expand Up @@ -29106,7 +29115,8 @@ toughness=2
[card]
name=Devoted Druid
auto={T}:add{G}
auto={0}:name(Put counter and untap) transforms((,newability[counter(-1/-1)],newability[untap])) oneshot
#auto={0}:name(Put counter and untap) transforms((,newability[counter(-1/-1)],newability[untap])) oneshot
auto={C(-1/-1,1)}:name(Put counter and untap) untap
text={T}: Add {G} to your mana pool. -- Put a -1/-1 counter on Devoted Druid: Untap Devoted Druid.
mana={1}{G}
type=Creature
Expand Down
30 changes: 17 additions & 13 deletions projects/mtg/include/AllAbilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -746,8 +746,8 @@ class TrplayerProliferated: public Trigger
{
public:
bool thiscontroller, thisopponent;
MTGCardInstance * proliferateException; //added exception to avid a proliferation loop (eg. Tekuthal, Inquiry Dominus)
TrplayerProliferated(GameObserver* observer, int id, MTGCardInstance * source, TargetChooser * tc, bool once = false, bool thiscontroller = false, bool thisopponent = false, MTGCardInstance * proliferateException = NULL) :
TargetChooser * proliferateException; //added exception to avid a proliferation loop (eg. Tekuthal, Inquiry Dominus)
TrplayerProliferated(GameObserver* observer, int id, MTGCardInstance * source, TargetChooser * tc, bool once = false, bool thiscontroller = false, bool thisopponent = false, TargetChooser * proliferateException = NULL) :
Trigger(observer, id, source, once, tc), thiscontroller(thiscontroller), thisopponent(thisopponent), proliferateException(proliferateException)
{
}
Expand All @@ -756,7 +756,7 @@ class TrplayerProliferated: public Trigger
{
WEventplayerProliferated * e = dynamic_cast<WEventplayerProliferated *> (event);
if (!e) return 0;
if (proliferateException && e->source && !strcmp(proliferateException->data->name.c_str(), e->source->data->name.c_str())) return 0; //If the source of proliferation it's the exception card it doesn't have effect (loop avoidance);
if (proliferateException && proliferateException->canTarget(e->source)) return 0; //If the source of proliferation belongs to exception it doesn't have effect (loop avoidance);
if (!tc->canTarget(e->player)) return 0;
if(thiscontroller)
if(e->player != source->controller())
Expand Down Expand Up @@ -1485,8 +1485,8 @@ class TrLifeGained: public Trigger
bool sourceUntapped, thiscontroller, thisopponent;
bool limitOnceATurn;
int triggeredTurn;
MTGCardInstance * gainException; //added exception to avid a gainlife loop (eg. Angels of Vitality)
TrLifeGained(GameObserver* observer, int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL, int type = 0, bool sourceUntapped = false, bool once = false, bool thiscontroller = false, bool thisopponent = false, bool limitOnceATurn = false, MTGCardInstance * gainException = NULL) :
TargetChooser * gainException; //added exception to avid a gainlife loop
TrLifeGained(GameObserver* observer, int id, MTGCardInstance * source, TargetChooser * tc, TargetChooser * fromTc = NULL, int type = 0, bool sourceUntapped = false, bool once = false, bool thiscontroller = false, bool thisopponent = false, bool limitOnceATurn = false, TargetChooser * gainException = NULL) :
Trigger(observer, id, source, once , tc), fromTc(fromTc), type(type), sourceUntapped(sourceUntapped), thiscontroller(thiscontroller), thisopponent(thisopponent), limitOnceATurn(limitOnceATurn), gainException(gainException)
{
triggeredTurn = -1;
Expand All @@ -1503,7 +1503,7 @@ class TrLifeGained: public Trigger
if (!tc->canTarget(e->player)) return 0;
//if (fromTc && !fromTc->canTarget(e->player)) return 0;
if (fromTc && !fromTc->canTarget(e->source)) return 0; //Now it's possible to specify if a source can trigger or not the event of life gain
if (gainException && e->source && !strcmp(gainException->data->name.c_str(), e->source->data->name.c_str())) return 0; //If the source of life gain it's the exception card don't gain life (loop avoidance);
if (gainException && gainException->canTarget(e->source)) return 0; //If the source of life gain belongs to exception it doesn't have effect (loop avoidance);
if (type == 1 && (e->amount > 0)) return 0;
if (type == 0 && (e->amount < 0)) return 0;
if(thiscontroller)
Expand Down Expand Up @@ -1618,8 +1618,8 @@ class TrCounter: public Trigger
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, bool limitOnceATurn = false, MTGCardInstance * counterException = NULL) :
TargetChooser * 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, bool limitOnceATurn = false, TargetChooser * counterException = NULL) :
Trigger(observer, id, source, once, tc), counter(counter), type(type), duplicate(duplicate), limitOnceATurn(limitOnceATurn), counterException(counterException)
{
triggeredTurn = -1;
Expand All @@ -1633,7 +1633,7 @@ class TrCounter: public Trigger
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);
if (counterException && counterException->canTarget(e->source)) return 0; //If the source of counter gain/loss belongs to exception it doesn't have effect (loop avoidance);
if (counter && !(e->power == counter->power && e->toughness == counter->toughness && e->name == counter->name)) return 0;
if (tc && !tc->canTarget(e->targetCard)) return 0;
if (duplicate){
Expand Down Expand Up @@ -1668,11 +1668,12 @@ class TrTotalCounter: public Trigger
bool duplicate;
bool half;
int plus;
bool nocost; //added to avoid trigger on counter cost payment (eg. Doubling Season)
bool limitOnceATurn;
int triggeredTurn;
MTGCardInstance * counterException; //added exception to avid a counter loop (eg. Doubling Season)
TrTotalCounter(GameObserver* observer, int id, MTGCardInstance * source, Counter * counter, TargetChooser * tc, int type = 0, bool once = false, bool duplicate = false, bool half = false, int plus = 0, bool limitOnceATurn = false, MTGCardInstance * counterException = NULL) :
Trigger(observer, id, source, once, tc), counter(counter), type(type), duplicate(duplicate), half(half), plus(plus), limitOnceATurn(limitOnceATurn), counterException(counterException)
TargetChooser * counterException; //added exception to avid a counter loop.
TrTotalCounter(GameObserver* observer, int id, MTGCardInstance * source, Counter * counter, TargetChooser * tc, int type = 0, bool once = false, bool duplicate = false, bool half = false, int plus = 0, bool nocost = false, bool limitOnceATurn = false, TargetChooser * counterException = NULL) :
Trigger(observer, id, source, once, tc), counter(counter), type(type), duplicate(duplicate), half(half), plus(plus), nocost(nocost), limitOnceATurn(limitOnceATurn), counterException(counterException)
{
triggeredTurn = -1;
}
Expand All @@ -1685,7 +1686,8 @@ class TrTotalCounter: public Trigger
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);
if (nocost && e->iscost) return 0;
if (counterException && counterException->canTarget(e->source)) return 0; //If the source of counter gain/loss belongs to exception it doesn't have effect (loop avoidance);
if (counter && !(e->power == counter->power && e->toughness == counter->toughness && e->name == counter->name)) return 0;
if (tc && !tc->canTarget(e->targetCard)) return 0;
if (plus > 0){
Expand Down Expand Up @@ -5409,10 +5411,12 @@ class ATransformer: public MTGAbility
list<int> oldtypes;
vector<int> dontremove;
bool removemc;
bool removeAllColors;
bool addNewColors;
bool remove;
bool removeCreatureSubtypes;
bool removeTypes;
bool removeAllSubtypes;
string menu;

string newpower;
Expand Down
3 changes: 2 additions & 1 deletion projects/mtg/include/WEvent.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,9 @@ struct WEventTotalCounters : public WEvent {
bool added;
bool removed;
int totalamount;
bool iscost;
MTGCardInstance * source;
WEventTotalCounters(Counters *counter,string name,int power, int toughness,bool added = false, bool removed = false, int totalamount = 0, MTGCardInstance * source = NULL);
WEventTotalCounters(Counters *counter,string name,int power, int toughness,bool added = false, bool removed = false, int totalamount = 0, bool iscost = false, MTGCardInstance * source = NULL);
using WEvent::getTarget;
virtual Targetable * getTarget(int target);
};
Expand Down
29 changes: 23 additions & 6 deletions projects/mtg/src/AllAbilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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++)
Expand Down Expand Up @@ -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;
Expand All @@ -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++)
{
Expand Down Expand Up @@ -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);
Expand Down
48 changes: 27 additions & 21 deletions projects/mtg/src/CardDescriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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)
{
Expand All @@ -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)
Expand Down
17 changes: 14 additions & 3 deletions projects/mtg/src/ExtraCost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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();
Expand Down
Loading

0 comments on commit 816c42b

Please sign in to comment.