From 321f82a3810369751ae41c3c6e618fad6b2ea518 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Fri, 11 May 2018 21:58:45 +0400 Subject: [PATCH 1/2] Refactoring: replace custom creature tokens with basic class (9 cards) --- Mage.Sets/src/mage/cards/a/AngelsTomb.java | 36 +++++----------- .../src/mage/cards/a/AtarkaMonument.java | 37 +++++----------- .../src/mage/cards/a/AzoriusKeyrune.java | 33 +++++--------- .../src/mage/cards/b/BlinkmothNexus.java | 36 ++++++---------- Mage.Sets/src/mage/cards/b/BorosKeyrune.java | 34 +++++---------- .../src/mage/cards/c/CelestialColonnade.java | 43 +++++++------------ Mage.Sets/src/mage/cards/c/ChimericEgg.java | 33 ++++---------- Mage.Sets/src/mage/cards/c/ChimericIdol.java | 32 ++++---------- Mage.Sets/src/mage/cards/c/ChimericMass.java | 32 +++++--------- .../BecomesCreatureSourceEffect.java | 32 ++++++++------ 10 files changed, 116 insertions(+), 232 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/AngelsTomb.java b/Mage.Sets/src/mage/cards/a/AngelsTomb.java index 9cfa070e56..f3be463600 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 10f2d52ceb..6d35ee10a1 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 c294422812..6338b5cf6c 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 0a5aed5fed..ddb504a800 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 8cb37bd545..7d1a77dd83 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 982ba8a058..99b2a16486 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 6430539440..0630e258e3 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 9b4e6b0f79..b8db34d7b1 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 115efb1266..3c47fffbb3 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/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java index 377f649a94..55c6842112 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(); } From f0219515789918c07a853b0b3e8e844c129c68c2 Mon Sep 17 00:00:00 2001 From: Oleg Agafonov Date: Fri, 11 May 2018 22:22:02 +0400 Subject: [PATCH 2/2] Tests: added tokens tests in mage-verify (ignored until massive fixes, run it manually): * check token class name convention (must ends with Token); * check token package (must be in mage.game.permanent.token); * check private tokens (must be replaced with CreateToken); * check missing data from tok-file; --- Mage.Verify/pom.xml | 11 ++ .../java/mage/verify/VerifyCardDataTest.java | 147 ++++++++++++++++++ 2 files changed, 158 insertions(+) diff --git a/Mage.Verify/pom.xml b/Mage.Verify/pom.xml index e5fa977a77..c0cc0aae2b 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 79b88f1110..fda71e4f3e 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 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 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 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 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 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 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 {