diff --git a/Mage.Sets/src/mage/cards/a/AngelsTomb.java b/Mage.Sets/src/mage/cards/a/AngelsTomb.java
index 9cfa070e560..f3be463600b 100644
--- a/Mage.Sets/src/mage/cards/a/AngelsTomb.java
+++ b/Mage.Sets/src/mage/cards/a/AngelsTomb.java
@@ -28,6 +28,7 @@
package mage.cards.a;
import java.util.UUID;
+
import mage.MageInt;
import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect;
@@ -39,18 +40,23 @@ import mage.constants.Duration;
import mage.constants.SubType;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
+import mage.game.permanent.token.custom.CreatureToken;
/**
- *
* @author Loki
*/
public class AngelsTomb extends CardImpl {
public AngelsTomb(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}");
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// Whenever a creature enters the battlefield under your control, you may have Angel's Tomb become a 3/3 white Angel artifact creature with flying until end of turn.
- this.addAbility(new CreatureEntersBattlefieldTriggeredAbility(new BecomesCreatureSourceEffect(new AngelTombToken(), "", Duration.EndOfTurn), true));
+ this.addAbility(new CreatureEntersBattlefieldTriggeredAbility(new BecomesCreatureSourceEffect(
+ new CreatureToken(3, 3, "3/3 white Angel artifact creature with flying")
+ .withColor("W")
+ .withSubType(SubType.ANGEL)
+ .withAbility(FlyingAbility.getInstance()),
+ "", Duration.EndOfTurn), true));
}
public AngelsTomb(final AngelsTomb card) {
@@ -61,26 +67,4 @@ public class AngelsTomb extends CardImpl {
public AngelsTomb copy() {
return new AngelsTomb(this);
}
-}
-
-class AngelTombToken extends TokenImpl {
-
- public AngelTombToken() {
- super("", "3/3 white Angel artifact creature with flying");
- cardType.add(CardType.ARTIFACT);
- cardType.add(CardType.CREATURE);
- color.setWhite(true);
-
- subtype.add(SubType.ANGEL);
- power = new MageInt(3);
- toughness = new MageInt(3);
- addAbility(FlyingAbility.getInstance());
- }
- public AngelTombToken(final AngelTombToken token) {
- super(token);
- }
-
- public AngelTombToken copy() {
- return new AngelTombToken(this);
- }
-}
+}
\ No newline at end of file
diff --git a/Mage.Sets/src/mage/cards/a/AtarkaMonument.java b/Mage.Sets/src/mage/cards/a/AtarkaMonument.java
index 10f2d52cebb..6d35ee10a1d 100644
--- a/Mage.Sets/src/mage/cards/a/AtarkaMonument.java
+++ b/Mage.Sets/src/mage/cards/a/AtarkaMonument.java
@@ -28,6 +28,7 @@
package mage.cards.a;
import java.util.UUID;
+
import mage.MageInt;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
@@ -43,23 +44,28 @@ import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
+import mage.game.permanent.token.custom.CreatureToken;
/**
- *
* @author fireshoes
*/
public class AtarkaMonument extends CardImpl {
public AtarkaMonument(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}");
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// {T}: Add {R} or {G}.
this.addAbility(new RedManaAbility());
this.addAbility(new GreenManaAbility());
-
+
// {4}{R}{G}: Atarka Monument becomes a 4/4 red and green Dragon artifact creature with flying until end of turn.
- this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect
- (new AtarkaMonumentToken(), "", Duration.EndOfTurn), new ManaCostsImpl("{4}{R}{G}")));
+ this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(
+ new CreatureToken(4, 4, "4/4 red and green Dragon artifact creature with flying")
+ .withColor("RG")
+ .withSubType(SubType.DRAGON)
+ .withType(CardType.ARTIFACT)
+ .withAbility(FlyingAbility.getInstance()),
+ "", Duration.EndOfTurn), new ManaCostsImpl("{4}{R}{G}")));
}
public AtarkaMonument(final AtarkaMonument card) {
@@ -70,25 +76,4 @@ public class AtarkaMonument extends CardImpl {
public AtarkaMonument copy() {
return new AtarkaMonument(this);
}
-
- private static class AtarkaMonumentToken extends TokenImpl {
- AtarkaMonumentToken() {
- super("", "4/4 red and green Dragon artifact creature with flying");
- this.cardType.add(CardType.ARTIFACT);
- this.cardType.add(CardType.CREATURE);
- this.color.setRed(true);
- this.color.setGreen(true);
- this.subtype.add(SubType.DRAGON);
- this.power = new MageInt(4);
- this.toughness = new MageInt(4);
- this.addAbility(FlyingAbility.getInstance());
- }
- public AtarkaMonumentToken(final AtarkaMonumentToken token) {
- super(token);
- }
-
- public AtarkaMonumentToken copy() {
- return new AtarkaMonumentToken(this);
- }
- }
}
diff --git a/Mage.Sets/src/mage/cards/a/AzoriusKeyrune.java b/Mage.Sets/src/mage/cards/a/AzoriusKeyrune.java
index c2944228124..6338b5cf6ca 100644
--- a/Mage.Sets/src/mage/cards/a/AzoriusKeyrune.java
+++ b/Mage.Sets/src/mage/cards/a/AzoriusKeyrune.java
@@ -28,6 +28,7 @@
package mage.cards.a;
import java.util.UUID;
+
import mage.MageInt;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
@@ -43,6 +44,7 @@ import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
+import mage.game.permanent.token.custom.CreatureToken;
/**
* @author LevelX2
@@ -50,14 +52,20 @@ import mage.game.permanent.token.Token;
public class AzoriusKeyrune extends CardImpl {
public AzoriusKeyrune(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}");
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// {T}: Add {W} or {U}.
this.addAbility(new WhiteManaAbility());
this.addAbility(new BlueManaAbility());
// {W}{U}: Azorius Keyrune becomes a 2/2 white and blue Bird artifact creature with flying until end of turn.
- this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new AzoriusKeyruneToken(), "", Duration.EndOfTurn), new ManaCostsImpl("{W}{U}")));
+ this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(
+ new CreatureToken(2, 2, "2/2 white and blue Bird artifact creature with flying")
+ .withColor("WU")
+ .withSubType(SubType.BIRD)
+ .withType(CardType.ARTIFACT)
+ .withAbility(FlyingAbility.getInstance()),
+ "", Duration.EndOfTurn), new ManaCostsImpl("{W}{U}")));
}
public AzoriusKeyrune(final AzoriusKeyrune card) {
@@ -68,25 +76,4 @@ public class AzoriusKeyrune extends CardImpl {
public AzoriusKeyrune copy() {
return new AzoriusKeyrune(this);
}
-
- private static class AzoriusKeyruneToken extends TokenImpl {
- AzoriusKeyruneToken() {
- super("", "2/2 white and blue Bird artifact creature with flying");
- cardType.add(CardType.ARTIFACT);
- cardType.add(CardType.CREATURE);
- color.setWhite(true);
- color.setBlue(true);
- this.subtype.add(SubType.BIRD);
- power = new MageInt(2);
- toughness = new MageInt(2);
- this.addAbility(FlyingAbility.getInstance());
- }
- public AzoriusKeyruneToken(final AzoriusKeyruneToken token) {
- super(token);
- }
-
- public AzoriusKeyruneToken copy() {
- return new AzoriusKeyruneToken(this);
- }
- }
}
diff --git a/Mage.Sets/src/mage/cards/b/BlinkmothNexus.java b/Mage.Sets/src/mage/cards/b/BlinkmothNexus.java
index 0a5aed5fed8..ddb504a800c 100644
--- a/Mage.Sets/src/mage/cards/b/BlinkmothNexus.java
+++ b/Mage.Sets/src/mage/cards/b/BlinkmothNexus.java
@@ -29,6 +29,7 @@
package mage.cards.b;
import java.util.UUID;
+
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@@ -48,6 +49,7 @@ import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.SubtypePredicate;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
+import mage.game.permanent.token.custom.CreatureToken;
import mage.target.TargetPermanent;
/**
@@ -62,14 +64,19 @@ public class BlinkmothNexus extends CardImpl {
}
public BlinkmothNexus(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},null);
-
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, null);
+
// {T}: Add {C}to your mana pool.
this.addAbility(new ColorlessManaAbility());
-
+
// {1}: Blinkmoth Nexus becomes a 1/1 Blinkmoth artifact creature with flying until end of turn. It's still a land.
- this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new BlinkmothNexusToken(), "land", Duration.EndOfTurn), new GenericManaCost(1)));
-
+ this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(
+ new CreatureToken(1, 1, "1/1 Blinkmoth artifact creature with flying")
+ .withSubType(SubType.BLINKMOTH)
+ .withType(CardType.ARTIFACT)
+ .withAbility(FlyingAbility.getInstance()),
+ "land", Duration.EndOfTurn), new GenericManaCost(1)));
+
// {1}, {T}: Target Blinkmoth creature gets +1/+1 until end of turn.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(1, 1, Duration.EndOfTurn), new GenericManaCost(1));
ability.addCost(new TapSourceCost());
@@ -88,22 +95,3 @@ public class BlinkmothNexus extends CardImpl {
}
}
-
-class BlinkmothNexusToken extends TokenImpl {
- public BlinkmothNexusToken() {
- super("Blinkmoth", "1/1 Blinkmoth artifact creature with flying");
- cardType.add(CardType.ARTIFACT);
- cardType.add(CardType.CREATURE);
- this.subtype.add(SubType.BLINKMOTH);
- power = new MageInt(1);
- toughness = new MageInt(1);
- this.addAbility(FlyingAbility.getInstance());
- }
- public BlinkmothNexusToken(final BlinkmothNexusToken token) {
- super(token);
- }
-
- public BlinkmothNexusToken copy() {
- return new BlinkmothNexusToken(this);
- }
-}
diff --git a/Mage.Sets/src/mage/cards/b/BorosKeyrune.java b/Mage.Sets/src/mage/cards/b/BorosKeyrune.java
index 8cb37bd545c..7d1a77dd836 100644
--- a/Mage.Sets/src/mage/cards/b/BorosKeyrune.java
+++ b/Mage.Sets/src/mage/cards/b/BorosKeyrune.java
@@ -28,6 +28,7 @@
package mage.cards.b;
import java.util.UUID;
+
import mage.MageInt;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
@@ -43,22 +44,28 @@ import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
+import mage.game.permanent.token.custom.CreatureToken;
/**
- *
* @author LevelX2
*/
public class BorosKeyrune extends CardImpl {
public BorosKeyrune(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}");
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// {T}: Add {R} or {W}.
this.addAbility(new RedManaAbility());
this.addAbility(new WhiteManaAbility());
// {R}{W}: Boros Keyrune becomes a 1/1 red and white Soldier artifact creature with double strike until end of turn.
- this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new BorosKeyruneToken(), "", Duration.EndOfTurn), new ManaCostsImpl("{R}{W}")));
+ this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(
+ new CreatureToken(1, 1, "1/1 red and white Soldier artifact creature with double strike")
+ .withColor("RW")
+ .withSubType(SubType.SOLDIER)
+ .withType(CardType.ARTIFACT)
+ .withAbility(DoubleStrikeAbility.getInstance()),
+ "", Duration.EndOfTurn), new ManaCostsImpl("{R}{W}")));
}
public BorosKeyrune(final BorosKeyrune card) {
@@ -69,25 +76,4 @@ public class BorosKeyrune extends CardImpl {
public BorosKeyrune copy() {
return new BorosKeyrune(this);
}
-
- private static class BorosKeyruneToken extends TokenImpl {
- BorosKeyruneToken() {
- super("Soldier", "1/1 red and white Soldier artifact creature with double strike");
- cardType.add(CardType.ARTIFACT);
- cardType.add(CardType.CREATURE);
- color.setRed(true);
- color.setWhite(true);
- subtype.add(SubType.SOLDIER);
- power = new MageInt(1);
- toughness = new MageInt(1);
- this.addAbility(DoubleStrikeAbility.getInstance());
- }
- public BorosKeyruneToken(final BorosKeyruneToken token) {
- super(token);
- }
-
- public BorosKeyruneToken copy() {
- return new BorosKeyruneToken(this);
- }
- }
}
diff --git a/Mage.Sets/src/mage/cards/c/CelestialColonnade.java b/Mage.Sets/src/mage/cards/c/CelestialColonnade.java
index 982ba8a0580..99b2a16486c 100644
--- a/Mage.Sets/src/mage/cards/c/CelestialColonnade.java
+++ b/Mage.Sets/src/mage/cards/c/CelestialColonnade.java
@@ -28,6 +28,7 @@
package mage.cards.c;
import java.util.UUID;
+
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTappedAbility;
import mage.abilities.common.SimpleActivatedAbility;
@@ -45,20 +46,31 @@ import mage.constants.Duration;
import mage.constants.Zone;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
+import mage.game.permanent.token.custom.CreatureToken;
/**
- *
* @author BetaSteward_at_googlemail.com
*/
public class CelestialColonnade extends CardImpl {
public CelestialColonnade(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.LAND},null);
+ super(ownerId, setInfo, new CardType[]{CardType.LAND}, null);
+
+ // Celestial Colonnade enters the battlefield tapped.
this.addAbility(new EntersBattlefieldTappedAbility());
+
+ // {T}: Add {W} or {U]
this.addAbility(new BlueManaAbility());
this.addAbility(new WhiteManaAbility());
- this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new CelestialColonnadeToken(), "land", Duration.EndOfTurn), new ManaCostsImpl("{3}{W}{U}")));
+ // {3}{W}{U}: Until end of turn, Celestial Colonnade becomes a 4/4 white and blue Elemental creature with flying and vigilance. It’s still a land.
+ this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(
+ new CreatureToken(4, 4, "4/4 white and blue Elemental creature with flying and vigilance")
+ .withColor("WU")
+ .withSubType(SubType.ELEMENTAL)
+ .withAbility(FlyingAbility.getInstance())
+ .withAbility(VigilanceAbility.getInstance()),
+ "land", Duration.EndOfTurn), new ManaCostsImpl("{3}{W}{U}")));
}
public CelestialColonnade(final CelestialColonnade card) {
@@ -70,27 +82,4 @@ public class CelestialColonnade extends CardImpl {
return new CelestialColonnade(this);
}
-}
-
-class CelestialColonnadeToken extends TokenImpl {
-
- public CelestialColonnadeToken() {
- super("", "4/4 white and blue Elemental creature with flying and vigilance");
- cardType.add(CardType.CREATURE);
- subtype.add(SubType.ELEMENTAL);
- color.setBlue(true);
- color.setWhite(true);
- power = new MageInt(4);
- toughness = new MageInt(4);
- addAbility(FlyingAbility.getInstance());
- addAbility(VigilanceAbility.getInstance());
- }
- public CelestialColonnadeToken(final CelestialColonnadeToken token) {
- super(token);
- }
-
- public CelestialColonnadeToken copy() {
- return new CelestialColonnadeToken(this);
- }
-
-}
+}
\ No newline at end of file
diff --git a/Mage.Sets/src/mage/cards/c/ChimericEgg.java b/Mage.Sets/src/mage/cards/c/ChimericEgg.java
index 6430539440b..0630e258e3b 100644
--- a/Mage.Sets/src/mage/cards/c/ChimericEgg.java
+++ b/Mage.Sets/src/mage/cards/c/ChimericEgg.java
@@ -28,6 +28,7 @@
package mage.cards.c;
import java.util.UUID;
+
import mage.MageInt;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SpellCastOpponentTriggeredAbility;
@@ -48,11 +49,10 @@ import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.CardTypePredicate;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
-
+import mage.game.permanent.token.custom.CreatureToken;
/**
- *
* @author Pete Rossi
*/
public class ChimericEgg extends CardImpl {
@@ -65,13 +65,17 @@ public class ChimericEgg extends CardImpl {
public ChimericEgg(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
-
+
// Whenever an opponent casts a nonartifact spell, put a charge counter on Chimeric Egg.
this.addAbility(new SpellCastOpponentTriggeredAbility(new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), nonArtifactFilter, false));
// Remove three charge counters from Chimeric Egg: Chimeric Egg becomes a 6/6 Construct artifact creature with trample until end of turn.
- this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect
- (new ChimericEggToken(), "", Duration.EndOfTurn), new RemoveCountersSourceCost(new Counter(CounterType.CHARGE.getName(), 3))));
+ this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(
+ new CreatureToken(6, 6, "6/6 Construct artifact creature with trample")
+ .withSubType(SubType.CONSTRUCT)
+ .withType(CardType.ARTIFACT)
+ .withAbility(TrampleAbility.getInstance()),
+ "", Duration.EndOfTurn), new RemoveCountersSourceCost(new Counter(CounterType.CHARGE.getName(), 3))));
}
public ChimericEgg(final ChimericEgg card) {
@@ -82,23 +86,4 @@ public class ChimericEgg extends CardImpl {
public ChimericEgg copy() {
return new ChimericEgg(this);
}
-
- private static class ChimericEggToken extends TokenImpl {
- ChimericEggToken() {
- super("", "6/6 Construct artifact creature with trample");
- cardType.add(CardType.ARTIFACT);
- cardType.add(CardType.CREATURE);
- this.subtype.add(SubType.CONSTRUCT);
- power = new MageInt(6);
- toughness = new MageInt(6);
- this.addAbility(TrampleAbility.getInstance());
- }
- public ChimericEggToken(final ChimericEggToken token) {
- super(token);
- }
-
- public ChimericEggToken copy() {
- return new ChimericEggToken(this);
- }
- }
}
diff --git a/Mage.Sets/src/mage/cards/c/ChimericIdol.java b/Mage.Sets/src/mage/cards/c/ChimericIdol.java
index 9b4e6b0f79b..b8db34d7b14 100644
--- a/Mage.Sets/src/mage/cards/c/ChimericIdol.java
+++ b/Mage.Sets/src/mage/cards/c/ChimericIdol.java
@@ -28,6 +28,7 @@
package mage.cards.c;
import java.util.UUID;
+
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
@@ -43,19 +44,23 @@ import mage.constants.Zone;
import mage.filter.common.FilterControlledLandPermanent;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
+import mage.game.permanent.token.custom.CreatureToken;
/**
- *
* @author LevelX2
*/
public class ChimericIdol extends CardImpl {
public ChimericIdol(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}");
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// {0}: Tap all lands you control. Chimeric Idol becomes a 3/3 Turtle artifact creature until end of turn.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapAllEffect(new FilterControlledLandPermanent("lands you control")), new ManaCostsImpl("{0}"));
- ability.addEffect(new BecomesCreatureSourceEffect(new ChimericIdolToken(), "", Duration.EndOfTurn));
+ ability.addEffect(new BecomesCreatureSourceEffect(
+ new CreatureToken(3, 3, "3/3 Turtle artifact creature")
+ .withSubType(SubType.TURTLE)
+ .withType(CardType.ARTIFACT),
+ "", Duration.EndOfTurn));
this.addAbility(ability);
}
@@ -68,23 +73,4 @@ public class ChimericIdol extends CardImpl {
public ChimericIdol copy() {
return new ChimericIdol(this);
}
-}
-
-class ChimericIdolToken extends TokenImpl {
-
- public ChimericIdolToken() {
- super("Turtle", "3/3 Turtle artifact creature token");
- cardType.add(CardType.ARTIFACT);
- cardType.add(CardType.CREATURE);
- subtype.add(SubType.TURTLE);
- power = new MageInt(3);
- toughness = new MageInt(3);
- }
- public ChimericIdolToken(final ChimericIdolToken token) {
- super(token);
- }
-
- public ChimericIdolToken copy() {
- return new ChimericIdolToken(this);
- }
-}
+}
\ No newline at end of file
diff --git a/Mage.Sets/src/mage/cards/c/ChimericMass.java b/Mage.Sets/src/mage/cards/c/ChimericMass.java
index 115efb12669..3c47fffbb33 100644
--- a/Mage.Sets/src/mage/cards/c/ChimericMass.java
+++ b/Mage.Sets/src/mage/cards/c/ChimericMass.java
@@ -28,6 +28,7 @@
package mage.cards.c;
import java.util.UUID;
+
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldAbility;
import mage.abilities.common.SimpleActivatedAbility;
@@ -46,6 +47,7 @@ import mage.constants.Zone;
import mage.counters.CounterType;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.Token;
+import mage.game.permanent.token.custom.CreatureToken;
/**
* @author BetaSteward_at_googlemail.com
@@ -53,14 +55,19 @@ import mage.game.permanent.token.Token;
public class ChimericMass extends CardImpl {
public ChimericMass(UUID ownerId, CardSetInfo setInfo) {
- super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{X}");
+ super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{X}");
// Chimeric Mass enters the battlefield with X charge counters on it.
this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.CHARGE.createInstance())));
// {1}: Until end of turn, Chimeric Mass becomes a Construct artifact creature with "This creature's power and toughness are each equal to the number of charge counters on it."
// set to character defining to prevent setting P/T again to 0 becuase already set by CDA of the token
- this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new ChimericMassToken(), "", Duration.EndOfTurn, false, true), new GenericManaCost(1)));
+ this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(
+ new CreatureToken(0, 0, "Construct artifact creature with \"This creature's power and toughness are each equal to the number of charge counters on it.\"")
+ .withType(CardType.ARTIFACT)
+ .withSubType(SubType.CONSTRUCT)
+ .withAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetPowerToughnessSourceEffect(new CountersSourceCount(CounterType.CHARGE), Duration.WhileOnBattlefield))),
+ "", Duration.EndOfTurn, false, true), new GenericManaCost(1)));
}
public ChimericMass(final ChimericMass card) {
@@ -72,23 +79,4 @@ public class ChimericMass extends CardImpl {
return new ChimericMass(this);
}
-}
-
-class ChimericMassToken extends TokenImpl {
-
- public ChimericMassToken() {
- super("", "Construct artifact creature with \"This creature's power and toughness are each equal to the number of charge counters on it.\"");
- cardType.add(CardType.CREATURE);
- subtype.add(SubType.CONSTRUCT);
- power = new MageInt(0);
- toughness = new MageInt(0);
- this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetPowerToughnessSourceEffect(new CountersSourceCount(CounterType.CHARGE), Duration.WhileOnBattlefield)));
- }
- public ChimericMassToken(final ChimericMassToken token) {
- super(token);
- }
-
- public ChimericMassToken copy() {
- return new ChimericMassToken(this);
- }
-}
+}
\ No newline at end of file
diff --git a/Mage.Verify/pom.xml b/Mage.Verify/pom.xml
index e5fa977a770..c0cc0aae2b2 100644
--- a/Mage.Verify/pom.xml
+++ b/Mage.Verify/pom.xml
@@ -41,6 +41,17 @@
jar
+
+ org.reflections
+ reflections
+ 0.9.11
+
+
+ org.mage
+ mage-client
+ 1.4.29
+
+
diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java
index 79b88f1110e..fda71e4f3eb 100644
--- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java
+++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java
@@ -1,15 +1,25 @@
package mage.verify;
+import javassist.bytecode.SignatureAttribute;
import mage.ObjectColor;
import mage.cards.*;
import mage.cards.basiclands.BasicLand;
import mage.constants.CardType;
import mage.constants.Rarity;
import mage.constants.SuperType;
+import mage.game.permanent.token.Token;
+import mage.game.permanent.token.TokenImpl;
import org.junit.Assert;
+import org.junit.Ignore;
import org.junit.Test;
+import org.mage.plugins.card.images.CardDownloadData;
+import org.mage.plugins.card.images.DownloadPictures;
+import org.reflections.Reflections;
import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
@@ -19,6 +29,10 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
+/**
+ *
+ * @author JayDi85
+ */
public class VerifyCardDataTest {
// right now this is very noisy, and not useful enough to make any assertions on
@@ -241,6 +255,139 @@ public class VerifyCardDataTest {
}
}
+ private Object createNewObject(Class> clazz) {
+ try {
+ Constructor> cons = clazz.getConstructor();
+ return cons.newInstance();
+ } catch (InvocationTargetException ex) {
+ Throwable e = ex.getTargetException();
+ e.printStackTrace();
+ return null;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private void printMessages(Collection list) {
+ for (String mes : list) {
+ System.out.println(mes);
+ }
+ }
+
+ private String extractShortClass(Class extends TokenImpl> tokenClass) {
+ String origin = tokenClass.getName();
+ if (origin.contains("$")) {
+ // inner classes, example: mage.cards.f.FigureOfDestiny$FigureOfDestinyToken3
+ return origin.replaceAll(".+\\$(.+)", "$1");
+ } else {
+ // public classes, example: mage.game.permanent.token.FigureOfDestinyToken
+ return origin.replaceAll(".+\\.(.+)", "$1");
+ }
+ }
+
+ @Test
+ @Ignore // TODO: enable test after massive token fixes
+ public void checkMissingTokenData() {
+
+ Collection errorsList = new ArrayList<>();
+ Collection warningsList = new ArrayList<>();
+
+ // all tokens must be stores in card-pictures-tok.txt (if not then viewer and image downloader are missing token images)
+ // https://github.com/ronmamo/reflections
+ Reflections reflections = new Reflections("mage.");
+ Set> tokenClassesList = reflections.getSubTypesOf(TokenImpl.class);
+
+ // xmage tokens
+ Set> privateTokens = new HashSet<>();
+ Set> publicTokens = new HashSet<>();
+ for (Class extends TokenImpl> tokenClass : tokenClassesList) {
+ if (Modifier.isPublic(tokenClass.getModifiers())) {
+ publicTokens.add(tokenClass);
+ } else {
+ privateTokens.add(tokenClass);
+ }
+ }
+
+ // tok file's data
+ ArrayList tokFileTokens = DownloadPictures.getTokenCardUrls();
+ LinkedHashMap tokDataClassesIndex = new LinkedHashMap<>();
+ LinkedHashMap tokDataNamesIndex = new LinkedHashMap<>();
+ for (CardDownloadData tokData : tokFileTokens) {
+
+ String searchName;
+ String setsList;
+
+ // by class
+ searchName = tokData.getTokenClassName();
+ setsList = tokDataClassesIndex.getOrDefault(searchName, "");
+ if (!setsList.isEmpty()) {
+ setsList += ",";
+ }
+ setsList += tokData.getSet();
+ tokDataClassesIndex.put(searchName, setsList);
+
+ // by name
+ searchName = tokData.getName();
+ setsList = tokDataNamesIndex.getOrDefault(searchName, "");
+ if (!setsList.isEmpty()) {
+ setsList += ",";
+ }
+ setsList += tokData.getSet();
+ tokDataNamesIndex.put(searchName, setsList);
+ }
+
+ // 1. check token name convention
+ for (Class extends TokenImpl> tokenClass : tokenClassesList) {
+ if (!tokenClass.getName().endsWith("Token")) {
+ String className = extractShortClass(tokenClass);
+ warningsList.add("warning, token class must ends with Token: " + className + " from " + tokenClass.getName());
+ }
+ }
+
+ // 2. check store file for public
+ for (Class extends TokenImpl> tokenClass : publicTokens) {
+ String fullClass = tokenClass.getName();
+ if (!fullClass.startsWith("mage.game.permanent.token.")) {
+ String className = extractShortClass(tokenClass);
+ errorsList.add("error, public token must stores in mage.game.permanent.token package: " + className + " from " + tokenClass.getName());
+ }
+ }
+
+ // 3. check private tokens (they aren't need at all)
+ for (Class extends TokenImpl> tokenClass : privateTokens) {
+ String className = extractShortClass(tokenClass);
+ errorsList.add("error, no needs in private tokens, replace it with CreatureToken: " + className + " from " + tokenClass.getName());
+ }
+
+ // 4. all public tokens must have tok-data (private tokens uses for innner abilities -- no need images for it)
+ for (Class extends TokenImpl> tokenClass : publicTokens) {
+ String className = extractShortClass(tokenClass);
+ Token token = (Token) createNewObject(tokenClass);
+ //Assert.assertNotNull("Can't create token by default constructor", token);
+ if (token == null) {
+ Assert.fail("Can't create token by default constructor: " + className);
+ }
+
+ if (tokDataNamesIndex.getOrDefault(token.getName(), "").isEmpty()) {
+ errorsList.add("error, can't find data in card-pictures-tok.txt for token: " + tokenClass.getName() + " -> " + token.getName());
+ }
+ }
+
+ // TODO: all sets must have full tokens data in tok file (token in every set)
+ // 1. Download scryfall tokens list: https://api.scryfall.com/cards/search?q=t:token
+ // 2. Proccess each token with all prints: read "prints_search_uri" field from token data and go to link like
+ // https://api.scryfall.com/cards/search?order=set&q=%21%E2%80%9CAngel%E2%80%9D&unique=prints
+ // 3. Collect all strings in "set@name"
+ // 4. Proccess tokens data and find missing strings from "set@name" list
+
+ printMessages(warningsList);
+ printMessages(errorsList);
+ if(errorsList.size() > 0){
+ Assert.fail("Founded token errors: " + errorsList.size());
+ }
+ }
+
private static final Pattern SHORT_JAVA_STRING = Pattern.compile("(?<=\")[A-Z][a-z]+(?=\")");
private Set findSourceTokens(Class c) throws IOException {
diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java
index 377f649a94e..55c68421124 100644
--- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java
+++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java
@@ -42,24 +42,24 @@ import mage.game.permanent.token.Token;
public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements SourceEffect {
protected Token token;
- protected String type;
+ protected String theyAreStillType;
protected boolean losePreviousTypes;
protected DynamicValue power = null;
protected DynamicValue toughness = null;
- public BecomesCreatureSourceEffect(Token token, String type, Duration duration) {
- this(token, type, duration, false, false);
+ public BecomesCreatureSourceEffect(Token token, String theyAreStillType, Duration duration) {
+ this(token, theyAreStillType, duration, false, false);
}
- public BecomesCreatureSourceEffect(Token token, String type, Duration duration, boolean losePreviousTypes, boolean characterDefining) {
- this(token, type, duration, losePreviousTypes, characterDefining, null, null);
+ public BecomesCreatureSourceEffect(Token token, String theyAreStillType, Duration duration, boolean losePreviousTypes, boolean characterDefining) {
+ this(token, theyAreStillType, duration, losePreviousTypes, characterDefining, null, null);
}
- public BecomesCreatureSourceEffect(Token token, String type, Duration duration, boolean losePreviousTypes, boolean characterDefining, DynamicValue power, DynamicValue toughness) {
+ public BecomesCreatureSourceEffect(Token token, String theyAreStillType, Duration duration, boolean losePreviousTypes, boolean characterDefining, DynamicValue power, DynamicValue toughness) {
super(duration, Outcome.BecomeCreature);
this.characterDefining = characterDefining;
this.token = token;
- this.type = type;
+ this.theyAreStillType = theyAreStillType;
this.losePreviousTypes = losePreviousTypes;
this.power = power;
this.toughness = toughness;
@@ -69,7 +69,7 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
public BecomesCreatureSourceEffect(final BecomesCreatureSourceEffect effect) {
super(effect);
this.token = effect.token.copy();
- this.type = effect.type;
+ this.theyAreStillType = effect.theyAreStillType;
this.losePreviousTypes = effect.losePreviousTypes;
if (effect.power != null) {
this.power = effect.power.copy();
@@ -110,7 +110,7 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
for (CardType cardType : token.getCardType()) {
permanent.addCardType(cardType);
}
- if (type != null && type.isEmpty() || type == null && permanent.isLand()) {
+ if (theyAreStillType != null && theyAreStillType.isEmpty() || theyAreStillType == null && permanent.isLand()) {
permanent.getSubtype(game).retainAll(SubType.getLandTypes(false));
}
if (!token.getSubtype(game).isEmpty()) {
@@ -119,6 +119,7 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
permanent.setIsAllCreatureTypes(token.isAllCreatureTypes());
}
break;
+
case ColorChangingEffects_5:
if (sublayer == SubLayer.NA) {
if (token.getColor(game).hasColor()) {
@@ -126,19 +127,20 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
}
}
break;
+
case AbilityAddingRemovingEffects_6:
if (sublayer == SubLayer.NA) {
for (Ability ability : token.getAbilities()) {
permanent.addAbility(ability, source.getSourceId(), game);
}
-
}
break;
+
case PTChangingEffects_7:
if ((sublayer == SubLayer.CharacteristicDefining_7a && isCharacterDefining())
|| (sublayer == SubLayer.SetPT_7b && !isCharacterDefining())) {
if (power != null) {
- permanent.getPower().setValue(power.calculate(game, source, this));
+ permanent.getPower().setValue(power.calculate(game, source, this)); // check all other becomes to use calculate?
} else if (token.getPower() != null) {
permanent.getPower().setValue(token.getPower().getValue());
}
@@ -148,11 +150,15 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
permanent.getToughness().setValue(token.getToughness().getValue());
}
}
+ break;
}
+
return true;
+
} else if (duration == Duration.Custom) {
this.discard();
}
+
return false;
}
@@ -162,8 +168,8 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements
}
private void setText() {
- if (type != null && !type.isEmpty()) {
- staticText = duration.toString() + " {this} becomes a " + token.getDescription() + " that's still a " + this.type;
+ if (theyAreStillType != null && !theyAreStillType.isEmpty()) {
+ staticText = duration.toString() + " {this} becomes a " + token.getDescription() + " that's still a " + this.theyAreStillType;
} else {
staticText = duration.toString() + " {this} becomes a " + token.getDescription();
}