Merge origin/master

This commit is contained in:
LevelX2 2018-05-13 22:52:40 +02:00
commit f30c0a7054
12 changed files with 274 additions and 232 deletions

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}

View file

@ -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. Its 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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -41,6 +41,17 @@
<type>jar</type>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.11</version>
</dependency>
<dependency>
<groupId>org.mage</groupId>
<artifactId>mage-client</artifactId>
<version>1.4.29</version>
</dependency>
</dependencies>
<build>

View file

@ -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<String> 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<String> errorsList = new ArrayList<>();
Collection<String> 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<Class<? extends TokenImpl>> tokenClassesList = reflections.getSubTypesOf(TokenImpl.class);
// xmage tokens
Set<Class<? extends TokenImpl>> privateTokens = new HashSet<>();
Set<Class<? extends TokenImpl>> 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<CardDownloadData> tokFileTokens = DownloadPictures.getTokenCardUrls();
LinkedHashMap<String, String> tokDataClassesIndex = new LinkedHashMap<>();
LinkedHashMap<String, String> 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<String> findSourceTokens(Class c) throws IOException {

View file

@ -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();
}