Merge pull request 'master' (#39) from External/mage:master into master
All checks were successful
/ build_release (push) Successful in 15m40s

Reviewed-on: #39
This commit is contained in:
Failure 2025-08-23 20:25:00 -07:00
commit 220763b685
68 changed files with 2739 additions and 235 deletions

View file

@ -0,0 +1,64 @@
package mage.cards.a;
import mage.abilities.condition.common.KickedCondition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.abilities.keyword.KickerAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.StaticFilters;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardAndOrCardInLibrary;
import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AangsJourney extends CardImpl {
private static final Predicate<Card> predicate = Predicates.and(
SuperType.BASIC.getPredicate(),
CardType.LAND.getPredicate()
);
public AangsJourney(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}");
this.subtype.add(SubType.LESSON);
// Kicker {2}
this.addAbility(new KickerAbility("{2}"));
// Search your library for a basic land card. If this spell was kicked, instead search your library for a basic land card and a Shrine card. Reveal those cards, put them into your hand, then shuffle.
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new SearchLibraryPutInHandEffect(new TargetCardAndOrCardInLibrary(
predicate, SubType.SHRINE.getPredicate(),
"a basic land card and/or a Shrine card"
), true),
new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true),
KickedCondition.ONCE, "search your library for a basic land card. If this spell was kicked, " +
"instead search your library for a basic land card and a Shrine card. " +
"Reveal those cards, put them into your hand, then shuffle"
));
// You gain 2 life.
this.getSpellAbility().addEffect(new GainLifeEffect(2).concatBy("<br>"));
}
private AangsJourney(final AangsJourney card) {
super(card);
}
@Override
public AangsJourney copy() {
return new AangsJourney(this);
}
}

View file

@ -57,6 +57,12 @@ class AlpineMoonEffect extends ContinuousEffectImpl {
this.staticText = "lands your opponents control with the chosen name " this.staticText = "lands your opponents control with the chosen name "
+ "lose all land types and abilities, " + "lose all land types and abilities, "
+ "and they gain \"{T}: Add one mana of any color.\""; + "and they gain \"{T}: Add one mana of any color.\"";
addDependedToType(DependencyType.BecomeMountain);
addDependedToType(DependencyType.BecomeForest);
addDependedToType(DependencyType.BecomeIsland);
addDependedToType(DependencyType.BecomeSwamp);
addDependedToType(DependencyType.BecomePlains);
addDependedToType(DependencyType.BecomeNonbasicLand);
} }
private AlpineMoonEffect(final AlpineMoonEffect effect) { private AlpineMoonEffect(final AlpineMoonEffect effect) {
@ -84,9 +90,6 @@ class AlpineMoonEffect extends ContinuousEffectImpl {
for (Permanent land : game.getBattlefield().getActivePermanents(filter2, source.getControllerId(), game)) { for (Permanent land : game.getBattlefield().getActivePermanents(filter2, source.getControllerId(), game)) {
switch (layer) { switch (layer) {
case TypeChangingEffects_4: case TypeChangingEffects_4:
// 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects
// So the ability removing has to be done before Layer 6
land.removeAllAbilities(source.getSourceId(), game);
land.removeAllSubTypes(game, SubTypeSet.NonBasicLandType); land.removeAllSubTypes(game, SubTypeSet.NonBasicLandType);
break; break;
case AbilityAddingRemovingEffects_6: case AbilityAddingRemovingEffects_6:

View file

@ -1,7 +1,6 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.MageObject; import mage.MageObject;
import mage.ObjectColor; import mage.ObjectColor;
@ -16,6 +15,8 @@ import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
* *
* @author fireshoes * @author fireshoes
@ -29,7 +30,7 @@ public final class AnHavvaConstable extends CardImpl {
this.toughness = new MageInt(1); this.toughness = new MageInt(1);
// An-Havva Constable's toughness is equal to 1 plus the number of green creatures on the battlefield. // An-Havva Constable's toughness is equal to 1 plus the number of green creatures on the battlefield.
this.addAbility(new SimpleStaticAbility(new AnHavvaConstableEffect())); this.addAbility(new SimpleStaticAbility(Zone.ALL, new AnHavvaConstableEffect()));
} }
private AnHavvaConstable(final AnHavvaConstable card) { private AnHavvaConstable(final AnHavvaConstable card) {
@ -72,7 +73,7 @@ class AnHavvaConstableEffect extends ContinuousEffectImpl {
FilterCreaturePermanent filter = new FilterCreaturePermanent("green creatures"); FilterCreaturePermanent filter = new FilterCreaturePermanent("green creatures");
filter.add(new ColorPredicate(ObjectColor.GREEN)); filter.add(new ColorPredicate(ObjectColor.GREEN));
int numberOfGreenCreatures = game.getBattlefield().count(filter, source.getSourceId(), source, game); int numberOfGreenCreatures = game.getBattlefield().count(filter, source.getControllerId(), source, game);
mageObject.getToughness().setModifiedBaseValue(1 + numberOfGreenCreatures); mageObject.getToughness().setModifiedBaseValue(1 + numberOfGreenCreatures);

View file

@ -62,8 +62,8 @@ class BottleCapBlastEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
UUID target = getTargetPointer().getFirst(game, source); UUID targetId = getTargetPointer().getFirst(game, source);
Player player = game.getPlayer(target); Player player = game.getPlayer(targetId);
if (player != null) { if (player != null) {
player.damage(5, source, game); player.damage(5, source, game);
return true; return true;
@ -72,11 +72,10 @@ class BottleCapBlastEffect extends OneShotEffect {
if (permanent == null) { if (permanent == null) {
return false; return false;
} }
int lethal = Math.min(permanent.getLethalDamage(source.getSourceId(), game), 5); int excess = permanent.damageWithExcess(5, source, game);
permanent.damage(5, source.getSourceId(), source, game); if (excess > 0) {
if (lethal < 5) {
new TreasureToken().putOntoBattlefield( new TreasureToken().putOntoBattlefield(
5 - lethal, game, source, source.getControllerId(), true, false excess, game, source, source.getControllerId(), true, false
); );
} }
return true; return true;

View file

@ -1,7 +1,5 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.keyword.DiscoverEffect; import mage.abilities.effects.keyword.DiscoverEffect;
@ -9,19 +7,18 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.filter.StaticFilters; import mage.game.Controllable;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.Target;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.Optional;
import java.util.UUID;
import static mage.filter.StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2; import static mage.filter.StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2;
/** /**
*
* @author jimga150 * @author jimga150
*/ */
public final class ContestOfClaws extends CardImpl { public final class ContestOfClaws extends CardImpl {
@ -29,14 +26,10 @@ public final class ContestOfClaws extends CardImpl {
public ContestOfClaws(UUID ownerId, CardSetInfo setInfo) { public ContestOfClaws(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}");
// Target creature you control deals damage equal to its power to another target creature. If excess damage was dealt this way, discover X, where X is that excess damage. // Target creature you control deals damage equal to its power to another target creature. If excess damage was dealt this way, discover X, where X is that excess damage.
this.getSpellAbility().addEffect(new ContestOfClawsDamageEffect()); this.getSpellAbility().addEffect(new ContestOfClawsDamageEffect());
Target target = new TargetControlledCreaturePermanent().setTargetTag(1); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(1));
this.getSpellAbility().addTarget(target); this.getSpellAbility().addTarget(new TargetPermanent(FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2));
Target target2 = new TargetPermanent(FILTER_ANOTHER_CREATURE_TARGET_2).setTargetTag(2);
this.getSpellAbility().addTarget(target2);
} }
private ContestOfClaws(final ContestOfClaws card) { private ContestOfClaws(final ContestOfClaws card) {
@ -74,22 +67,13 @@ class ContestOfClawsDamageEffect extends OneShotEffect {
if (ownCreature == null || targetCreature == null) { if (ownCreature == null || targetCreature == null) {
return false; return false;
} }
int damage = ownCreature.getPower().getValue(); int excess = targetCreature.damageWithExcess( ownCreature.getPower().getValue(), ownCreature.getId(), source, game);
int lethalDamage = targetCreature.getLethalDamage(source.getSourceId(), game); if (excess > 0) {
targetCreature.damage(damage, ownCreature.getId(), source, game, false, true); Optional.ofNullable(source)
.map(Controllable::getControllerId)
if (damage < lethalDamage){ .map(game::getPlayer)
return true; .ifPresent(player -> DiscoverEffect.doDiscover(player, excess, game, source));
} }
int discoverValue = damage - lethalDamage;
Player player = game.getPlayer(source.getControllerId());
if (player == null){
// If somehow this case is hit, the damage still technically happened, so i guess it applied?
return true;
}
DiscoverEffect.doDiscover(player, discoverValue, game, source);
return true; return true;
} }
} }

View file

@ -102,7 +102,7 @@ class DarkImpostorContinuousEffect extends ContinuousEffectImpl {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = source.getSourcePermanentIfItStillExists(game); Permanent permanent = source.getSourcePermanentIfItStillExists(game);
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source, 1));
if (permanent == null || exileZone == null || exileZone.isEmpty()) { if (permanent == null || exileZone == null || exileZone.isEmpty()) {
return false; return false;
} }

View file

@ -1,6 +1,5 @@
package mage.cards.d; package mage.cards.d;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
@ -16,14 +15,14 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterCreatureCard;
import mage.filter.common.FilterLandCard; import mage.filter.common.FilterLandCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetCardInGraveyard;
import java.util.UUID;
/** /**
* *
* @author LevelX2 * @author LevelX2

View file

@ -64,7 +64,7 @@ class EvraHalcyonWitnessEffect extends OneShotEffect {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
if (player != null && player.isLifeTotalCanChange()) { if (player != null && player.isLifeTotalCanChange()) {
Permanent perm = game.getPermanent(source.getSourceId()); Permanent perm = game.getPermanent(source.getSourceId());
if (perm != null) { if (perm != null && perm.isCreature(game)) {
int amount = perm.getPower().getValue(); int amount = perm.getPower().getValue();
int life = player.getLife(); int life = player.getLife();
if (life == amount) { if (life == amount) {

View file

@ -0,0 +1,158 @@
package mage.cards.f;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
import mage.abilities.keyword.FirebendingAbility;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard;
import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.card.OwnerIdPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInGraveyard;
import mage.util.CardUtil;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class FireLordSozin extends CardImpl {
public FireLordSozin(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.NOBLE);
this.power = new MageInt(5);
this.toughness = new MageInt(5);
this.color.setBlack(true);
this.nightCard = true;
// Menace
this.addAbility(new MenaceAbility());
// Firebending 3
this.addAbility(new FirebendingAbility(3));
// Whenever Fire Lord Sozin deals combat damage to a player, you may pay {X}. When you do, put any number of target creature cards with total mana value X or less from that player's graveyard onto the battlefield under your control.
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new FireLordSozinEffect()));
}
private FireLordSozin(final FireLordSozin card) {
super(card);
}
@Override
public FireLordSozin copy() {
return new FireLordSozin(this);
}
}
class FireLordSozinEffect extends OneShotEffect {
FireLordSozinEffect() {
super(Outcome.Benefit);
staticText = "you may pay {X}. When you do, put any number of target creature cards with " +
"total mana value X or less from that player's graveyard onto the battlefield under your control";
}
private FireLordSozinEffect(final FireLordSozinEffect effect) {
super(effect);
}
@Override
public FireLordSozinEffect copy() {
return new FireLordSozinEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
if (controller == null || !controller.chooseUse(Outcome.BoostCreature, "Pay {X}?", source, game)) {
return false;
}
int xValue = controller.announceX(0, Integer.MAX_VALUE, "Announce the value for {X}", game, source, true);
ManaCosts cost = new ManaCostsImpl<>("{X}");
cost.add(new GenericManaCost(xValue));
if (!cost.pay(source, game, source, source.getControllerId(), false, null)) {
return false;
}
ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false);
ability.addTarget(new FireLordSozinTarget((UUID) getValue("damagedPlayer"), xValue));
game.fireReflexiveTriggeredAbility(ability, source);
return true;
}
}
class FireLordSozinTarget extends TargetCardInGraveyard {
private final int xValue;
private static final FilterCard makeFilter(UUID ownerId, int xValue) {
FilterCard filter = new FilterCreatureCard("creature cards with total mana value " + xValue + " or less from that player's graveyard");
filter.add(new OwnerIdPredicate(ownerId));
return filter;
}
FireLordSozinTarget(UUID ownerId, int xValue) {
super(0, Integer.MAX_VALUE, makeFilter(ownerId, xValue), false);
this.xValue = xValue;
}
private FireLordSozinTarget(final FireLordSozinTarget target) {
super(target);
this.xValue = target.xValue;
}
@Override
public FireLordSozinTarget copy() {
return new FireLordSozinTarget(this);
}
@Override
public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) {
return super.canTarget(playerId, id, source, game)
&& CardUtil.checkCanTargetTotalValueLimit(this.getTargets(), id, MageObject::getManaValue, xValue, game);
}
@Override
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
return CardUtil.checkPossibleTargetsTotalValueLimit(
this.getTargets(),
super.possibleTargets(sourceControllerId, source, game),
MageObject::getManaValue, xValue, game
);
}
@Override
public String getMessage(Game game) {
// shows selected total
int selectedValue = this.getTargets().stream()
.map(game::getObject)
.filter(Objects::nonNull)
.mapToInt(MageObject::getManaValue)
.sum();
return super.getMessage(game) + " (selected total mana value " + selectedValue + ")";
}
}

View file

@ -15,7 +15,6 @@ import mage.util.CardUtil;
import java.util.UUID; import java.util.UUID;
/** /**
*
* @author ciaccona007 * @author ciaccona007
*/ */
public final class GoblinNegotiation extends CardImpl { public final class GoblinNegotiation extends CardImpl {
@ -62,13 +61,11 @@ class GoblinNegotiationEffect extends OneShotEffect {
if (permanent == null) { if (permanent == null) {
return false; return false;
} }
int damage = CardUtil.getSourceCostsTag(game, source, "X", 0); int excess = permanent.damageWithExcess(
int lethal = Math.min(permanent.getLethalDamage(source.getSourceId(), game), damage); CardUtil.getSourceCostsTag(game, source, "X", 0), source, game
permanent.damage(damage, source.getSourceId(), source, game); );
if (damage > lethal) { if (excess > 0) {
new GoblinToken().putOntoBattlefield( new GoblinToken().putOntoBattlefield(excess, game, source);
damage - lethal, game, source, source.getControllerId()
);
} }
return true; return true;
} }

View file

@ -0,0 +1,72 @@
package mage.cards.h;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect;
import mage.abilities.effects.common.continuous.PlayFromTopOfLibraryEffect;
import mage.abilities.keyword.IndestructibleAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class HakodaSelflessCommander extends CardImpl {
private static final FilterCard filter = new FilterCard(SubType.ALLY, "Ally spells");
public HakodaSelflessCommander(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.WARRIOR);
this.subtype.add(SubType.ALLY);
this.power = new MageInt(3);
this.toughness = new MageInt(5);
// Vigilance
this.addAbility(VigilanceAbility.getInstance());
// You may look at the top card of your library any time.
this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect()));
// You may cast Ally spells from the top of your library.
this.addAbility(new SimpleStaticAbility(new PlayFromTopOfLibraryEffect(filter)));
// Sacrifice Hakoda: Creatures you control get +0/+5 and gain indestructible until end of turn.
Ability ability = new SimpleActivatedAbility(
new BoostControlledEffect(0, 5, Duration.EndOfTurn)
.setText("creatures you control get +0/+5"),
new SacrificeSourceCost()
);
ability.addEffect(new GainAbilityAllEffect(
IndestructibleAbility.getInstance(), Duration.EndOfTurn,
StaticFilters.FILTER_CONTROLLED_CREATURE
).setText("and gain indestructible until end of turn"));
this.addAbility(ability);
}
private HakodaSelflessCommander(final HakodaSelflessCommander card) {
super(card);
}
@Override
public HakodaSelflessCommander copy() {
return new HakodaSelflessCommander(this);
}
}

View file

@ -9,6 +9,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.AnotherPredicate;
@ -29,6 +30,8 @@ public final class HaruHiddenTalent extends CardImpl {
public HaruHiddenTalent(UUID ownerId, CardSetInfo setInfo) { public HaruHiddenTalent(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.PEASANT); this.subtype.add(SubType.PEASANT);
this.subtype.add(SubType.ALLY); this.subtype.add(SubType.ALLY);

View file

@ -60,13 +60,11 @@ class HellToPayEffect extends OneShotEffect {
if (permanent == null) { if (permanent == null) {
return false; return false;
} }
int damage = CardUtil.getSourceCostsTag(game, source, "X", 0); int excess = permanent.damageWithExcess(
int lethal = Math.min(permanent.getLethalDamage(source.getSourceId(), game), damage); CardUtil.getSourceCostsTag(game, source, "X", 0), source, game
permanent.damage(damage, source.getSourceId(), source, game); );
if (damage > lethal) { if (excess > 0) {
new TreasureToken().putOntoBattlefield( new TreasureToken().putOntoBattlefield(excess, game, source, source.getControllerId(), true, false);
damage - lethal, game, source, source.getControllerId(), true, false
);
} }
return true; return true;
} }

View file

@ -0,0 +1,84 @@
package mage.cards.h;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.continuous.BoostAllEffect;
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
import mage.abilities.keyword.MenaceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetPlayer;
import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.SecondTargetPointer;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class HowToStartARiot extends CardImpl {
public HowToStartARiot(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}");
this.subtype.add(SubType.LESSON);
// Target creature gains menace until end of turn.
this.getSpellAbility().addEffect(new GainAbilityTargetEffect(new MenaceAbility(false)));
this.getSpellAbility().addTarget(new TargetCreaturePermanent());
// Creatures target player controls get +2/+0 until end of turn.
this.getSpellAbility().addEffect(new HowToStartARiotEffect());
this.getSpellAbility().addTarget(new TargetPlayer());
}
private HowToStartARiot(final HowToStartARiot card) {
super(card);
}
@Override
public HowToStartARiot copy() {
return new HowToStartARiot(this);
}
}
class HowToStartARiotEffect extends OneShotEffect {
HowToStartARiotEffect() {
super(Outcome.Benefit);
this.setTargetPointer(new SecondTargetPointer());
staticText = "creatures target player controls get +2/+0 until end of turn";
this.concatBy("<br>");
}
private HowToStartARiotEffect(final HowToStartARiotEffect effect) {
super(effect);
}
@Override
public HowToStartARiotEffect copy() {
return new HowToStartARiotEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player == null) {
return false;
}
FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(new ControllerIdPredicate(player.getId()));
game.addEffect(new BoostAllEffect(
2, 0, Duration.EndOfTurn, filter, false
), source);
return true;
}
}

View file

@ -55,14 +55,13 @@ class LacerateFleshEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget()); Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent == null) { if (permanent == null) {
return false; return false;
} }
int lethal = Math.min(permanent.getLethalDamage(source.getSourceId(), game), 4); int excess = permanent.damageWithExcess(4, source, game);
permanent.damage(4, source.getSourceId(), source, game); if (excess > 0) {
if (lethal < 4) { new BloodToken().putOntoBattlefield(excess, game, source);
new BloodToken().putOntoBattlefield(4 - lethal, game, source);
} }
return true; return true;
} }

View file

@ -0,0 +1,72 @@
package mage.cards.l;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility;
import mage.abilities.effects.common.counter.AddCountersTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.game.Game;
import mage.target.common.TargetControlledCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class LongFengGrandSecretariat extends CardImpl {
private static final FilterPermanent filter = new FilterControlledPermanent("another creature you control or a land you control");
static {
filter.add(LongFengGrandSecretariatPredicate.instance);
}
public LongFengGrandSecretariat(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B/G}{B/G}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.ADVISOR);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// Whenever another creature you control or a land you control is put into a graveyard from the battlefield, put a +1/+1 counter on target creature you control.
Ability ability = new PutIntoGraveFromBattlefieldAllTriggeredAbility(
new AddCountersTargetEffect(CounterType.P1P1.createInstance()),
false, filter, false
);
ability.addTarget(new TargetControlledCreaturePermanent());
this.addAbility(ability);
}
private LongFengGrandSecretariat(final LongFengGrandSecretariat card) {
super(card);
}
@Override
public LongFengGrandSecretariat copy() {
return new LongFengGrandSecretariat(this);
}
}
enum LongFengGrandSecretariatPredicate implements ObjectSourcePlayerPredicate<MageObject> {
instance;
@Override
public boolean apply(ObjectSourcePlayer<MageObject> input, Game game) {
return input.getObject().isLand(game)
|| input.getObject().isCreature(game)
&& AnotherPredicate.instance.apply(input, game);
}
}

View file

@ -79,7 +79,7 @@ class MegatronDestructiveForceEffect extends OneShotEffect {
return false; return false;
} }
TargetSacrifice target = new TargetSacrifice( TargetSacrifice target = new TargetSacrifice(
0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_ARTIFACT 0, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_ARTIFACT
); );
player.choose(outcome, target, source, game); player.choose(outcome, target, source, game);
Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent permanent = game.getPermanent(target.getFirstTarget());
@ -93,7 +93,7 @@ class MegatronDestructiveForceEffect extends OneShotEffect {
} }
ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(
new MegatronDestructiveForceReflexiveEffect(manaValue), false new MegatronDestructiveForceReflexiveEffect(manaValue), false
); );
ability.addHint(new StaticHint("Sacrificed artifact mana value: " + manaValue)); ability.addHint(new StaticHint("Sacrificed artifact mana value: " + manaValue));
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
@ -109,8 +109,8 @@ class MegatronDestructiveForceReflexiveEffect extends OneShotEffect {
MegatronDestructiveForceReflexiveEffect(int value) { MegatronDestructiveForceReflexiveEffect(int value) {
super(Outcome.Damage); super(Outcome.Damage);
staticText = "{this} deals damage equal to the sacrificed artifact's mana value to target " + staticText = "{this} deals damage equal to the sacrificed artifact's mana value to target " +
"creature. If excess damage would be dealt to that creature this way, instead that damage " + "creature. If excess damage would be dealt to that creature this way, instead that damage " +
"is dealt to that creature's controller and you convert {this}."; "is dealt to that creature's controller and you convert {this}.";
this.value = value; this.value = value;
} }
@ -126,36 +126,22 @@ class MegatronDestructiveForceReflexiveEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent sourcePermanent = source.getSourcePermanentOrLKI(game);
if (sourcePermanent == null) {
return false;
}
if (value < 1) { if (value < 1) {
return false; return false;
} }
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent == null) { if (permanent == null) {
return false; return false;
} }
int excess = permanent.damageWithExcess(value, source, game);
int lethal = permanent.getLethalDamage(source.getSourceId(), game); if (excess < 1) {
int excess = value - lethal;
if (excess <= 0) {
// no excess damage.
permanent.damage(value, source.getSourceId(), source, game);
return true; return true;
} }
// excess damage. dealing excess to controller's instead. And convert Megatron.
permanent.damage(lethal, source.getSourceId(), source, game);
Player player = game.getPlayer(permanent.getControllerId()); Player player = game.getPlayer(permanent.getControllerId());
if (player != null) { if (player != null) {
player.damage(excess, source, game); player.damage(excess, source, game);
} }
new TransformSourceEffect().apply(game, source); new TransformSourceEffect().apply(game, source);
return true; return true;
} }
} }

View file

@ -0,0 +1,132 @@
package mage.cards.m;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalCostModificationEffect;
import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect;
import mage.abilities.hint.ConditionHint;
import mage.abilities.hint.Hint;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.watchers.Watcher;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class MomoFriendlyFlier extends CardImpl {
private static final FilterCard filter = new FilterCard();
private static final FilterPermanent filter2 = new FilterControlledCreaturePermanent("another creature you control with flying");
static {
filter.add(Predicates.not(SubType.LEMUR.getPredicate()));
filter.add(new AbilityPredicate(FlyingAbility.class));
filter2.add(new AbilityPredicate(FlyingAbility.class));
}
public MomoFriendlyFlier(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.LEMUR);
this.subtype.add(SubType.BAT);
this.subtype.add(SubType.ALLY);
this.power = new MageInt(1);
this.toughness = new MageInt(1);
// Flying
this.addAbility(FlyingAbility.getInstance());
// The first non-Lemur creature spell with flying you cast during each of your turns costs {1} less to cast.
this.addAbility(new SimpleStaticAbility(new ConditionalCostModificationEffect(
new SpellsCostReductionControllerEffect(filter, 1), MomoFriendlyFlierCondition.instance,
"the first non-Lemur creature spell with flying you cast during each of your turns costs {1} less to cast"
)).addHint(MomoFriendlyFlierCondition.getHint()), new MomoFriendlyFlierWatcher());
// Whenever another creature you control with flying enters, Momo gets +1/+1 until end of turn.
this.addAbility(new EntersBattlefieldAllTriggeredAbility(
new BoostSourceEffect(1, 1, Duration.EndOfTurn), filter2
));
}
private MomoFriendlyFlier(final MomoFriendlyFlier card) {
super(card);
}
@Override
public MomoFriendlyFlier copy() {
return new MomoFriendlyFlier(this);
}
}
enum MomoFriendlyFlierCondition implements Condition {
instance;
private static final Hint hint = new ConditionHint(
instance, "You haven't cast a non-Lemur creature spell with flying during your turn yet"
);
public static Hint getHint() {
return hint;
}
@Override
public boolean apply(Game game, Ability source) {
return game.isActivePlayer(source.getControllerId())
&& !MomoFriendlyFlierWatcher.checkPlayer(game, source);
}
}
class MomoFriendlyFlierWatcher extends Watcher {
private final Set<UUID> set = new HashSet<>();
MomoFriendlyFlierWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() != GameEvent.EventType.SPELL_CAST) {
return;
}
Spell spell = game.getSpell(event.getTargetId());
if (spell != null
&& spell.isCreature(game)
&& !spell.hasSubtype(SubType.LEMUR, game)
&& spell.getAbilities(game).containsClass(FlyingAbility.class)) {
set.add(spell.getControllerId());
}
}
@Override
public void reset() {
super.reset();
set.clear();
}
static boolean checkPlayer(Game game, Ability source) {
return game
.getState()
.getWatcher(MomoFriendlyFlierWatcher.class)
.set
.contains(source.getControllerId());
}
}

View file

@ -80,9 +80,8 @@ class NahirisWarcraftingEffect extends OneShotEffect {
if (player == null || permanent == null) { if (player == null || permanent == null) {
return false; return false;
} }
int lethal = permanent.getLethalDamage(source.getSourceId(), game); int excess = permanent.damageWithExcess(5, source, game);
int excess = permanent.damage(5, source, game) - lethal; if (excess < 1) {
if (excess <= 0) {
return true; return true;
} }
Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, excess)); Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, excess));

View file

@ -2,7 +2,6 @@ package mage.cards.o;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateTokenEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
@ -61,10 +60,8 @@ class OrbitalPlungeEffect extends OneShotEffect {
if (permanent == null) { if (permanent == null) {
return false; return false;
} }
int lethal = permanent.getLethalDamage(source.getSourceId(), game); if (permanent.damageWithExcess(6, source, game) > 0) {
permanent.damage(6, source.getSourceId(), source, game); new LanderToken().putOntoBattlefield(1, game, source);
if (lethal < 6) {
new CreateTokenEffect(new LanderToken()).apply(game, source);
} }
return true; return true;
} }

View file

@ -7,15 +7,18 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.filter.StaticFilters; import mage.game.Controllable;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.EachTargetPointer;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL;
@ -47,6 +50,7 @@ class RamThroughEffect extends OneShotEffect {
RamThroughEffect() { RamThroughEffect() {
super(Outcome.Benefit); super(Outcome.Benefit);
this.setTargetPointer(new EachTargetPointer());
staticText = "Target creature you control deals damage equal to its power to target creature you don't control. " + staticText = "Target creature you control deals damage equal to its power to target creature you don't control. " +
"If the creature you control has trample, excess damage is dealt to that creature's controller instead."; "If the creature you control has trample, excess damage is dealt to that creature's controller instead.";
} }
@ -62,29 +66,31 @@ class RamThroughEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
if (source.getTargets().size() != 2) { List<Permanent> permanents = this
throw new IllegalStateException("It must have two targets, but found " + source.getTargets().size()); .getTargetPointer()
} .getTargets(game, source)
.stream()
Permanent myPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); .map(game::getPermanent)
Permanent anotherPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); .filter(Objects::nonNull)
.collect(Collectors.toList());
if (myPermanent == null || anotherPermanent == null) { if (permanents.size() < 2) {
return false; return false;
} }
int power = myPermanent.getPower().getValue(); Permanent permanent = permanents.get(0);
int power = permanent.getPower().getValue();
if (power < 1) { if (power < 1) {
return false; return false;
} }
if (!myPermanent.getAbilities().containsKey(TrampleAbility.getInstance().getId())) { Permanent creature = permanents.get(1);
return anotherPermanent.damage(power, myPermanent.getId(), source, game, false, true) > 0; if (!permanent.hasAbility(TrampleAbility.getInstance(), game)) {
return creature.damage(power, permanent.getId(), source, game) > 0;
} }
int lethal = anotherPermanent.getLethalDamage(myPermanent.getId(), game); int excess = creature.damageWithExcess(power, permanent.getId(), source, game);
lethal = Math.min(lethal, power); if (excess > 0) {
anotherPermanent.damage(lethal, myPermanent.getId(), source, game); Optional.ofNullable(creature)
Player player = game.getPlayer(anotherPermanent.getControllerId()); .map(Controllable::getControllerId)
if (player != null && lethal < power) { .map(game::getPlayer)
player.damage(power - lethal, myPermanent.getId(), source, game); .ifPresent(player -> player.damage(excess, permanent.getId(), source, game));
} }
return true; return true;
} }

View file

@ -0,0 +1,72 @@
package mage.cards.r;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.game.Controllable;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetAttackingOrBlockingCreature;
import java.util.Optional;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class RazorRings extends CardImpl {
public RazorRings(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}");
// Razor Rings deals 4 damage to target attacking or blocking creature. You gain life equal to the excess damage dealt this way.
this.getSpellAbility().addEffect(new RazorRingsEffect());
this.getSpellAbility().addTarget(new TargetAttackingOrBlockingCreature());
}
private RazorRings(final RazorRings card) {
super(card);
}
@Override
public RazorRings copy() {
return new RazorRings(this);
}
}
class RazorRingsEffect extends OneShotEffect {
RazorRingsEffect() {
super(Outcome.Benefit);
staticText = "{this} deals 4 damage to target attacking or blocking creature. " +
"You gain life equal to the excess damage dealt this way";
}
private RazorRingsEffect(final RazorRingsEffect effect) {
super(effect);
}
@Override
public RazorRingsEffect copy() {
return new RazorRingsEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent == null) {
return false;
}
int excess = permanent.damageWithExcess(4, source, game);
if (excess > 0) {
Optional.ofNullable(source)
.map(Controllable::getControllerId)
.map(game::getPlayer)
.ifPresent(player -> player.gainLife(excess, game, source));
}
return true;
}
}

View file

@ -129,7 +129,6 @@ class RexCyberhoundContinuousEffect extends ContinuousEffectImpl {
for (Ability ability : card.getAbilities(game)) { for (Ability ability : card.getAbilities(game)) {
if (ability.isActivatedAbility()) { if (ability.isActivatedAbility()) {
ActivatedAbility copyAbility = (ActivatedAbility) ability.copy(); ActivatedAbility copyAbility = (ActivatedAbility) ability.copy();
copyAbility.setMaxActivationsPerTurn(1);
perm.addAbility(copyAbility, source.getSourceId(), game, true); perm.addAbility(copyAbility, source.getSourceId(), game, true);
} }
} }

View file

@ -0,0 +1,71 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.CardsInControllerGraveyardCondition;
import mage.abilities.decorator.ConditionalAsThoughEffect;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount;
import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect;
import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicates;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class SerpentOfThePass extends CardImpl {
private static final Condition condition = new CardsInControllerGraveyardCondition(3, new FilterCard(SubType.LESSON));
private static final Hint hint = new ValueHint(
"Lesson cards in your graveyard", new CardsInControllerGraveyardCount(new FilterCard(SubType.LESSON))
);
private static final FilterCard filter = new FilterCard("noncreature, nonland card");
static {
filter.add(Predicates.not(CardType.CREATURE.getPredicate()));
filter.add(Predicates.not(CardType.LAND.getPredicate()));
}
private static final DynamicValue xValue = new CardsInControllerGraveyardCount(filter);
private static final Hint hint2 = new ValueHint("Noncreature, nonland cards in your graveyard", xValue);
public SerpentOfThePass(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}");
this.subtype.add(SubType.SERPENT);
this.power = new MageInt(6);
this.toughness = new MageInt(5);
// If there are three or more Lesson cards in your graveyard, you may cast this spell as though it had flash.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new ConditionalAsThoughEffect(
new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame), condition
).setText("if there are three or more Lesson cards in your graveyard, " +
"you may cast this spell as though it had flash.")).addHint(hint));
// This spell costs {1} less to cast for each noncreature, nonland card in your graveyard.
this.addAbility(new SimpleStaticAbility(
Zone.ALL, new SpellCostReductionForEachSourceEffect(1, xValue)
).setRuleAtTheTop(true).addHint(hint2));
}
private SerpentOfThePass(final SerpentOfThePass card) {
super(card);
}
@Override
public SerpentOfThePass copy() {
return new SerpentOfThePass(this);
}
}

View file

@ -0,0 +1,75 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class SokkaLateralStrategist extends CardImpl {
public SokkaLateralStrategist(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W/U}{W/U}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.WARRIOR);
this.subtype.add(SubType.ALLY);
this.power = new MageInt(2);
this.toughness = new MageInt(4);
// Vigilance
this.addAbility(VigilanceAbility.getInstance());
// Whenever Sokka and at least one other creature attack, draw a card.
this.addAbility(new SokkaLateralStrategistTriggeredAbility());
}
private SokkaLateralStrategist(final SokkaLateralStrategist card) {
super(card);
}
@Override
public SokkaLateralStrategist copy() {
return new SokkaLateralStrategist(this);
}
}
class SokkaLateralStrategistTriggeredAbility extends TriggeredAbilityImpl {
SokkaLateralStrategistTriggeredAbility() {
super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1));
this.setTriggerPhrase("Whenever {this} and at least one other creature attack, ");
}
private SokkaLateralStrategistTriggeredAbility(final SokkaLateralStrategistTriggeredAbility ability) {
super(ability);
}
@Override
public SokkaLateralStrategistTriggeredAbility copy() {
return new SokkaLateralStrategistTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
return game.getCombat().getAttackers().size() >= 2 && game.getCombat().getAttackers().contains(getSourceId());
}
}

View file

@ -1,33 +1,31 @@
package mage.cards.s; package mage.cards.s;
import mage.MageInt; import mage.MageInt;
import mage.abilities.keyword.FearAbility;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.ManaWasSpentCondition; import mage.abilities.condition.common.ManaWasSpentCondition;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.SacrificeSourceUnlessConditionEffect; import mage.abilities.effects.common.SacrificeSourceUnlessConditionEffect;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.keyword.FearAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/** /**
*
* @author TheElk801 * @author TheElk801
*/ */
public final class SquealingDevil extends CardImpl { public final class SquealingDevil extends CardImpl {
@ -76,24 +74,22 @@ class SquealingDevilEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
ManaCosts cost = new ManaCostsImpl<>("{X}"); if (player == null || !player.chooseUse(Outcome.BoostCreature, "Pay {X}?", source, game)) {
if (player != null) { return false;
if (player.chooseUse(Outcome.BoostCreature, "Pay " + cost.getText() + "?", source, game)) {
int costX = player.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to boost)", game, source, true);
cost.add(new GenericManaCost(costX));
if (cost.pay(source, game, source, source.getControllerId(), false, null)) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent != null && permanent.isCreature(game)) {
ContinuousEffect effect = new BoostTargetEffect(costX, 0, Duration.EndOfTurn);
effect.setTargetPointer(new FixedTarget(permanent, game));
game.addEffect(effect, source);
return true;
}
return false;
}
}
} }
return false; int xValue = player.announceX(0, Integer.MAX_VALUE, "Announce the value for {X} (pay to boost)", game, source, true);
ManaCosts cost = new ManaCostsImpl<>("{X}");
cost.add(new GenericManaCost(xValue));
if (!cost.pay(source, game, source, source.getControllerId(), false, null)) {
return false;
}
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent == null) {
return false;
}
game.addEffect(new BoostTargetEffect(xValue, 0, Duration.EndOfTurn)
.setTargetPointer(new FixedTarget(permanent, game)), source);
return true;
} }
@Override @Override

View file

@ -78,14 +78,19 @@ class StalwartSuccessorTriggeredAbility extends TriggeredAbilityImpl {
@Override @Override
public boolean checkTrigger(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) {
int zccOffset = 0;
Permanent permanent = game.getPermanent(event.getTargetId()); Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent == null) {
permanent = game.getPermanentEntering(event.getTargetId());
zccOffset = 1;
}
if (permanent == null if (permanent == null
|| !permanent.isCreature(game) || !permanent.isCreature(game)
|| !permanent.isControlledBy(getControllerId()) || !permanent.isControlledBy(getControllerId())
|| !StalwartSuccessorWatcher.checkCreature(permanent, event, game)) { || !StalwartSuccessorWatcher.checkCreature(permanent, event, game)) {
return false; return false;
} }
this.getEffects().setTargetPointer(new FixedTarget(permanent, game)); this.getEffects().setTargetPointer(new FixedTarget(permanent.getId(), permanent.getZoneChangeCounter(game) + zccOffset));
return true; return true;
} }
} }
@ -101,6 +106,11 @@ class StalwartSuccessorWatcher extends Watcher {
@Override @Override
public void watch(GameEvent event, Game game) { public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.COUNTERS_ADDED) { if (event.getType() == GameEvent.EventType.COUNTERS_ADDED) {
if (game.getPermanent(event.getTargetId()) == null) {
// permanent entering
Permanent permanent = game.getPermanentEntering(event.getTargetId());
map.putIfAbsent(new MageObjectReference(event.getTargetId(), permanent.getZoneChangeCounter(game) + 1, game), event.getId());
}
map.putIfAbsent(new MageObjectReference(event.getTargetId(), game), event.getId()); map.putIfAbsent(new MageObjectReference(event.getTargetId(), game), event.getId());
} }
} }

View file

@ -0,0 +1,85 @@
package mage.cards.t;
import mage.abilities.Ability;
import mage.abilities.common.SagaAbility;
import mage.abilities.effects.Effects;
import mage.abilities.effects.common.ChooseACardNameEffect;
import mage.abilities.effects.common.DestroyAllEffect;
import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect;
import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect;
import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SagaChapter;
import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class TheRiseOfSozin extends CardImpl {
public TheRiseOfSozin(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}{B}");
this.subtype.add(SubType.SAGA);
this.secondSideCardClazz = mage.cards.f.FireLordSozin.class;
// (As this Saga enters and after your draw step, add a lore counter.)
SagaAbility sagaAbility = new SagaAbility(this);
// I -- Destroy all creatures.
sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_I, new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_CREATURES)
);
// II -- Choose a card name. Search target opponent's graveyard, hand, and library for up to four cards with that name and exile them. Then that player shuffles.
sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_II,
new Effects(
new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.ALL), new TheRiseOfSozinEffect()
), new TargetOpponent()
);
// III -- Exile this Saga, then return it to the battlefield transformed under your control.
this.addAbility(new TransformAbility());
sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect());
this.addAbility(sagaAbility);
}
private TheRiseOfSozin(final TheRiseOfSozin card) {
super(card);
}
@Override
public TheRiseOfSozin copy() {
return new TheRiseOfSozin(this);
}
}
class TheRiseOfSozinEffect extends SearchTargetGraveyardHandLibraryForCardNameAndExileEffect {
TheRiseOfSozinEffect() {
super(true, "target opponent's", "up to four cards with that name", false, 4);
}
private TheRiseOfSozinEffect(final TheRiseOfSozinEffect effect) {
super(effect);
}
@Override
public TheRiseOfSozinEffect copy() {
return new TheRiseOfSozinEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
String chosenCardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY);
return applySearchAndExile(game, source, chosenCardName, getTargetPointer().getFirst(game, source));
}
}

View file

@ -60,8 +60,7 @@ class TorchTheWitnessEffect extends OneShotEffect {
if (permanent == null) { if (permanent == null) {
return false; return false;
} }
int lethal = permanent.getLethalDamage(source.getSourceId(), game); if (permanent.damageWithExcess(2 * CardUtil.getSourceCostsTag(game, source, "X", 0), source, game) > 0) {
if (lethal < permanent.damage(2 * CardUtil.getSourceCostsTag(game, source, "X", 0), source, game)) {
InvestigateEffect.doInvestigate(source.getControllerId(), 1, game, source); InvestigateEffect.doInvestigate(source.getControllerId(), 1, game, source);
} }
return true; return true;

View file

@ -63,7 +63,7 @@ class TreeOfPerditionEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player opponent = game.getPlayer(source.getFirstTarget()); Player opponent = game.getPlayer(source.getFirstTarget());
Permanent perm = game.getPermanent(source.getSourceId()); Permanent perm = game.getPermanent(source.getSourceId());
if (perm == null || opponent == null || !opponent.isLifeTotalCanChange()) { if (perm == null || opponent == null || !opponent.isLifeTotalCanChange() || !perm.isCreature(game)) {
return false; return false;
} }

View file

@ -59,7 +59,7 @@ class TreeOfRedemptionEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getControllerId());
Permanent perm = game.getPermanent(source.getSourceId()); Permanent perm = game.getPermanent(source.getSourceId());
if (perm == null || player == null || !player.isLifeTotalCanChange()) { if (perm == null || player == null || !player.isLifeTotalCanChange() || !perm.isCreature(game)) {
return false; return false;
} }

View file

@ -67,19 +67,18 @@ class UnleashTheInfernoEffect extends OneShotEffect {
if (permanent == null) { if (permanent == null) {
return false; return false;
} }
int lethal = Math.min(permanent.getLethalDamage(source.getSourceId(), game), 7); int excess = permanent.damageWithExcess(7, source, game);
permanent.damage(7, source, game); if (excess < 1) {
int excess = 7 - lethal; return true;
if (excess > 0) {
ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new DestroyTargetEffect(), false);
FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent(
"artifact or enchantment an opponent controls with mana value less than or equal to " + excess
);
filter.add(TargetController.OPPONENT.getControllerPredicate());
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, excess + 1));
ability.addTarget(new TargetPermanent(filter));
game.fireReflexiveTriggeredAbility(ability, source);
} }
ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility(new DestroyTargetEffect(), false);
FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent(
"artifact or enchantment an opponent controls with mana value less than or equal to " + excess
);
filter.add(TargetController.OPPONENT.getControllerPredicate());
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, excess + 1));
ability.addTarget(new TargetPermanent(filter));
game.fireReflexiveTriggeredAbility(ability, source);
return true; return true;
} }
} }

View file

@ -6,6 +6,9 @@ import mage.abilities.Ability;
import mage.abilities.common.PlayLandOrCastSpellTriggeredAbility; import mage.abilities.common.PlayLandOrCastSpellTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCost;
import mage.abilities.costs.mana.ManaCosts;
import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.GainLifeEffect;
@ -14,7 +17,6 @@ import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.game.Controllable;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
@ -142,14 +144,16 @@ class UriangerAugureltPlayEffect extends AsThoughEffectImpl {
if (card.isLand(game)) { if (card.isLand(game)) {
return true; return true;
} }
// TODO: This should ideally apply the reduction while the spell is being cast because effects that increase the cost apply first Player controller = game.getPlayer(source.getControllerId());
Optional.ofNullable(source) if (controller != null) {
.map(Controllable::getControllerId) ManaCosts<ManaCost> newCost = CardUtil.reduceCost(card.getManaCost(), 2);
.map(game::getPlayer) if (newCost.isEmpty()) {
.ifPresent(player -> player.setCastSourceIdWithAlternateMana( newCost.add(new GenericManaCost(0));
card.getId(), CardUtil.reduceCost(card.getManaCost(), 2), }
null, MageIdentifier.UriangerAugureltAlternateCast controller.setCastSourceIdWithAlternateMana(
)); card.getId(), newCost, null, MageIdentifier.UriangerAugureltAlternateCast
);
}
return true; return true;
} }
} }

View file

@ -14,11 +14,13 @@ import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.game.Controllable;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetAnyTarget; import mage.target.common.TargetAnyTarget;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
/** /**
@ -91,14 +93,11 @@ class VikyaScorchingStalwartEffect extends OneShotEffect {
if (!permanent.isCreature(game)) { if (!permanent.isCreature(game)) {
return permanent.damage(amount, source, game) > 0; return permanent.damage(amount, source, game) > 0;
} }
int lethal = permanent.getLethalDamage(source.getSourceId(), game); if (permanent.damageWithExcess(amount, source, game) > 0) {
permanent.damage(amount, source.getSourceId(), source, game); Optional.ofNullable(source)
if (lethal >= amount) { .map(Controllable::getControllerId)
return true; .map(game::getPlayer)
} .ifPresent(player -> player.drawCards(1, source, game));
Player player = game.getPlayer(source.getControllerId());
if (player != null) {
player.drawCards(1, source, game);
} }
return true; return true;
} }

View file

@ -1,25 +1,26 @@
package mage.cards.w; package mage.cards.w;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.token.ElfWarriorToken; import mage.game.permanent.token.ElfWarriorToken;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.EachTargetPointer;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL; import static mage.filter.StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL;
/** /**
*
* @author bwsinger * @author bwsinger
*/ */
public final class WindswiftSlice extends CardImpl { public final class WindswiftSlice extends CardImpl {
@ -48,6 +49,7 @@ class WindswiftSliceEffect extends OneShotEffect {
WindswiftSliceEffect() { WindswiftSliceEffect() {
super(Outcome.Benefit); super(Outcome.Benefit);
this.setTargetPointer(new EachTargetPointer());
staticText = "Target creature you control deals damage equal to its power to target " + staticText = "Target creature you control deals damage equal to its power to target " +
"creature you don't control. Create a number of 1/1 green Elf Warrior creature " + "creature you don't control. Create a number of 1/1 green Elf Warrior creature " +
"tokens equal to the amount of excess damage dealt this way."; "tokens equal to the amount of excess damage dealt this way.";
@ -64,27 +66,26 @@ class WindswiftSliceEffect extends OneShotEffect {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Permanent myPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); List<Permanent> permanents = this
Permanent anotherPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); .getTargetPointer()
.getTargets(game, source)
if (myPermanent == null || anotherPermanent == null) { .stream()
.map(game::getPermanent)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (permanents.size() < 2) {
return false; return false;
} }
Permanent permanent = permanents.get(0);
int power = myPermanent.getPower().getValue(); int power = permanent.getPower().getValue();
if (power < 1) { if (power < 1) {
return false; return false;
} }
Permanent creature = permanents.get(1);
int lethal = anotherPermanent.getLethalDamage(myPermanent.getId(), game); int excess = creature.damageWithExcess(power, permanent.getId(), source, game);
lethal = Math.min(lethal, power); if (excess > 0) {
new ElfWarriorToken().putOntoBattlefield(excess, game, source);
anotherPermanent.damage(power, myPermanent.getId(), source, game);
if (lethal < power) {
new ElfWarriorToken().putOntoBattlefield(power - lethal, game, source, source.getControllerId());
} }
return true; return true;
} }
} }

View file

@ -27,6 +27,7 @@ public final class AvatarTheLastAirbender extends ExpansionSet {
cards.add(new SetCardInfo("Aang's Iceberg", 336, Rarity.RARE, mage.cards.a.AangsIceberg.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang's Iceberg", 336, Rarity.RARE, mage.cards.a.AangsIceberg.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aang's Iceberg", 5, Rarity.RARE, mage.cards.a.AangsIceberg.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang's Iceberg", 5, Rarity.RARE, mage.cards.a.AangsIceberg.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aang's Journey", 1, Rarity.COMMON, mage.cards.a.AangsJourney.class));
cards.add(new SetCardInfo("Aang, Master of Elements", 207, Rarity.MYTHIC, mage.cards.a.AangMasterOfElements.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang, Master of Elements", 207, Rarity.MYTHIC, mage.cards.a.AangMasterOfElements.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aang, Master of Elements", 363, Rarity.MYTHIC, mage.cards.a.AangMasterOfElements.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Aang, Master of Elements", 363, Rarity.MYTHIC, mage.cards.a.AangMasterOfElements.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aang, the Last Airbender", 4, Rarity.UNCOMMON, mage.cards.a.AangTheLastAirbender.class)); cards.add(new SetCardInfo("Aang, the Last Airbender", 4, Rarity.UNCOMMON, mage.cards.a.AangTheLastAirbender.class));
@ -55,6 +56,8 @@ public final class AvatarTheLastAirbender extends ExpansionSet {
cards.add(new SetCardInfo("Epic Downfall", 96, Rarity.UNCOMMON, mage.cards.e.EpicDownfall.class)); cards.add(new SetCardInfo("Epic Downfall", 96, Rarity.UNCOMMON, mage.cards.e.EpicDownfall.class));
cards.add(new SetCardInfo("Fated Firepower", 132, Rarity.MYTHIC, mage.cards.f.FatedFirepower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fated Firepower", 132, Rarity.MYTHIC, mage.cards.f.FatedFirepower.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fated Firepower", 341, Rarity.MYTHIC, mage.cards.f.FatedFirepower.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fated Firepower", 341, Rarity.MYTHIC, mage.cards.f.FatedFirepower.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fire Lord Sozin", 117, Rarity.MYTHIC, mage.cards.f.FireLordSozin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fire Lord Sozin", 356, Rarity.MYTHIC, mage.cards.f.FireLordSozin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fire Lord Zuko", 221, Rarity.RARE, mage.cards.f.FireLordZuko.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fire Lord Zuko", 221, Rarity.RARE, mage.cards.f.FireLordZuko.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fire Lord Zuko", 360, Rarity.RARE, mage.cards.f.FireLordZuko.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fire Lord Zuko", 360, Rarity.RARE, mage.cards.f.FireLordZuko.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fire Nation Attacks", 133, Rarity.UNCOMMON, mage.cards.f.FireNationAttacks.class)); cards.add(new SetCardInfo("Fire Nation Attacks", 133, Rarity.UNCOMMON, mage.cards.f.FireNationAttacks.class));
@ -63,15 +66,19 @@ public final class AvatarTheLastAirbender extends ExpansionSet {
cards.add(new SetCardInfo("First-Time Flyer", 49, Rarity.COMMON, mage.cards.f.FirstTimeFlyer.class)); cards.add(new SetCardInfo("First-Time Flyer", 49, Rarity.COMMON, mage.cards.f.FirstTimeFlyer.class));
cards.add(new SetCardInfo("Flexible Waterbender", 50, Rarity.COMMON, mage.cards.f.FlexibleWaterbender.class)); cards.add(new SetCardInfo("Flexible Waterbender", 50, Rarity.COMMON, mage.cards.f.FlexibleWaterbender.class));
cards.add(new SetCardInfo("Flopsie, Bumi's Buddy", 179, Rarity.UNCOMMON, mage.cards.f.FlopsieBumisBuddy.class)); cards.add(new SetCardInfo("Flopsie, Bumi's Buddy", 179, Rarity.UNCOMMON, mage.cards.f.FlopsieBumisBuddy.class));
cards.add(new SetCardInfo("Forest", 286, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", 291, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Forest", 291, Rarity.LAND, mage.cards.basiclands.Forest.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Geyser Leaper", 52, Rarity.COMMON, mage.cards.g.GeyserLeaper.class)); cards.add(new SetCardInfo("Geyser Leaper", 52, Rarity.COMMON, mage.cards.g.GeyserLeaper.class));
cards.add(new SetCardInfo("Giant Koi", 53, Rarity.COMMON, mage.cards.g.GiantKoi.class)); cards.add(new SetCardInfo("Giant Koi", 53, Rarity.COMMON, mage.cards.g.GiantKoi.class));
cards.add(new SetCardInfo("Glider Kids", 21, Rarity.COMMON, mage.cards.g.GliderKids.class)); cards.add(new SetCardInfo("Glider Kids", 21, Rarity.COMMON, mage.cards.g.GliderKids.class));
cards.add(new SetCardInfo("Hakoda, Selfless Commander", 366, Rarity.RARE, mage.cards.h.HakodaSelflessCommander.class));
cards.add(new SetCardInfo("Haru, Hidden Talent", 182, Rarity.UNCOMMON, mage.cards.h.HaruHiddenTalent.class)); cards.add(new SetCardInfo("Haru, Hidden Talent", 182, Rarity.UNCOMMON, mage.cards.h.HaruHiddenTalent.class));
cards.add(new SetCardInfo("Heartless Act", 103, Rarity.UNCOMMON, mage.cards.h.HeartlessAct.class)); cards.add(new SetCardInfo("Heartless Act", 103, Rarity.UNCOMMON, mage.cards.h.HeartlessAct.class));
cards.add(new SetCardInfo("Hei Bai, Spirit of Balance", 225, Rarity.UNCOMMON, mage.cards.h.HeiBaiSpiritOfBalance.class)); cards.add(new SetCardInfo("Hei Bai, Spirit of Balance", 225, Rarity.UNCOMMON, mage.cards.h.HeiBaiSpiritOfBalance.class));
cards.add(new SetCardInfo("Hog-Monkey", 104, Rarity.COMMON, mage.cards.h.HogMonkey.class)); cards.add(new SetCardInfo("Hog-Monkey", 104, Rarity.COMMON, mage.cards.h.HogMonkey.class));
cards.add(new SetCardInfo("How to Start a Riot", 140, Rarity.COMMON, mage.cards.h.HowToStartARiot.class));
cards.add(new SetCardInfo("Iguana Parrot", 56, Rarity.COMMON, mage.cards.i.IguanaParrot.class)); cards.add(new SetCardInfo("Iguana Parrot", 56, Rarity.COMMON, mage.cards.i.IguanaParrot.class));
cards.add(new SetCardInfo("Island", 283, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", 288, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Island", 288, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("It'll Quench Ya!", 58, Rarity.COMMON, mage.cards.i.ItllQuenchYa.class)); cards.add(new SetCardInfo("It'll Quench Ya!", 58, Rarity.COMMON, mage.cards.i.ItllQuenchYa.class));
cards.add(new SetCardInfo("Jeong Jeong's Deserters", 25, Rarity.COMMON, mage.cards.j.JeongJeongsDeserters.class)); cards.add(new SetCardInfo("Jeong Jeong's Deserters", 25, Rarity.COMMON, mage.cards.j.JeongJeongsDeserters.class));
@ -82,20 +89,26 @@ public final class AvatarTheLastAirbender extends ExpansionSet {
cards.add(new SetCardInfo("Katara, the Fearless", 350, Rarity.RARE, mage.cards.k.KataraTheFearless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Katara, the Fearless", 350, Rarity.RARE, mage.cards.k.KataraTheFearless.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Katara, the Fearless", 361, Rarity.RARE, mage.cards.k.KataraTheFearless.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Katara, the Fearless", 361, Rarity.RARE, mage.cards.k.KataraTheFearless.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lightning Strike", 146, Rarity.COMMON, mage.cards.l.LightningStrike.class)); cards.add(new SetCardInfo("Lightning Strike", 146, Rarity.COMMON, mage.cards.l.LightningStrike.class));
cards.add(new SetCardInfo("Long Feng, Grand Secretariat", 233, Rarity.UNCOMMON, mage.cards.l.LongFengGrandSecretariat.class));
cards.add(new SetCardInfo("Master Pakku", 63, Rarity.UNCOMMON, mage.cards.m.MasterPakku.class)); cards.add(new SetCardInfo("Master Pakku", 63, Rarity.UNCOMMON, mage.cards.m.MasterPakku.class));
cards.add(new SetCardInfo("Master Piandao", 28, Rarity.UNCOMMON, mage.cards.m.MasterPiandao.class)); cards.add(new SetCardInfo("Master Piandao", 28, Rarity.UNCOMMON, mage.cards.m.MasterPiandao.class));
cards.add(new SetCardInfo("Merchant of Many Hats", 110, Rarity.COMMON, mage.cards.m.MerchantOfManyHats.class)); cards.add(new SetCardInfo("Merchant of Many Hats", 110, Rarity.COMMON, mage.cards.m.MerchantOfManyHats.class));
cards.add(new SetCardInfo("Momo, Friendly Flier", 29, Rarity.RARE, mage.cards.m.MomoFriendlyFlier.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Momo, Friendly Flier", 317, Rarity.RARE, mage.cards.m.MomoFriendlyFlier.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mongoose Lizard", 148, Rarity.COMMON, mage.cards.m.MongooseLizard.class)); cards.add(new SetCardInfo("Mongoose Lizard", 148, Rarity.COMMON, mage.cards.m.MongooseLizard.class));
cards.add(new SetCardInfo("Mountain", 285, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 290, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Mountain", 290, Rarity.LAND, mage.cards.basiclands.Mountain.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Ostrich-Horse", 188, Rarity.COMMON, mage.cards.o.OstrichHorse.class)); cards.add(new SetCardInfo("Ostrich-Horse", 188, Rarity.COMMON, mage.cards.o.OstrichHorse.class));
cards.add(new SetCardInfo("Otter-Penguin", 67, Rarity.COMMON, mage.cards.o.OtterPenguin.class)); cards.add(new SetCardInfo("Otter-Penguin", 67, Rarity.COMMON, mage.cards.o.OtterPenguin.class));
cards.add(new SetCardInfo("Ozai's Cruelty", 113, Rarity.UNCOMMON, mage.cards.o.OzaisCruelty.class)); cards.add(new SetCardInfo("Ozai's Cruelty", 113, Rarity.UNCOMMON, mage.cards.o.OzaisCruelty.class));
cards.add(new SetCardInfo("Path to Redemption", 31, Rarity.COMMON, mage.cards.p.PathToRedemption.class)); cards.add(new SetCardInfo("Path to Redemption", 31, Rarity.COMMON, mage.cards.p.PathToRedemption.class));
cards.add(new SetCardInfo("Pillar Launch", 189, Rarity.COMMON, mage.cards.p.PillarLaunch.class)); cards.add(new SetCardInfo("Pillar Launch", 189, Rarity.COMMON, mage.cards.p.PillarLaunch.class));
cards.add(new SetCardInfo("Plains", 282, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 287, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Plains", 287, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Pretending Poxbearers", 237, Rarity.COMMON, mage.cards.p.PretendingPoxbearers.class)); cards.add(new SetCardInfo("Pretending Poxbearers", 237, Rarity.COMMON, mage.cards.p.PretendingPoxbearers.class));
cards.add(new SetCardInfo("Rabaroo Troop", 32, Rarity.COMMON, mage.cards.r.RabarooTroop.class)); cards.add(new SetCardInfo("Rabaroo Troop", 32, Rarity.COMMON, mage.cards.r.RabarooTroop.class));
cards.add(new SetCardInfo("Raucous Audience", 190, Rarity.COMMON, mage.cards.r.RaucousAudience.class)); cards.add(new SetCardInfo("Raucous Audience", 190, Rarity.COMMON, mage.cards.r.RaucousAudience.class));
cards.add(new SetCardInfo("Razor Rings", 33, Rarity.COMMON, mage.cards.r.RazorRings.class));
cards.add(new SetCardInfo("Rebellious Captives", 191, Rarity.COMMON, mage.cards.r.RebelliousCaptives.class)); cards.add(new SetCardInfo("Rebellious Captives", 191, Rarity.COMMON, mage.cards.r.RebelliousCaptives.class));
cards.add(new SetCardInfo("Redirect Lightning", 151, Rarity.RARE, mage.cards.r.RedirectLightning.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Redirect Lightning", 151, Rarity.RARE, mage.cards.r.RedirectLightning.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Redirect Lightning", 343, Rarity.RARE, mage.cards.r.RedirectLightning.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Redirect Lightning", 343, Rarity.RARE, mage.cards.r.RedirectLightning.class, NON_FULL_USE_VARIOUS));
@ -103,12 +116,17 @@ public final class AvatarTheLastAirbender extends ExpansionSet {
cards.add(new SetCardInfo("Rough Rhino Cavalry", 152, Rarity.COMMON, mage.cards.r.RoughRhinoCavalry.class)); cards.add(new SetCardInfo("Rough Rhino Cavalry", 152, Rarity.COMMON, mage.cards.r.RoughRhinoCavalry.class));
cards.add(new SetCardInfo("Rowdy Snowballers", 68, Rarity.COMMON, mage.cards.r.RowdySnowballers.class)); cards.add(new SetCardInfo("Rowdy Snowballers", 68, Rarity.COMMON, mage.cards.r.RowdySnowballers.class));
cards.add(new SetCardInfo("Saber-Tooth Moose-Lion", 194, Rarity.COMMON, mage.cards.s.SaberToothMooseLion.class)); cards.add(new SetCardInfo("Saber-Tooth Moose-Lion", 194, Rarity.COMMON, mage.cards.s.SaberToothMooseLion.class));
cards.add(new SetCardInfo("Serpent of the Pass", 70, Rarity.UNCOMMON, mage.cards.s.SerpentOfThePass.class));
cards.add(new SetCardInfo("Sokka's Haiku", 71, Rarity.UNCOMMON, mage.cards.s.SokkasHaiku.class)); cards.add(new SetCardInfo("Sokka's Haiku", 71, Rarity.UNCOMMON, mage.cards.s.SokkasHaiku.class));
cards.add(new SetCardInfo("Sokka, Bold Boomeranger", 240, Rarity.RARE, mage.cards.s.SokkaBoldBoomeranger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sokka, Bold Boomeranger", 240, Rarity.RARE, mage.cards.s.SokkaBoldBoomeranger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sokka, Bold Boomeranger", 383, Rarity.RARE, mage.cards.s.SokkaBoldBoomeranger.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sokka, Bold Boomeranger", 383, Rarity.RARE, mage.cards.s.SokkaBoldBoomeranger.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sokka, Lateral Strategist", 241, Rarity.UNCOMMON, mage.cards.s.SokkaLateralStrategist.class));
cards.add(new SetCardInfo("Southern Air Temple", 36, Rarity.UNCOMMON, mage.cards.s.SouthernAirTemple.class)); cards.add(new SetCardInfo("Southern Air Temple", 36, Rarity.UNCOMMON, mage.cards.s.SouthernAirTemple.class));
cards.add(new SetCardInfo("Suki, Kyoshi Warrior", 243, Rarity.UNCOMMON, mage.cards.s.SukiKyoshiWarrior.class)); cards.add(new SetCardInfo("Suki, Kyoshi Warrior", 243, Rarity.UNCOMMON, mage.cards.s.SukiKyoshiWarrior.class));
cards.add(new SetCardInfo("Swamp", 284, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", 289, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Swamp", 289, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("The Rise of Sozin", 117, Rarity.MYTHIC, mage.cards.t.TheRiseOfSozin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Rise of Sozin", 356, Rarity.MYTHIC, mage.cards.t.TheRiseOfSozin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Toph, the Blind Bandit", 198, Rarity.UNCOMMON, mage.cards.t.TophTheBlindBandit.class)); cards.add(new SetCardInfo("Toph, the Blind Bandit", 198, Rarity.UNCOMMON, mage.cards.t.TophTheBlindBandit.class));
cards.add(new SetCardInfo("Toph, the First Metalbender", 247, Rarity.RARE, mage.cards.t.TophTheFirstMetalbender.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Toph, the First Metalbender", 247, Rarity.RARE, mage.cards.t.TophTheFirstMetalbender.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Toph, the First Metalbender", 353, Rarity.RARE, mage.cards.t.TophTheFirstMetalbender.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Toph, the First Metalbender", 353, Rarity.RARE, mage.cards.t.TophTheFirstMetalbender.class, NON_FULL_USE_VARIOUS));

View file

@ -24,51 +24,85 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet {
super("Avatar: The Last Airbender Eternal", "TLE", ExpansionSet.buildDate(2025, 11, 21), SetType.SUPPLEMENTAL); super("Avatar: The Last Airbender Eternal", "TLE", ExpansionSet.buildDate(2025, 11, 21), SetType.SUPPLEMENTAL);
this.blockName = "Avatar: The Last Airbender"; // for sorting in GUI this.blockName = "Avatar: The Last Airbender"; // for sorting in GUI
this.rotationSet = true; this.rotationSet = true;
this.hasBasicLands = false; this.hasBasicLands = true;
cards.add(new SetCardInfo("Aang's Defense", 211, Rarity.COMMON, mage.cards.a.AangsDefense.class)); cards.add(new SetCardInfo("Aang's Defense", 211, Rarity.COMMON, mage.cards.a.AangsDefense.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aang, Air Nomad", 210, Rarity.RARE, mage.cards.a.AangAirNomad.class)); cards.add(new SetCardInfo("Aang's Defense", 266, Rarity.COMMON, mage.cards.a.AangsDefense.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aang, Air Nomad", 210, Rarity.RARE, mage.cards.a.AangAirNomad.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aang, Air Nomad", 265, Rarity.RARE, mage.cards.a.AangAirNomad.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aang, Airbending Master", 74, Rarity.MYTHIC, mage.cards.a.AangAirbendingMaster.class)); cards.add(new SetCardInfo("Aang, Airbending Master", 74, Rarity.MYTHIC, mage.cards.a.AangAirbendingMaster.class));
cards.add(new SetCardInfo("Aardvark Sloth", 212, Rarity.COMMON, mage.cards.a.AardvarkSloth.class)); cards.add(new SetCardInfo("Aardvark Sloth", 212, Rarity.COMMON, mage.cards.a.AardvarkSloth.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aardvark Sloth", 267, Rarity.COMMON, mage.cards.a.AardvarkSloth.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Allied Teamwork", 213, Rarity.RARE, mage.cards.a.AlliedTeamwork.class)); cards.add(new SetCardInfo("Allied Teamwork", 213, Rarity.RARE, mage.cards.a.AlliedTeamwork.class));
cards.add(new SetCardInfo("Appa, Aang's Companion", 214, Rarity.UNCOMMON, mage.cards.a.AppaAangsCompanion.class)); cards.add(new SetCardInfo("Appa, Aang's Companion", 214, Rarity.UNCOMMON, mage.cards.a.AppaAangsCompanion.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Appa, Aang's Companion", 268, Rarity.UNCOMMON, mage.cards.a.AppaAangsCompanion.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Bumi, Eclectic Earthbender", 248, Rarity.RARE, mage.cards.b.BumiEclecticEarthbender.class)); cards.add(new SetCardInfo("Bumi, Eclectic Earthbender", 248, Rarity.RARE, mage.cards.b.BumiEclecticEarthbender.class));
cards.add(new SetCardInfo("Capital Guard", 234, Rarity.COMMON, mage.cards.c.CapitalGuard.class)); cards.add(new SetCardInfo("Capital Guard", 234, Rarity.COMMON, mage.cards.c.CapitalGuard.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Capital Guard", 277, Rarity.COMMON, mage.cards.c.CapitalGuard.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Deny Entry", 222, Rarity.COMMON, mage.cards.d.DenyEntry.class)); cards.add(new SetCardInfo("Deny Entry", 222, Rarity.COMMON, mage.cards.d.DenyEntry.class));
cards.add(new SetCardInfo("Dragon Moose", 235, Rarity.COMMON, mage.cards.d.DragonMoose.class)); cards.add(new SetCardInfo("Dragon Moose", 235, Rarity.COMMON, mage.cards.d.DragonMoose.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Dragon Moose", 278, Rarity.COMMON, mage.cards.d.DragonMoose.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Earthbending Student", 249, Rarity.UNCOMMON, mage.cards.e.EarthbendingStudent.class)); cards.add(new SetCardInfo("Earthbending Student", 249, Rarity.UNCOMMON, mage.cards.e.EarthbendingStudent.class));
cards.add(new SetCardInfo("Eel-Hounds", 250, Rarity.UNCOMMON, mage.cards.e.EelHounds.class)); cards.add(new SetCardInfo("Eel-Hounds", 250, Rarity.UNCOMMON, mage.cards.e.EelHounds.class));
cards.add(new SetCardInfo("Elephant-Rat", 228, Rarity.COMMON, mage.cards.e.ElephantRat.class)); cards.add(new SetCardInfo("Elephant-Rat", 228, Rarity.COMMON, mage.cards.e.ElephantRat.class));
cards.add(new SetCardInfo("Explore", 259, Rarity.COMMON, mage.cards.e.Explore.class)); cards.add(new SetCardInfo("Explore", 259, Rarity.COMMON, mage.cards.e.Explore.class));
cards.add(new SetCardInfo("Explosive Shot", 236, Rarity.COMMON, mage.cards.e.ExplosiveShot.class)); cards.add(new SetCardInfo("Explosive Shot", 236, Rarity.COMMON, mage.cards.e.ExplosiveShot.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Explosive Shot", 279, Rarity.COMMON, mage.cards.e.ExplosiveShot.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Feed the Swarm", 257, Rarity.COMMON, mage.cards.f.FeedTheSwarm.class)); cards.add(new SetCardInfo("Feed the Swarm", 257, Rarity.COMMON, mage.cards.f.FeedTheSwarm.class));
cards.add(new SetCardInfo("Fire Nation Ambushers", 229, Rarity.COMMON, mage.cards.f.FireNationAmbushers.class)); cards.add(new SetCardInfo("Fire Nation Ambushers", 229, Rarity.COMMON, mage.cards.f.FireNationAmbushers.class));
cards.add(new SetCardInfo("Fire Nation Archers", 237, Rarity.RARE, mage.cards.f.FireNationArchers.class)); cards.add(new SetCardInfo("Fire Nation Archers", 237, Rarity.RARE, mage.cards.f.FireNationArchers.class));
cards.add(new SetCardInfo("Fire Nation Sentinels", 230, Rarity.RARE, mage.cards.f.FireNationSentinels.class)); cards.add(new SetCardInfo("Fire Nation Sentinels", 230, Rarity.RARE, mage.cards.f.FireNationSentinels.class));
cards.add(new SetCardInfo("Fire Nation Soldier", 238, Rarity.COMMON, mage.cards.f.FireNationSoldier.class)); cards.add(new SetCardInfo("Fire Nation Soldier", 238, Rarity.COMMON, mage.cards.f.FireNationSoldier.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fire Nation's Conquest", 239, Rarity.UNCOMMON, mage.cards.f.FireNationsConquest.class)); cards.add(new SetCardInfo("Fire Nation Soldier", 280, Rarity.COMMON, mage.cards.f.FireNationSoldier.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fire Nation's Conquest", 239, Rarity.UNCOMMON, mage.cards.f.FireNationsConquest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Fire Nation's Conquest", 281, Rarity.UNCOMMON, mage.cards.f.FireNationsConquest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Flying Dolphin-Fish", 223, Rarity.COMMON, mage.cards.f.FlyingDolphinFish.class)); cards.add(new SetCardInfo("Flying Dolphin-Fish", 223, Rarity.COMMON, mage.cards.f.FlyingDolphinFish.class));
cards.add(new SetCardInfo("Force of Negation", 13, Rarity.MYTHIC, mage.cards.f.ForceOfNegation.class)); cards.add(new SetCardInfo("Force of Negation", 13, Rarity.MYTHIC, mage.cards.f.ForceOfNegation.class));
cards.add(new SetCardInfo("Frog-Squirrels", 251, Rarity.COMMON, mage.cards.f.FrogSquirrels.class)); cards.add(new SetCardInfo("Frog-Squirrels", 251, Rarity.COMMON, mage.cards.f.FrogSquirrels.class));
cards.add(new SetCardInfo("Gilacorn", 231, Rarity.COMMON, mage.cards.g.Gilacorn.class)); cards.add(new SetCardInfo("Gilacorn", 231, Rarity.COMMON, mage.cards.g.Gilacorn.class));
cards.add(new SetCardInfo("Hippo-Cows", 252, Rarity.COMMON, mage.cards.h.HippoCows.class)); cards.add(new SetCardInfo("Hippo-Cows", 252, Rarity.COMMON, mage.cards.h.HippoCows.class));
cards.add(new SetCardInfo("Iroh, Firebending Instructor", 240, Rarity.UNCOMMON, mage.cards.i.IrohFirebendingInstructor.class)); cards.add(new SetCardInfo("Iroh, Firebending Instructor", 240, Rarity.UNCOMMON, mage.cards.i.IrohFirebendingInstructor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Katara, Heroic Healer", 215, Rarity.UNCOMMON, mage.cards.k.KataraHeroicHealer.class)); cards.add(new SetCardInfo("Iroh, Firebending Instructor", 282, Rarity.UNCOMMON, mage.cards.i.IrohFirebendingInstructor.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Katara, Heroic Healer", 215, Rarity.UNCOMMON, mage.cards.k.KataraHeroicHealer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Katara, Heroic Healer", 269, Rarity.UNCOMMON, mage.cards.k.KataraHeroicHealer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Katara, Waterbending Master", 93, Rarity.MYTHIC, mage.cards.k.KataraWaterbendingMaster.class)); cards.add(new SetCardInfo("Katara, Waterbending Master", 93, Rarity.MYTHIC, mage.cards.k.KataraWaterbendingMaster.class));
cards.add(new SetCardInfo("Komodo Rhino", 241, Rarity.COMMON, mage.cards.k.KomodoRhino.class)); cards.add(new SetCardInfo("Komodo Rhino", 241, Rarity.COMMON, mage.cards.k.KomodoRhino.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Komodo Rhino", 283, Rarity.COMMON, mage.cards.k.KomodoRhino.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kyoshi Warrior Guard", 216, Rarity.COMMON, mage.cards.k.KyoshiWarriorGuard.class)); cards.add(new SetCardInfo("Kyoshi Warrior Guard", 216, Rarity.COMMON, mage.cards.k.KyoshiWarriorGuard.class));
cards.add(new SetCardInfo("Lion Vulture", 232, Rarity.RARE, mage.cards.l.LionVulture.class)); cards.add(new SetCardInfo("Lion Vulture", 232, Rarity.RARE, mage.cards.l.LionVulture.class));
cards.add(new SetCardInfo("Lost in the Spirit World", 224, Rarity.UNCOMMON, mage.cards.l.LostInTheSpiritWorld.class)); cards.add(new SetCardInfo("Lost in the Spirit World", 224, Rarity.UNCOMMON, mage.cards.l.LostInTheSpiritWorld.class));
cards.add(new SetCardInfo("Loyal Fire Sage", 242, Rarity.UNCOMMON, mage.cards.l.LoyalFireSage.class)); cards.add(new SetCardInfo("Loyal Fire Sage", 242, Rarity.UNCOMMON, mage.cards.l.LoyalFireSage.class));
cards.add(new SetCardInfo("Match the Odds", 253, Rarity.UNCOMMON, mage.cards.m.MatchTheOdds.class)); cards.add(new SetCardInfo("Match the Odds", 253, Rarity.UNCOMMON, mage.cards.m.MatchTheOdds.class));
cards.add(new SetCardInfo("Mechanical Glider", 256, Rarity.COMMON, mage.cards.m.MechanicalGlider.class)); cards.add(new SetCardInfo("Mechanical Glider", 256, Rarity.COMMON, mage.cards.m.MechanicalGlider.class));
cards.add(new SetCardInfo("Momo, Rambunctious Rascal", 217, Rarity.UNCOMMON, mage.cards.m.MomoRambunctiousRascal.class)); cards.add(new SetCardInfo("Momo, Rambunctious Rascal", 217, Rarity.UNCOMMON, mage.cards.m.MomoRambunctiousRascal.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Momo, Rambunctious Rascal", 270, Rarity.UNCOMMON, mage.cards.m.MomoRambunctiousRascal.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 289, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 290, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 291, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 292, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 293, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 294, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 295, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 296, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Path to Redemption", 271, Rarity.COMMON, mage.cards.p.PathToRedemption.class));
cards.add(new SetCardInfo("Plains", 297, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 298, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 299, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 300, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 301, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 302, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 303, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 304, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Purple Pentapus", 233, Rarity.COMMON, mage.cards.p.PurplePentapus.class)); cards.add(new SetCardInfo("Purple Pentapus", 233, Rarity.COMMON, mage.cards.p.PurplePentapus.class));
cards.add(new SetCardInfo("Razor Rings", 272, Rarity.COMMON, mage.cards.r.RazorRings.class));
cards.add(new SetCardInfo("Roku's Mastery", 243, Rarity.UNCOMMON, mage.cards.r.RokusMastery.class)); cards.add(new SetCardInfo("Roku's Mastery", 243, Rarity.UNCOMMON, mage.cards.r.RokusMastery.class));
cards.add(new SetCardInfo("Run Amok", 258, Rarity.COMMON, mage.cards.r.RunAmok.class)); cards.add(new SetCardInfo("Run Amok", 258, Rarity.COMMON, mage.cards.r.RunAmok.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Run Amok", 284, Rarity.COMMON, mage.cards.r.RunAmok.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Seismic Tutelage", 254, Rarity.RARE, mage.cards.s.SeismicTutelage.class)); cards.add(new SetCardInfo("Seismic Tutelage", 254, Rarity.RARE, mage.cards.s.SeismicTutelage.class));
cards.add(new SetCardInfo("Sledding Otter-Penguin", 218, Rarity.COMMON, mage.cards.s.SleddingOtterPenguin.class)); cards.add(new SetCardInfo("Sledding Otter-Penguin", 218, Rarity.COMMON, mage.cards.s.SleddingOtterPenguin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sokka, Wolf Cove's Protector", 219, Rarity.UNCOMMON, mage.cards.s.SokkaWolfCovesProtector.class)); cards.add(new SetCardInfo("Sledding Otter-Penguin", 273, Rarity.COMMON, mage.cards.s.SleddingOtterPenguin.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sokka, Wolf Cove's Protector", 219, Rarity.UNCOMMON, mage.cards.s.SokkaWolfCovesProtector.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sokka, Wolf Cove's Protector", 274, Rarity.UNCOMMON, mage.cards.s.SokkaWolfCovesProtector.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("The Cabbage Merchant", 134, Rarity.RARE, mage.cards.t.TheCabbageMerchant.class)); cards.add(new SetCardInfo("The Cabbage Merchant", 134, Rarity.RARE, mage.cards.t.TheCabbageMerchant.class));
cards.add(new SetCardInfo("The Great Henge", 41, Rarity.MYTHIC, mage.cards.t.TheGreatHenge.class)); cards.add(new SetCardInfo("The Great Henge", 41, Rarity.MYTHIC, mage.cards.t.TheGreatHenge.class));
cards.add(new SetCardInfo("The Terror of Serpent's Pass", 225, Rarity.RARE, mage.cards.t.TheTerrorOfSerpentsPass.class)); cards.add(new SetCardInfo("The Terror of Serpent's Pass", 225, Rarity.RARE, mage.cards.t.TheTerrorOfSerpentsPass.class));
@ -77,14 +111,20 @@ public final class AvatarTheLastAirbenderEternal extends ExpansionSet {
cards.add(new SetCardInfo("Thriving Heath", 262, Rarity.COMMON, mage.cards.t.ThrivingHeath.class)); cards.add(new SetCardInfo("Thriving Heath", 262, Rarity.COMMON, mage.cards.t.ThrivingHeath.class));
cards.add(new SetCardInfo("Thriving Isle", 263, Rarity.COMMON, mage.cards.t.ThrivingIsle.class)); cards.add(new SetCardInfo("Thriving Isle", 263, Rarity.COMMON, mage.cards.t.ThrivingIsle.class));
cards.add(new SetCardInfo("Thriving Moor", 264, Rarity.COMMON, mage.cards.t.ThrivingMoor.class)); cards.add(new SetCardInfo("Thriving Moor", 264, Rarity.COMMON, mage.cards.t.ThrivingMoor.class));
cards.add(new SetCardInfo("Tundra Wall", 220, Rarity.COMMON, mage.cards.t.TundraWall.class)); cards.add(new SetCardInfo("Tundra Wall", 220, Rarity.COMMON, mage.cards.t.TundraWall.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Tundra Wall", 275, Rarity.COMMON, mage.cards.t.TundraWall.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Turtle-Seals", 226, Rarity.COMMON, mage.cards.t.TurtleSeals.class)); cards.add(new SetCardInfo("Turtle-Seals", 226, Rarity.COMMON, mage.cards.t.TurtleSeals.class));
cards.add(new SetCardInfo("Warship Scout", 244, Rarity.COMMON, mage.cards.w.WarshipScout.class)); cards.add(new SetCardInfo("Warship Scout", 244, Rarity.COMMON, mage.cards.w.WarshipScout.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Warship Scout", 285, Rarity.COMMON, mage.cards.w.WarshipScout.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Water Whip", 227, Rarity.RARE, mage.cards.w.WaterWhip.class)); cards.add(new SetCardInfo("Water Whip", 227, Rarity.RARE, mage.cards.w.WaterWhip.class));
cards.add(new SetCardInfo("Wolf Cove Villager", 221, Rarity.COMMON, mage.cards.w.WolfCoveVillager.class)); cards.add(new SetCardInfo("Wolf Cove Villager", 221, Rarity.COMMON, mage.cards.w.WolfCoveVillager.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Zhao, the Seething Flame", 245, Rarity.UNCOMMON, mage.cards.z.ZhaoTheSeethingFlame.class)); cards.add(new SetCardInfo("Wolf Cove Villager", 276, Rarity.COMMON, mage.cards.w.WolfCoveVillager.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Zuko's Offense", 247, Rarity.COMMON, mage.cards.z.ZukosOffense.class)); cards.add(new SetCardInfo("Zhao, the Seething Flame", 245, Rarity.UNCOMMON, mage.cards.z.ZhaoTheSeethingFlame.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Zuko, Avatar Hunter", 246, Rarity.RARE, mage.cards.z.ZukoAvatarHunter.class)); cards.add(new SetCardInfo("Zhao, the Seething Flame", 286, Rarity.UNCOMMON, mage.cards.z.ZhaoTheSeethingFlame.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Zuko's Offense", 247, Rarity.COMMON, mage.cards.z.ZukosOffense.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Zuko's Offense", 288, Rarity.COMMON, mage.cards.z.ZukosOffense.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Zuko, Avatar Hunter", 246, Rarity.RARE, mage.cards.z.ZukoAvatarHunter.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Zuko, Avatar Hunter", 287, Rarity.RARE, mage.cards.z.ZukoAvatarHunter.class, NON_FULL_USE_VARIOUS));
cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName())); cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName()));
} }

View file

@ -0,0 +1,55 @@
package org.mage.test.cards.continuous;
import mage.constants.PhaseStep;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.game.permanent.Permanent;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class AddCardSubtypeAllEffectTest extends CardTestPlayerBase {
/*
Kudo, King Among Bears
{G}{W}
Legendary Creature Bear
Other creatures have base power and toughness 2/2 and are Bears in addition to their other types.
2/2
*/
private static final String kudo = "Kudo, King Among Bears";
/*
Fugitive Wizard
{U}
Creature Human Wizard
1/1
*/
private static final String fugitive = "Fugitive Wizard";
@Test
public void testAddCardSubtypeAllEffect() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, fugitive, 3);
addCard(Zone.BATTLEFIELD, playerB, fugitive, 3);
addCard(Zone.BATTLEFIELD, playerA, kudo);
addCard(Zone.BATTLEFIELD, playerA, "Savannah", 2);
setStopAt(1, PhaseStep.END_TURN);
execute();
for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) {
if (permanent.getName().equals(fugitive)) {
assertTrue(permanent.hasSubtype(SubType.BEAR, currentGame));
assertTrue(permanent.hasSubtype(SubType.WIZARD, currentGame));
assertTrue(permanent.hasSubtype(SubType.HUMAN, currentGame));
assertEquals(2, permanent.getPower().getModifiedBaseValue());
assertEquals(2, permanent.getToughness().getModifiedBaseValue());
}
}
assertSubtype(kudo, SubType.BEAR);
}
}

View file

@ -0,0 +1,69 @@
package org.mage.test.cards.continuous;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class BecomesColorEffectTest extends CardTestPlayerBase {
/*
Ancient Kavu
{3}{R}
Creature Kavu
{2}: This creature becomes colorless until end of turn.
Those with the ability to change their nature survived Phyrexias biological attacks. Everything else died.
3/3
*/
String kavu = "Ancient Kavu";
/*
Alchor's Tomb
{4}
Artifact
{2}, {T}: Target permanent you control becomes the color of your choice. (This effect lasts indefinitely.)
*/
String alchorsTomb = "Alchor's Tomb";
/*
*/
@Test
public void testBecomesColorSource() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, kavu);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
checkColor("Ancient Kavu is red", 1, PhaseStep.PRECOMBAT_MAIN, playerA, kavu, "R", true);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}: {this}");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkColor("Ancient Kavu is colorless", 1, PhaseStep.PRECOMBAT_MAIN, playerA, kavu, "C", true);
checkColor("Ancient Kavu is red again", 2, PhaseStep.PRECOMBAT_MAIN, playerA, kavu, "R", true);
setStopAt(2, PhaseStep.BEGIN_COMBAT);
execute();
}
@Test
public void testBecomesColorTarget() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, kavu);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
addCard(Zone.BATTLEFIELD, playerA, alchorsTomb);
checkColor("Ancient Kavu is red", 1, PhaseStep.PRECOMBAT_MAIN, playerA, kavu, "R", true);
// make Ancient Kavu green
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}, {T}: Target permanent", kavu);
setChoice(playerA, "Green");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkColor("Ancient Kavu is green", 1, PhaseStep.PRECOMBAT_MAIN, playerA, kavu, "G", true);
checkColor("Ancient Kavu is still green the following turn", 2, PhaseStep.PRECOMBAT_MAIN, playerA, kavu, "G", true);
// activate Ancient Kavu's ability to override green color until end of turn
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}: {this}");
checkColor("Ancient Kavu is colorless", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, kavu, "C", true);
// next turn it should be green again
checkColor("Ancient Kavu is green again", 4, PhaseStep.PRECOMBAT_MAIN, playerA, kavu, "G", true);
setStopAt(4, PhaseStep.BEGIN_COMBAT);
execute();
}
}

View file

@ -0,0 +1,87 @@
package org.mage.test.cards.continuous;
import mage.ObjectColor;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.PowerPredicate;
import mage.filter.predicate.mageobject.ToughnessPredicate;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
import java.util.Collections;
public class BecomesCreatureEffectTest extends CardTestPlayerBase {
/*
Ambush Commander
{3}{G}{G}
Creature Elf
Forests you control are 1/1 green Elf creatures that are still lands.
{1}{G}, Sacrifice an Elf: Target creature gets +3/+3 until end of turn.
2/2
*/
String ambushCommander = "Ambush Commander";
/*
Dryad Arbor
Land Creature Forest Dryad
1/1
*/
String dryadArbor = "Dryad Arbor";
/*
Frogify
{1}{U}
Enchantment Aura
Enchant creature
Enchanted creature loses all abilities and is a blue Frog creature with base power and toughness 1/1.
(It loses all other card types and creature types.)
*/
String frogify = "Frogify";
@Test
public void testBecomesCreatureAllEffect() {
FilterPermanent filter = new FilterPermanent();
filter.add(CardType.CREATURE.getPredicate());
filter.add(SubType.ELF.getPredicate());
filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, 1));
filter.add(new ToughnessPredicate(ComparisonType.EQUAL_TO, 1));
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 5);
addCard(Zone.BATTLEFIELD, playerA, dryadArbor);
addCard(Zone.HAND, playerA, ambushCommander);
runCode("Check forests are not 1/1 Elves", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
int numElves = game.getBattlefield().getActivePermanents(filter, player.getId(), game).size();
Assert.assertEquals("No 1/1 elves should be present", 0, numElves);
});
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, ambushCommander);
runCode("Check forests are 1/1 Elves", 1, PhaseStep.BEGIN_COMBAT, playerA, (info, player, game) -> {
int numElves = game.getBattlefield().getActivePermanents(filter, player.getId(), game).size();
// 5 forests + dryad arbor
Assert.assertEquals("There should be 6 1/1 elves present", 6, numElves);
});
setStopAt(1, PhaseStep.END_TURN);
execute();
}
@Test
public void testBecomesCreatureAttachedEffect() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
addCard(Zone.BATTLEFIELD, playerA, dryadArbor);
addCard(Zone.HAND, playerA, frogify);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, frogify, dryadArbor);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAbilities(playerA, dryadArbor, Collections.emptyList());
assertPowerToughness(playerA, dryadArbor, 1, 1);
assertType(dryadArbor, CardType.CREATURE, SubType.FROG);
assertNotSubtype(dryadArbor, SubType.DRYAD);
assertNotType(dryadArbor, CardType.LAND);
assertColor(playerA, dryadArbor, ObjectColor.BLUE, true);
assertColor(playerA, dryadArbor, ObjectColor.GREEN, false);
}
}

View file

@ -0,0 +1,45 @@
package org.mage.test.cards.continuous;
import mage.constants.CardType;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class BecomesCreatureIfVehicleEffectTest extends CardTestPlayerBase {
/*
Aerial Modification
{4}{W}
Enchantment Aura
Enchant creature or Vehicle
As long as enchanted permanent is a Vehicle, its a creature in addition to its other types.
Enchanted creature gets +2/+2 and has flying.
*/
String aerialMod = "Aerial Modification";
/*
Goliath Truck
{4}
Artifact Vehicle
Stowage Whenever this Vehicle attacks, put two +1/+1 counters on another target attacking creature.
Crew 2 (Tap any number of creatures you control with total power 2 or more: This Vehicle becomes an artifact creature until end of turn.)
4/4
*/
String goliathTruck = "Goliath Truck";
@Test
public void testBecomesCreatureIfVehicleEffect() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, goliathTruck);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 5);
addCard(Zone.HAND, playerA, aerialMod);
checkType("Goliath Truck is not a creature", 1, PhaseStep.PRECOMBAT_MAIN, playerA, goliathTruck, CardType.CREATURE, false);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, aerialMod, goliathTruck);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertType(goliathTruck, CardType.CREATURE, true);
}
}

View file

@ -157,4 +157,29 @@ public class EmblemsTest extends CardTestPlayerBase {
assertHandCount(playerA, 0); assertHandCount(playerA, 0);
} }
@Test
public void testJayaFieryNegotiator() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Jaya, Fiery Negotiator");
addCard(Zone.HAND, playerA, "Wrenn's Resolve");
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
addCard(Zone.LIBRARY, playerA, "Lightning Bolt", 2);
skipInitShuffling();
addCounters(1, PhaseStep.UPKEEP, playerA, "Jaya, Fiery Negotiator", CounterType.LOYALTY, 6);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-8: You get an emblem");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wrenn's Resolve");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
setChoice(playerA, false, 2);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertExileCount(playerA, 6 - 1);
assertLife(playerB, 20 - 3 * 3);
}
} }

View file

@ -0,0 +1,51 @@
package org.mage.test.cards.single._5ed;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class AnHavvaConstableTest extends CardTestPlayerBase {
/*
An-Havva Constable
{1}{G}{G}
Creature Human
An-Havva Constables toughness is equal to 1 plus the number of green creatures on the battlefield.
2/1+*
*/
private static final String constable = "An-Havva Constable";
/*
Bear Cub
{1}{G}
Creature Bear
2/2
*/
private static final String cub = "Bear Cub";
@Test
public void testAnHavva() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Zone.BATTLEFIELD, playerA, constable);
addCard(Zone.HAND, playerA, constable);
addCard(Zone.BATTLEFIELD, playerA, cub, 2);
addCard(Zone.BATTLEFIELD, playerB, cub, 3);
addCard(Zone.HAND, playerA, "Lightning Bolt");
checkPT("An-Havva Constable has toughness 7", 1, PhaseStep.PRECOMBAT_MAIN, playerA, constable, 2, 1 + 6);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", cub);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPT("An-Havva Constable has toughness 6", 1, PhaseStep.PRECOMBAT_MAIN, playerA, constable, 2, 1 + 5);
setStopAt(1, PhaseStep.END_TURN);
execute();
playerA.getHand().getCards(currentGame).stream()
.filter(card -> card.getName().equals(constable))
.findFirst().
ifPresent(card -> Assert.assertEquals(6, card.getToughness().getValue()));
}
}

View file

@ -0,0 +1,53 @@
package org.mage.test.cards.single.avr;
import mage.abilities.common.SimpleActivatedAbility;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class DarkImpostorTest extends CardTestPlayerBase {
/*
Dark Impostor
{2}{B}
Creature Vampire Assassin
{4}{B}{B}: Exile target creature and put a +1/+1 counter on this creature.
This creature has all activated abilities of all creature cards exiled with it.
2/2
*/
public static final String darkImposter = "Dark Impostor";
/*
Deathrite Shaman
{B/G}
Creature Elf Shaman
{T}: Exile target land card from a graveyard. Add one mana of any color.
{B}, {T}: Exile target instant or sorcery card from a graveyard. Each opponent loses 2 life.
{G}, {T}: Exile target creature card from a graveyard. You gain 2 life.
1/2
*/
public static final String deathriteShaman = "Deathrite Shaman";
@Test
public void testDarkImpostor() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, darkImposter);
addCard(Zone.BATTLEFIELD, playerA, deathriteShaman);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{B}{B}");
addTarget(playerA, deathriteShaman);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAbilityCount(playerA, darkImposter, SimpleActivatedAbility.class, 4); // own ability + 3 other from deathrite
}
}

View file

@ -0,0 +1,34 @@
package org.mage.test.cards.single.c13;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class ActOfAuthorityEffectTest extends CardTestPlayerBase {
/*
Act of Authority
{1}{W}{W}
Enchantment
When this enchantment enters, you may exile target artifact or enchantment.
At the beginning of your upkeep, you may exile target artifact or enchantment. If you do, its controller gains control of this enchantment.
*/
private static final String actOfAuthority = "Act of Authority";
@Test
public void testActOfAuthority() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, actOfAuthority);
addCard(Zone.BATTLEFIELD, playerB, actOfAuthority + "@actB");
setChoice(playerA, true); // upkeep
addTarget(playerA, "@actB");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerB, actOfAuthority, 1);
}
}

View file

@ -0,0 +1,57 @@
package org.mage.test.cards.single.dft;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class AatchikEmeraldRadianTest extends CardTestPlayerBase {
/*
Aatchik, Emerald Radian
{3}{B}{B}{G}
Legendary Creature Insect Druid
When Aatchik enters, create a 1/1 green Insect creature token for each artifact and/or creature card in your graveyard.
Whenever another Insect you control dies, put a +1/+1 counter on Aatchik. Each opponent loses 1 life.
3/3
*/
private static final String aatchik = "Aatchik, Emerald Radian";
/*
Springheart Nantuko
{1}{G}
Enchantment Creature Insect Monk
Bestow {1}{G}
Enchanted creature gets +1/+1.
Landfall Whenever a land you control enters, you may pay {1}{G} if this permanent is attached to a creature you control.
If you do, create a token thats a copy of that creature. If you didnt create a token this way, create a 1/1 green Insect creature token.
1/1
*/
private static final String nantuko = "Springheart Nantuko";
@Test
public void testOpponentCreatingTokens() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, aatchik);
addCard(Zone.BATTLEFIELD, playerB, aatchik);
addCard(Zone.GRAVEYARD, playerA, aatchik);
addCard(Zone.GRAVEYARD, playerB, aatchik);
addCard(Zone.BATTLEFIELD, playerA, "Bayou", 9);
addCard(Zone.HAND, playerA, nantuko);
addCard(Zone.HAND, playerA, "Bayou");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nantuko + " using bestow");
addTarget(playerA, aatchik);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bayou");
setChoice(playerA, true);
setChoice(playerA, aatchik);
setChoice(playerA, "When {this} enters");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertTokenCount(playerB, "Insect Token", 0);
assertTokenCount(playerA, "Insect Token", 1);
}
}

View file

@ -0,0 +1,77 @@
package org.mage.test.cards.single.dis;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.UntapAllControllerEffect;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
import static org.junit.Assert.assertEquals;
public class ExperimentKrajTest extends CardTestPlayerBase {
/*
Experiment Kraj
{2}{G}{G}{U}{U}
Legendary Creature Ooze Mutant
Experiment Kraj has all activated abilities of each other creature with a +1/+1 counter on it.
{T}: Put a +1/+1 counter on target creature.
*/
private static final String experimentKraj = "Experiment Kraj";
/*
Stoneforge Mystic
{1}{W}
Creature Kor Artificer
When this creature enters, you may search your library for an Equipment card, reveal it, put it into your hand, then shuffle.
{1}{W}, {T}: You may put an Equipment card from your hand onto the battlefield.
*/
private static final String stoneforgeMystic = "Stoneforge Mystic";
/*
Noble Hierarch
{G}
Creature Human Druid
Exalted (Whenever a creature you control attacks alone, that creature gets +1/+1 until end of turn.)
{T}: Add {G}, {W}, or {U}.
*/
private static final String nobleHierarch = "Noble Hierarch";
@Test
public void testExperimentKraj() {
setStrictChooseMode(true);
Ability ability = new SimpleActivatedAbility(
Zone.ALL,
new UntapAllControllerEffect(StaticFilters.FILTER_CONTROLLED_A_CREATURE),
new ManaCostsImpl<>("")
);
addCustomCardWithAbility("Untap creatures", playerA, ability);
addCard(Zone.BATTLEFIELD, playerA, experimentKraj);
addCard(Zone.BATTLEFIELD, playerA, stoneforgeMystic);
addCard(Zone.BATTLEFIELD, playerB, nobleHierarch);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Put a +1/+1", stoneforgeMystic);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "untap all");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Put a +1/+1", nobleHierarch);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertEquals("Kraj should have 5 activated abilities", 5, getPermanent(experimentKraj).getAbilities(currentGame)
.stream()
.filter(Ability::isActivatedAbility)
.count());
}
}

View file

@ -0,0 +1,75 @@
package org.mage.test.cards.single.fic;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.UntapAllControllerEffect;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class UriangerAugureltTest extends CardTestPlayerBase {
private static final String urianger = "Urianger Augurelt";
private static final String arcaneSignet = "Arcane Signet";
private static final String howlingMine = "Howling Mine";
private static final String thoughtVessel = "Thought Vessel";
private static final String benalishKnight = "Benalish Knight";
@Test
public void uriangerAugureltTest() {
setStrictChooseMode(true);
skipInitShuffling();
removeAllCardsFromLibrary(playerA);
Ability ability = new SimpleActivatedAbility(
Zone.ALL,
new UntapAllControllerEffect(StaticFilters.FILTER_CONTROLLED_A_CREATURE),
new ManaCostsImpl<>("")
);
addCustomCardWithAbility("Untap creatures", playerA, ability);
addCard(Zone.BATTLEFIELD, playerA, urianger);
addCard(Zone.LIBRARY, playerA, "Plains", 3);
addCard(Zone.LIBRARY, playerA, arcaneSignet);
addCard(Zone.LIBRARY, playerA, howlingMine);
addCard(Zone.LIBRARY, playerA, thoughtVessel);
addCard(Zone.LIBRARY, playerA, benalishKnight);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "<i>Draw Arcanum</i>");
setChoice(playerA, true, 4);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "untap all");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "<i>Draw Arcanum</i>");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "untap all");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "<i>Draw Arcanum</i>");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "untap all");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "<i>Draw Arcanum</i>");
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "<i>Play Arcanum</i>");
waitStackResolved(3, PhaseStep.PRECOMBAT_MAIN);
playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Plains");
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, benalishKnight, true);
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, arcaneSignet, true);
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, howlingMine, true);
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, thoughtVessel, true);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, benalishKnight, 1);
assertPermanentCount(playerA, arcaneSignet, 1);
assertPermanentCount(playerA, howlingMine, 1);
assertPermanentCount(playerA, thoughtVessel, 1);
assertLife(playerA, 20 + 2 * 4);
}
}

View file

@ -0,0 +1,66 @@
package org.mage.test.cards.single.fin;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.game.permanent.Permanent;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class AettirAndPriwenTest extends CardTestPlayerBase {
/*
Aettir and Priwen
{6}
Legendary Artifact Equipment
Equipped creature has base power and toughness X/X, where X is your life total.
Equip {5}
*/
private static final String aettir = "Aettir and Priwen";
/*
Bear Cub
{1}{G}
Creature Bear
2/2
*/
private static final String cub = "Bear Cub";
/*
Lightning Bolt
{R}
Instant
Lightning Bolt deals 3 damage to any target.
*/
public static final String bolt = "Lightning Bolt";
@Test
public void testAettirAndPriwen() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, aettir);
addCard(Zone.BATTLEFIELD, playerA, cub);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 7);
addCard(Zone.HAND, playerA, bolt, 2);
checkPowerToughness(2, cub, 1, PhaseStep.PRECOMBAT_MAIN);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{5}: Equip");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
checkPowerToughness(20, cub, 1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bolt, playerA);
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
checkPowerToughness(20 - 3, cub, 1, PhaseStep.POSTCOMBAT_MAIN);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bolt, playerA);
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
checkPowerToughness(20 - 3 * 2, cub, 1, PhaseStep.POSTCOMBAT_MAIN);
checkPowerToughness(20 - 3 * 2, cub, 2, PhaseStep.PRECOMBAT_MAIN);
}
void checkPowerToughness(int xValue, String name, int turnNum, PhaseStep phaseStep) {
runCode("Checking P/T is " + xValue, turnNum, phaseStep, playerA, (info, player, game) -> {
Permanent permanent = getPermanent(name, player);
Assert.assertEquals(xValue, permanent.getPower().getModifiedBaseValue());
Assert.assertEquals(xValue, permanent.getToughness().getModifiedBaseValue());
});
}
}

View file

@ -0,0 +1,78 @@
package org.mage.test.cards.single.lci;
import mage.constants.CardType;
import mage.constants.PhaseStep;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class AbuelosAwakeningTest extends CardTestPlayerBase {
/*
Abuelo's Awakening
{X}{3}{W}
Sorcery
Return target artifact or non-Aura enchantment card from your graveyard to the battlefield with X additional +1/+1 counters on it.
Its a 1/1 Spirit creature with flying in addition to its other types.
*/
public static final String abuelosAwakening = "Abuelo's Awakening";
/*
Talisman of Progress
{2}
Artifact
{T}: Add {C}.
{T}: Add {W} or {U}. This artifact deals 1 damage to you.
*/
public static final String talisman = "Talisman of Progress";
/*
Lightning Bolt
{R}
Instant
Lightning Bolt deals 3 damage to any target.
*/
public static final String bolt = "Lightning Bolt";
@Test
public void testAbuelosAwakening() {
setStrictChooseMode(true);
addCard(Zone.GRAVEYARD, playerA, talisman);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 6);
addCard(Zone.HAND, playerA, abuelosAwakening);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, abuelosAwakening, talisman);
setChoiceAmount(playerA, 2);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertCounterCount(playerA, talisman, CounterType.P1P1, 2);
assertType(talisman, CardType.CREATURE, true);
assertSubtype(talisman, SubType.SPIRIT);
assertBasePowerToughness(playerA, talisman, 1, 1);
}
@Test
public void testAbuelosAwakeningDies() {
setStrictChooseMode(true);
addCard(Zone.GRAVEYARD, playerA, talisman);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 6);
addCard(Zone.HAND, playerA, abuelosAwakening);
addCard(Zone.HAND, playerB, bolt);
addCard(Zone.BATTLEFIELD, playerB, "Mountain");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, abuelosAwakening, talisman);
setChoiceAmount(playerA, 2);
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, bolt, talisman);
setStopAt(2, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, talisman, 0);
assertGraveyardCount(playerA, talisman, 1);
}
}

View file

@ -0,0 +1,44 @@
package org.mage.test.cards.single.lci;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class DireBlunderbussTest extends CardTestPlayerBase {
/*
Dire Blunderbuss
Color Indicator: RedArtifact Equipment
Equipped creature gets +3/+0 and has Whenever this creature attacks, you may sacrifice an artifact other than Dire Blunderbuss. When you do, this creature deals damage equal to its power to target creature.
Equip {1}
*/
private static final String direBlunderBuss = "Dire Blunderbuss";
@Test
public void DireBlunderbussTest() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, "Forest");
addCard(Zone.BATTLEFIELD, playerA, direBlunderBuss);
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears");
addCard(Zone.BATTLEFIELD, playerB, "Balduvian Bears@bearsB");
addCard(Zone.BATTLEFIELD, playerA, "Tormod's Crypt");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", "Balduvian Bears");
attack(1, playerA, "Balduvian Bears");
setChoice(playerA, true);
setChoice(playerA, "Tormod's Crypt");
addTarget(playerA, "@bearsB");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerB, "Balduvian Bears", 1);
assertLife(playerB, 20 - 2 - 3);
}
}

View file

@ -0,0 +1,44 @@
package org.mage.test.cards.single.lci;
import mage.ObjectColor;
import mage.constants.CardType;
import mage.constants.PhaseStep;
import mage.constants.SubType;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class EatenByPiranhasTest extends CardTestPlayerBase {
/*
Eaten by Piranhas
{1}{U}
Enchantment Aura
Flash (You may cast this spell any time you could cast an instant.)
Enchant creature
Enchanted creature loses all abilities and is a black Skeleton creature with base power and toughness 1/1. (It loses all other colors, card types, and creature types.)
*/
private static final String eatenByPiranhas = "Eaten by Piranhas";
@Test
public void testEatenByPiranhas() {
setStrictChooseMode(true);
addCard(Zone.HAND, playerB, eatenByPiranhas);
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, eatenByPiranhas);
addTarget(playerB, "Balduvian Bears");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertType("Balduvian Bears", CardType.CREATURE, SubType.SKELETON);
assertPowerToughness(playerA, "Balduvian Bears", 1, 1);
assertColor(playerA, "Balduvian Bears", ObjectColor.BLACK, true);
}
}

View file

@ -0,0 +1,63 @@
package org.mage.test.cards.single.m19;
import mage.abilities.mana.AnyColorManaAbility;
import mage.constants.PhaseStep;
import mage.constants.SubType;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class AlpineMoonTest extends CardTestPlayerBase {
/*
Alpine Moon
{R}
Enchantment
As this enchantment enters, choose a nonbasic land card name.
Lands your opponents control with the chosen name lose all land types and abilities, and they gain {T}: Add one mana of any color.
*/
private static final String alpine = "Alpine Moon";
/*
Urborg, Tomb of Yawgmoth
Legendary Land
Each land is a Swamp in addition to its other land types.
*/
private static final String urborg = "Urborg, Tomb of Yawgmoth";
@Test
public void testAlpineMoonAfterUrborg() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, urborg);
addCard(Zone.BATTLEFIELD, playerB, alpine);
addCard(Zone.BATTLEFIELD, playerB, "Mountain");
addCard(Zone.BATTLEFIELD, playerA, "Island");
setChoice(playerB, urborg);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertNotSubtype(urborg, SubType.SWAMP);
assertSubtype("Mountain", SubType.SWAMP);
assertSubtype("Island", SubType.SWAMP);
assertAbility(playerA, urborg, new AnyColorManaAbility(), true);
}
@Test
public void testAlpineMoonBeforeUrborg() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerB, urborg);
addCard(Zone.BATTLEFIELD, playerA, alpine);
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Zone.BATTLEFIELD, playerB, "Island");
setChoice(playerA, urborg);
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertNotSubtype(urborg, SubType.SWAMP);
assertSubtype("Mountain", SubType.SWAMP);
assertSubtype("Island", SubType.SWAMP);
assertAbility(playerB, urborg, new AnyColorManaAbility(), true);
}
}

View file

@ -0,0 +1,60 @@
package org.mage.test.cards.single.mh2;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
import mage.game.permanent.Permanent;
import mage.game.permanent.PermanentToken;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class AeveProgenitorOozeTest extends CardTestPlayerBase {
/*
Aeve, Progenitor Ooze
{2}{G}{G}{G}
Legendary Creature Ooze
Storm (When you cast this spell, copy it for each spell cast before it this turn. Copies become tokens.)
Aeve isnt legendary if its a token.
Aeve enters with a +1/+1 counter on it for each other Ooze you control.
2/2
*/
private static final String aeve = "Aeve, Progenitor Ooze";
/*
Lightning Bolt
{R}
Instant
Lightning Bolt deals 3 damage to any target.
*/
public static final String bolt = "Lightning Bolt";
@Test
public void testAeve() {
setStrictChooseMode(true);
addCard(Zone.HAND, playerA, aeve);
addCard(Zone.HAND, playerA, bolt);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 5);
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bolt, playerB);
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, aeve);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, aeve, 2);
assertTokenCount(playerA, aeve, 1);
for (Permanent permanent : currentGame.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, playerA.getId(), currentGame)) {
if (permanent.getName().equals(aeve)) {
if (permanent instanceof PermanentToken) {
Assert.assertEquals(0, permanent.getCounters(currentGame).getCount(CounterType.P1P1));
} else {
Assert.assertEquals(1, permanent.getCounters(currentGame).getCount(CounterType.P1P1));
}
}
}
}
}

View file

@ -0,0 +1,59 @@
package org.mage.test.cards.single.mir;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.player.TestPlayer;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class PhyrexianDreadnoughtTest extends CardTestPlayerBase {
/*
Phyrexian Dreadnought
{1}
Artifact Creature Phyrexian Dreadnought
Trample
When this creature enters, sacrifice it unless you sacrifice any number of creatures with total power 12 or greater.
12/12
*/
private static final String phyrexianDreadnought = "Phyrexian Dreadnought";
@Test
public void testPhyrexianDreadnoughtCanPay() {
setStrictChooseMode(true);
addCard(Zone.HAND, playerA, phyrexianDreadnought);
addCard(Zone.BATTLEFIELD, playerA, phyrexianDreadnought + "@sacTarget");
addCard(Zone.BATTLEFIELD, playerA, "Island");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, phyrexianDreadnought);
setChoice(playerA, true);
setChoice(playerA, "@sacTarget");
setChoice(playerA, TestPlayer.CHOICE_SKIP);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, phyrexianDreadnought, 1);
assertGraveyardCount(playerA, phyrexianDreadnought, 1);
}
@Test
public void testPhyrexianDreadnoughtCantPay() {
setStrictChooseMode(true);
addCard(Zone.HAND, playerA, phyrexianDreadnought);
addCard(Zone.BATTLEFIELD, playerA, "Island");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, phyrexianDreadnought);
setStopAt(1, PhaseStep.END_TURN);
setChoice(playerA, false);
execute();
assertGraveyardCount(playerA, phyrexianDreadnought, 1);
}
}

View file

@ -0,0 +1,54 @@
package org.mage.test.cards.single.neo;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.HasteAbility;
import mage.abilities.keyword.LifelinkAbility;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
import java.util.Arrays;
public class EaterOfVirtueTest extends CardTestPlayerBase {
/*
Eater of Virtue
{1}
Legendary Artifact Equipment
Whenever equipped creature dies, exile it.
Equipped creature gets +2/+0.
As long as a card exiled with Eater of Virtue has flying, equipped creature has flying.
The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, protection, reach, trample, and vigilance.
Equip {1}
*/
public static final String eaterOfVirtue = "Eater of Virtue";
@Test
public void testEaterOfVirtue() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, eaterOfVirtue);
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
addCard(Zone.BATTLEFIELD, playerA, "Adult Gold Dragon"); // Flying, Lifelink, Haste
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears");
addCard(Zone.HAND, playerB, "Doom Blade");
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip", "Adult Gold Dragon");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 1);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Doom Blade", "Adult Gold Dragon");
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 1);
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Equip", "Balduvian Bears");
setStopAt(1, PhaseStep.END_TURN);
execute();
assertAbilities(playerA, "Balduvian Bears", Arrays.asList(FlyingAbility.getInstance(), LifelinkAbility.getInstance(), HasteAbility.getInstance()));
}
}

View file

@ -0,0 +1,58 @@
package org.mage.test.cards.single.one;
import mage.cards.Card;
import mage.constants.CardType;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestCommanderDuelBase;
import java.util.List;
import static org.junit.Assert.assertTrue;
public class EncroachingMycosynthTest extends CardTestCommanderDuelBase {
/*
Encroaching Mycosynth
{3}{U}
Artifact
Nonland permanents you control are artifacts in addition to their other types.
The same is true for permanent spells you control and nonland permanent cards you own that arent on the battlefield.
*/
private static final String encroachingMycosynth = "Encroaching Mycosynth";
private static final String balduvianBears = "Balduvian Bears";
@Test
public void testEncroachingMycosynth() {
setStrictChooseMode(true);
addCard(Zone.GRAVEYARD, playerA, balduvianBears);
addCard(Zone.HAND, playerA, balduvianBears, 2);
addCard(Zone.BATTLEFIELD, playerA, balduvianBears);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
addCard(Zone.BATTLEFIELD, playerA, encroachingMycosynth);
addCard(Zone.EXILED, playerA, balduvianBears);
addCard(Zone.LIBRARY, playerA, balduvianBears);
addCard(Zone.COMMAND, playerA, balduvianBears);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, balduvianBears);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertType(balduvianBears, CardType.ARTIFACT, true);
List<Card> cards = getHandCards(playerA);
cards.addAll(getLibraryCards(playerA));
cards.addAll(getCommandCards(playerA));
cards.addAll(getExiledCards(playerA));
cards.addAll(getLibraryCards(playerA));
for (Card card : cards) {
if (!card.isLand(currentGame)) {
assertTrue(card.getCardType(currentGame).contains(CardType.ARTIFACT));
}
}
}
}

View file

@ -0,0 +1,59 @@
package org.mage.test.cards.single.one;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class NahirisSacrificeTest extends CardTestPlayerBase {
/*
Nahiri's Sacrifice
{1}{R}
Sorcery
As an additional cost to cast this spell, sacrifice an artifact or creature with mana value X.
Nahiris Sacrifice deals X damage divided as you choose among any number of target creatures.
*/
private static final String nahirisSacrifice = "Nahiri's Sacrifice";
private static final String balduvianBears = "Balduvian Bears";
@Test
public void testNahirisSacrifice() {
setStrictChooseMode(true);
addCard(Zone.HAND, playerA, nahirisSacrifice);
addCard(Zone.BATTLEFIELD, playerA, balduvianBears);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
addCard(Zone.BATTLEFIELD, playerB, balduvianBears + "@bearsB");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nahirisSacrifice, "@bearsB");
setChoice(playerA, "X=2");
setChoice(playerA, balduvianBears);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertGraveyardCount(playerB, balduvianBears, 1);
assertGraveyardCount(playerA, nahirisSacrifice, 1);
}
@Test
@Ignore // Enable after merging #13916
public void testNahirisSacrificePrevented() {
setStrictChooseMode(true);
addCard(Zone.HAND, playerA, nahirisSacrifice);
addCard(Zone.BATTLEFIELD, playerA, balduvianBears);
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
addCard(Zone.BATTLEFIELD, playerB, balduvianBears + "@bearsB");
addCard(Zone.BATTLEFIELD, playerB, "Yasharn, Implacable Earth");
checkPlayableAbility("Can't cast", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast " + nahirisSacrifice, false);
setStopAt(1, PhaseStep.END_TURN);
execute();
}
}

View file

@ -0,0 +1,57 @@
package org.mage.test.cards.single.shm;
import mage.constants.CardType;
import mage.constants.PhaseStep;
import mage.constants.SubType;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class ElsewhereFlaskTest extends CardTestPlayerBase {
/*
Elsewhere Flask
{2}
Artifact
When this artifact enters, draw a card.
Sacrifice this artifact: Choose a basic land type. Each land you control becomes that type until end of turn.
*/
private static final String elsewhereFlask = "Elsewhere Flask";
@Test
public void testElsewhereFlask() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, elsewhereFlask);
addCard(Zone.BATTLEFIELD, playerA, "Island");
addCard(Zone.BATTLEFIELD, playerA, "Forest");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice");
setChoice(playerA, "Swamp");
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertType("Island", CardType.LAND, SubType.SWAMP);
assertType("Forest", CardType.LAND, SubType.SWAMP);
}
@Test
public void testElsewhereFlask2() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, elsewhereFlask);
addCard(Zone.BATTLEFIELD, playerA, "Island");
addCard(Zone.BATTLEFIELD, playerA, "Forest");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice");
setChoice(playerA, "Swamp");
setStopAt(2, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertType("Island", CardType.LAND, SubType.ISLAND);
assertType("Forest", CardType.LAND, SubType.FOREST);
}
}

View file

@ -0,0 +1,48 @@
package org.mage.test.cards.single.tdm;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class StalwartSuccessorTest extends CardTestPlayerBase {
/*
Stalwart Successor
{1}{B}{G}
Creature Human Warrior
Menace (This creature cant be blocked except by two or more creatures.)
Whenever one or more counters are put on a creature you control, if its the first time counters have been put on that creature this turn, put a +1/+1 counter on that creature.
3/2
*/
private static final String stalwartSuccessor = "Stalwart Successor";
/*
Purestrain Genestealer
{2}{G}
Creature Tyranid
This creature enters with two +1/+1 counters on it.
Vanguard Species Whenever this creature attacks, you may remove a +1/+1 counter from it. If you do, search your library for a basic land card, put it onto the battlefield tapped, then shuffle.
1/1
*/
private static final String purestrainGenestealer = "Purestrain Genestealer";
@Test
public void testStalwartSuccessor() {
addCard(Zone.BATTLEFIELD, playerA, stalwartSuccessor);
addCard(Zone.BATTLEFIELD, playerA, "Forest", 3);
addCard(Zone.HAND, playerA, purestrainGenestealer);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, purestrainGenestealer);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertCounterCount(playerA, purestrainGenestealer, CounterType.P1P1, 2 + 1);
}
}

View file

@ -0,0 +1,45 @@
package org.mage.test.cards.single.tmp;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class AlurenTest extends CardTestPlayerBase {
/*
Aluren
{2}{G}{G}
Enchantment
Any player may cast creature spells with mana value 3 or less without paying their mana costs and as though they had flash.
*/
private static final String aluren = "Aluren";
/*
Bear Cub
{1}{G}
Creature Bear
2/2
*/
private static final String cub = "Bear Cub";
@Test
public void testAluren() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, aluren);
addCard(Zone.HAND, playerA, cub);
addCard(Zone.HAND, playerB, cub);
castSpell(1, PhaseStep.UPKEEP, playerA, cub);
setChoice(playerA, "Cast without paying its mana cost");
castSpell(1, PhaseStep.END_TURN, playerB, cub);
setChoice(playerB, "Cast without paying its mana cost");
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertPermanentCount(playerA, cub, 1);
assertPermanentCount(playerB, cub, 1);
}
}

View file

@ -0,0 +1,54 @@
package org.mage.test.cards.single.tmp;
import mage.abilities.keyword.LandwalkAbility;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Ignore;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
public class ExcavatorTest extends CardTestPlayerBase {
/*
Excavator
{2}
Artifact
{T}, Sacrifice a basic land: Target creature gains landwalk of each of the land types of the sacrificed land until end of turn.
(It cant be blocked as long as defending player controls a land of any of those types.)
*/
public static final String excavator = "Excavator";
/*
Leyline of the Guildpact
{G/W}{G/U}{B/G}{R/G}
Enchantment
If this card is in your opening hand, you may begin the game with it on the battlefield.
Each nonland permanent you control is all colors.
Lands you control are every basic land type in addition to their other types.
*/
public static final String leylineOfTheGuildpact = "Leyline of the Guildpact";
@Test
@Ignore("Failing because permanent LKI does not save MageObjectAttribute values")
public void testExcavator() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, excavator);
addCard(Zone.BATTLEFIELD, playerA, leylineOfTheGuildpact);
addCard(Zone.BATTLEFIELD, playerA, "Island");
addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}");
setChoice(playerA, "Island");
addTarget(playerA, "Balduvian Bears");
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertAbilityCount(playerA, "Balduvian Bears", LandwalkAbility.class, 5);
}
}

View file

@ -0,0 +1,95 @@
package org.mage.test.cards.single.who;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.LoseGameSourceControllerEffect;
import mage.abilities.effects.common.LoseLifeAllPlayersEffect;
import mage.abilities.effects.common.WinGameSourceControllerEffect;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestCommander4Players;
public class EverybodyLivesTest extends CardTestCommander4Players {
/*
Everybody Lives!
{1}{W}
Instant
All creatures gain hexproof and indestructible until end of turn. Players gain hexproof until end of turn.
Players cant lose life this turn and players cant lose the game or win the game this turn.
*/
private static final String everybodyLives = "Everybody Lives!";
@Test
public void testEverybodyLivesCantLoseLifeAndHexproof() {
setStrictChooseMode(true);
addCustomCardWithAbility("lose life effect", playerA, new SimpleActivatedAbility(
new LoseLifeAllPlayersEffect(20),
new ManaCostsImpl<>(""))
);
addCard(Zone.HAND, playerA, "Lightning Bolt");
addCard(Zone.HAND, playerA, everybodyLives);
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Zone.BATTLEFIELD, playerA, "Plains");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, everybodyLives, true);
checkPlayableAbility("Can't cast lightning bolt", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Lightning Bolt", false);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "each player");
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertLife(playerA, 20);
assertLife(playerB, 20);
assertLife(playerC, 20);
assertLife(playerD, 20);
}
@Test
public void testEverybodyLivesCantLoseGame() {
setStrictChooseMode(true);
addCustomCardWithAbility("lose game effect", playerA, new SimpleActivatedAbility(
new LoseGameSourceControllerEffect(),
new ManaCostsImpl<>(""))
);
addCard(Zone.HAND, playerA, everybodyLives);
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Zone.BATTLEFIELD, playerA, "Plains");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, everybodyLives, true);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "you lose");
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertHasNotLostTheGame(playerA);
}
@Test
public void testEverybodyLivesCantWinGame() {
setStrictChooseMode(true);
addCustomCardWithAbility("win game effect", playerA, new SimpleActivatedAbility(
new WinGameSourceControllerEffect(),
new ManaCostsImpl<>(""))
);
addCard(Zone.HAND, playerA, everybodyLives);
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
addCard(Zone.BATTLEFIELD, playerA, "Plains");
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, everybodyLives, true);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "you win");
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertHasNotWonTheGame(playerA);
}
}

View file

@ -2079,6 +2079,7 @@ public class VerifyCardDataTest {
} }
} }
} }
private void checkSubtypes(Card card, MtgJsonCard ref) { private void checkSubtypes(Card card, MtgJsonCard ref) {
if (skipListHaveName(SKIP_LIST_SUBTYPE, card.getExpansionSetCode(), card.getName())) { if (skipListHaveName(SKIP_LIST_SUBTYPE, card.getExpansionSetCode(), card.getName())) {
return; return;
@ -2343,7 +2344,11 @@ public class VerifyCardDataTest {
// search and check dies related abilities // search and check dies related abilities
String rules = triggeredAbility.getRule(); // remove reminder text
String rules = triggeredAbility
.getRule()
.replaceAll("(?i) <i>\\(.+\\)</i>", "")
.replaceAll("(?i) \\(.+\\)", "");
if (ignoredAbilities.stream().anyMatch(rules::contains)) { if (ignoredAbilities.stream().anyMatch(rules::contains)) {
continue; continue;
} }

View file

@ -6,9 +6,11 @@ import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.game.Controllable;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player;
import java.util.Optional;
/** /**
* @author TheElk801 * @author TheElk801
@ -47,12 +49,12 @@ public class DamageWithExcessEffect extends OneShotEffect {
return false; return false;
} }
int damage = amount.calculate(game, source, this); int damage = amount.calculate(game, source, this);
int lethal = permanent.getLethalDamage(source.getSourceId(), game); int excess = permanent.damageWithExcess(damage, source, game);
lethal = Math.min(lethal, damage); if (excess > 0) {
permanent.damage(lethal, source.getSourceId(), source, game); Optional.ofNullable(permanent)
Player player = game.getPlayer(permanent.getControllerId()); .map(Controllable::getControllerId)
if (player != null && lethal < damage) { .map(game::getPlayer)
player.damage(damage - lethal, source.getSourceId(), source, game); .ifPresent(player -> player.damage(excess, source, game));
} }
return true; return true;
} }

View file

@ -8,6 +8,7 @@ import mage.constants.Zone;
import mage.game.Controllable; import mage.game.Controllable;
import mage.game.Game; import mage.game.Game;
import mage.game.GameState; import mage.game.GameState;
import mage.util.CardUtil;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -177,6 +178,23 @@ public interface Permanent extends Card, Controllable {
int getLethalDamage(UUID attackerId, Game game); int getLethalDamage(UUID attackerId, Game game);
/**
* Same arguments as regular damage method, but returns the amount of excess damage dealt instead
*
* @return
*/
default int damageWithExcess(int damage, Ability source, Game game) {
return this.damageWithExcess(damage, source.getSourceId(), source, game);
}
default int damageWithExcess(int damage, UUID attackerId, Ability source, Game game) {
int lethal = getLethalDamage(attackerId, game);
int excess = Math.max(CardUtil.overflowDec(damage, lethal), 0);
int dealt = Math.min(lethal, damage);
this.damage(dealt, attackerId, source, game);
return excess;
}
void removeAllDamage(Game game); void removeAllDamage(Game game);
void reset(Game game); void reset(Game game);

View file

@ -38,14 +38,6 @@ public class TargetCardAndOrCardInLibrary extends TargetCardInLibrary {
private final PredicateCardAssignment assignment; private final PredicateCardAssignment assignment;
/**
* a [firstType] card and/or a [secondType] card
*/
protected TargetCardAndOrCardInLibrary(Predicate<? super Card> firstPredicate, Predicate<? super Card> secondPredicate, String filterText) {
super(0, 2, makeFilter(firstPredicate, secondPredicate, filterText));
this.assignment = new PredicateCardAssignment(firstPredicate, secondPredicate);
}
public TargetCardAndOrCardInLibrary(CardType firstType, CardType secondType) { public TargetCardAndOrCardInLibrary(CardType firstType, CardType secondType) {
this(firstType.getPredicate(), secondType.getPredicate(), makeFilterText( this(firstType.getPredicate(), secondType.getPredicate(), makeFilterText(
CardUtil.getTextWithFirstCharLowerCase(firstType.toString()), CardUtil.getTextWithFirstCharLowerCase(firstType.toString()),
@ -60,6 +52,14 @@ public class TargetCardAndOrCardInLibrary extends TargetCardInLibrary {
this(firstType.getPredicate(), secondType.getPredicate(), makeFilterText(firstType.getDescription(), secondType.getDescription())); this(firstType.getPredicate(), secondType.getPredicate(), makeFilterText(firstType.getDescription(), secondType.getDescription()));
} }
/**
* a [firstType] card and/or a [secondType] card
*/
public TargetCardAndOrCardInLibrary(Predicate<? super Card> firstPredicate, Predicate<? super Card> secondPredicate, String filterText) {
super(0, 2, makeFilter(firstPredicate, secondPredicate, filterText));
this.assignment = new PredicateCardAssignment(firstPredicate, secondPredicate);
}
protected TargetCardAndOrCardInLibrary(final TargetCardAndOrCardInLibrary target) { protected TargetCardAndOrCardInLibrary(final TargetCardAndOrCardInLibrary target) {
super(target); super(target);
this.assignment = target.assignment; this.assignment = target.assignment;

View file

@ -59737,7 +59737,7 @@ Flexible Waterbender|Avatar: The Last Airbender|50|C|{3}{U}|Creature - Human War
Geyser Leaper|Avatar: The Last Airbender|52|C|{4}{U}|Creature - Human Warrior Ally|4|3|Flying$Waterbend {4}: Draw a card, then discard a card.| Geyser Leaper|Avatar: The Last Airbender|52|C|{4}{U}|Creature - Human Warrior Ally|4|3|Flying$Waterbend {4}: Draw a card, then discard a card.|
Giant Koi|Avatar: The Last Airbender|53|C|{4}{U}{U}|Creature - Fish|5|7|Waterbend {3}: This creature can't be blocked this turn.$Islandcycling {2}| Giant Koi|Avatar: The Last Airbender|53|C|{4}{U}{U}|Creature - Fish|5|7|Waterbend {3}: This creature can't be blocked this turn.$Islandcycling {2}|
Iguana Parrot|Avatar: The Last Airbender|56|C|{2}{U}|Creature - Lizard Bird Pirate|2|2|Flying, vigilance$Prowess| Iguana Parrot|Avatar: The Last Airbender|56|C|{2}{U}|Creature - Lizard Bird Pirate|2|2|Flying, vigilance$Prowess|
It'll Quench Ya!|Avatar: The Last Airbender|58|C|{1}{U}|Instant - Lesson|||Counter target spell unless its controller pays 2.| It'll Quench Ya!|Avatar: The Last Airbender|58|C|{1}{U}|Instant - Lesson|||Counter target spell unless its controller pays {2}.|
Katara, Bending Prodigy|Avatar: The Last Airbender|59|U|{2}{U}|Legendary Creature - Human Warrior Ally|2|3|At the beginning of your end step, if Katara is tapped, put a +1/+1 counter on her.$Waterbend {6}: Draw a card.| Katara, Bending Prodigy|Avatar: The Last Airbender|59|U|{2}{U}|Legendary Creature - Human Warrior Ally|2|3|At the beginning of your end step, if Katara is tapped, put a +1/+1 counter on her.$Waterbend {6}: Draw a card.|
Master Pakku|Avatar: The Last Airbender|63|U|{1}{U}|Legendary Creature - Human Advisor Ally|1|3|Prowess$Whenever Master Pakku becomes tapped, target player mills X cards, where X is the number of Lesson cards in your graveyard.| Master Pakku|Avatar: The Last Airbender|63|U|{1}{U}|Legendary Creature - Human Advisor Ally|1|3|Prowess$Whenever Master Pakku becomes tapped, target player mills X cards, where X is the number of Lesson cards in your graveyard.|
Otter-Penguin|Avatar: The Last Airbender|67|C|{1}{U}|Creature - Otter Bird|2|1|Whenever you draw your second card each turn, this creature gets +1/+2 until end of turn and can't be blocked this turn.| Otter-Penguin|Avatar: The Last Airbender|67|C|{1}{U}|Creature - Otter Bird|2|1|Whenever you draw your second card each turn, this creature gets +1/+2 until end of turn and can't be blocked this turn.|
@ -59804,6 +59804,11 @@ Toph, the First Metalbender|Avatar: The Last Airbender|247|R|{1}{R}{G}{W}|Legend
Vindictive Warden|Avatar: The Last Airbender|249|C|{2}{B/R}|Creature - Human Soldier|2|3|Menace$Firebending 1${3}: This creature deals 1 damage to each opponent.| Vindictive Warden|Avatar: The Last Airbender|249|C|{2}{B/R}|Creature - Human Soldier|2|3|Menace$Firebending 1${3}: This creature deals 1 damage to each opponent.|
Barrels of Blasting Jelly|Avatar: The Last Airbender|254|C|{1}|Artifact|||{1}: Add one mana of any color. Activate only once each turn.${5}, {T}, Sacrifice this artifact: It deals 5 damage to target creature.| Barrels of Blasting Jelly|Avatar: The Last Airbender|254|C|{1}|Artifact|||{1}: Add one mana of any color. Activate only once each turn.${5}, {T}, Sacrifice this artifact: It deals 5 damage to target creature.|
Bender's Waterskin|Avatar: The Last Airbender|255|C|{3}|Artifact|||Untap this artifact during each other player's untap step.${T}: Add one mana of any color.| Bender's Waterskin|Avatar: The Last Airbender|255|C|{3}|Artifact|||Untap this artifact during each other player's untap step.${T}: Add one mana of any color.|
Plains|Avatar: The Last Airbender|282|C||Basic Land - Plains|||({T}: Add {W}.)|
Island|Avatar: The Last Airbender|283|C||Basic Land - Island|||({T}: Add {U}.)|
Swamp|Avatar: The Last Airbender|284|C||Basic Land - Swamp|||({T}: Add {B}.)|
Mountain|Avatar: The Last Airbender|285|C||Basic Land - Mountain|||({T}: Add {R}.)|
Forest|Avatar: The Last Airbender|286|C||Basic Land - Forest|||({T}: Add {G}.)|
Plains|Avatar: The Last Airbender|287|C||Basic Land - Plains|||({T}: Add {W}.)| Plains|Avatar: The Last Airbender|287|C||Basic Land - Plains|||({T}: Add {W}.)|
Island|Avatar: The Last Airbender|288|C||Basic Land - Island|||({T}: Add {U}.)| Island|Avatar: The Last Airbender|288|C||Basic Land - Island|||({T}: Add {U}.)|
Swamp|Avatar: The Last Airbender|289|C||Basic Land - Swamp|||({T}: Add {B}.)| Swamp|Avatar: The Last Airbender|289|C||Basic Land - Swamp|||({T}: Add {B}.)|
@ -59825,6 +59830,7 @@ Katara, the Fearless|Avatar: The Last Airbender|361|R|{G}{W}{U}|Legendary Creatu
Toph, the First Metalbender|Avatar: The Last Airbender|362|R|{1}{R}{G}{W}|Legendary Creature - Human Warrior Ally|3|3|Nontoken artifacts you control are lands in addition to their other types.$At the beginning of your end step, earthbend 2.| Toph, the First Metalbender|Avatar: The Last Airbender|362|R|{1}{R}{G}{W}|Legendary Creature - Human Warrior Ally|3|3|Nontoken artifacts you control are lands in addition to their other types.$At the beginning of your end step, earthbend 2.|
Avatar Aang|Avatar: The Last Airbender|363|M|{R}{G}{W}{U}|Legendary Creature - Human Avatar Ally|4|4|Flying, firebending 2$Whenever you waterbend, earthbend, firebend, or airbend, draw a card. Then if you've done all four this turn, transform Avatar Aang.| Avatar Aang|Avatar: The Last Airbender|363|M|{R}{G}{W}{U}|Legendary Creature - Human Avatar Ally|4|4|Flying, firebending 2$Whenever you waterbend, earthbend, firebend, or airbend, draw a card. Then if you've done all four this turn, transform Avatar Aang.|
Aang, Master of Elements|Avatar: The Last Airbender|363|M||Legendary Creature - Avatar Ally|6|6|Flying$Spells you cast cost {W}{U}{B}{R}{G} less to cast.$At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent.| Aang, Master of Elements|Avatar: The Last Airbender|363|M||Legendary Creature - Avatar Ally|6|6|Flying$Spells you cast cost {W}{U}{B}{R}{G} less to cast.$At the beginning of each upkeep, you may transform Aang, Master of Elements. If you do, you gain 4 life, draw four cards, put four +1/+1 counters on him, and he deals 4 damage to each opponent.|
Hakoda, Selfless Commander|Avatar: The Last Airbender|366|R|{3}{W}|Legendary Creature - Human Warrior Ally|3|5|Vigilance$You may look at the top card of your library any time.$You may cast Ally spells from the top of your library.$Sacrifice Hakoda: Creatures you control get +0/+5 and gain indestructible until end of turn.|
Sokka, Bold Boomeranger|Avatar: The Last Airbender|383|R|{U}{R}|Legendary Creature - Human Warrior Ally|1|1|When Sokka enters, discard up to two cards, then draw that many cards.$Whenever you cast an artifact or Lesson spell, put a +1/+1 counter on Sokka.| Sokka, Bold Boomeranger|Avatar: The Last Airbender|383|R|{U}{R}|Legendary Creature - Human Warrior Ally|1|1|When Sokka enters, discard up to two cards, then draw that many cards.$Whenever you cast an artifact or Lesson spell, put a +1/+1 counter on Sokka.|
Anti-Venom, Horrifying Healer|Marvel's Spider-Man|1|M|{W}{W}{W}{W}{W}|Legendary Creature - Symbiote Hero|5|5|When Anti-Venom enters, if he was cast, return target creature card from your graveyard to the battlefield.$If damage would be dealt to Anti-Venom, prevent that damage and put that many +1/+1 counters on him.| Anti-Venom, Horrifying Healer|Marvel's Spider-Man|1|M|{W}{W}{W}{W}{W}|Legendary Creature - Symbiote Hero|5|5|When Anti-Venom enters, if he was cast, return target creature card from your graveyard to the battlefield.$If damage would be dealt to Anti-Venom, prevent that damage and put that many +1/+1 counters on him.|
Aunt May|Marvel's Spider-Man|3|U|{W}|Legendary Creature - Human Citizen|0|2|Whenever another creature you control enters, you gain 1 life. If it's a Spider, put a +1/+1 counter on it.| Aunt May|Marvel's Spider-Man|3|U|{W}|Legendary Creature - Human Citizen|0|2|Whenever another creature you control enters, you gain 1 life. If it's a Spider, put a +1/+1 counter on it.|
@ -59940,7 +59946,7 @@ Aang, Air Nomad|Avatar: The Last Airbender Eternal|210|R|{3}{W}{W}|Legendary Cre
Aang's Defense|Avatar: The Last Airbender Eternal|211|C|{W}|Instant|||Target blocking creature you control gets +2/+2 until end of turn.$Draw a card.| Aang's Defense|Avatar: The Last Airbender Eternal|211|C|{W}|Instant|||Target blocking creature you control gets +2/+2 until end of turn.$Draw a card.|
Aardvark Sloth|Avatar: The Last Airbender Eternal|212|C|{3}{W}|Creature - Sloth Beast|3|3|Lifelink| Aardvark Sloth|Avatar: The Last Airbender Eternal|212|C|{3}{W}|Creature - Sloth Beast|3|3|Lifelink|
Allied Teamwork|Avatar: The Last Airbender Eternal|213|R|{2}{W}|Enchantment|||When this enchantment enters, create a 1/1 white Ally creature token.$Allies you control get +1/+1.| Allied Teamwork|Avatar: The Last Airbender Eternal|213|R|{2}{W}|Enchantment|||When this enchantment enters, create a 1/1 white Ally creature token.$Allies you control get +1/+1.|
Appa, Aang's Companion|Avatar: The Last Airbender Eternal|214|U|{3}{W}|Legendary Creature - Bison Ally|2|4|Flying$Whenever Appa attacks, another target attacking creature without flying gains flying until until end of turn.| Appa, Aang's Companion|Avatar: The Last Airbender Eternal|214|U|{3}{W}|Legendary Creature - Bison Ally|2|4|Flying$Whenever Appa attacks, another target attacking creature without flying gains flying until end of turn.|
Katara, Heroic Healer|Avatar: The Last Airbender Eternal|215|U|{4}{W}|Legendary Creature - Human Warrior Ally|2|3|Lifelink$When Katara enters, put a +1/+1 counter on each other creature you control.| Katara, Heroic Healer|Avatar: The Last Airbender Eternal|215|U|{4}{W}|Legendary Creature - Human Warrior Ally|2|3|Lifelink$When Katara enters, put a +1/+1 counter on each other creature you control.|
Kyoshi Warrior Guard|Avatar: The Last Airbender Eternal|216|C|{1}{W}|Creature - Human Warrior Ally|2|3|| Kyoshi Warrior Guard|Avatar: The Last Airbender Eternal|216|C|{1}{W}|Creature - Human Warrior Ally|2|3||
Momo, Rambunctious Rascal|Avatar: The Last Airbender Eternal|217|U|{2}{W}|Legendary Creature - Lemur Bat Ally|1|1|Flying$When Momo enters, he deals 4 damage to target tapped creature an opponent controls.| Momo, Rambunctious Rascal|Avatar: The Last Airbender Eternal|217|U|{2}{W}|Legendary Creature - Lemur Bat Ally|1|1|Flying$When Momo enters, he deals 4 damage to target tapped creature an opponent controls.|
@ -59991,3 +59997,43 @@ Thriving Grove|Avatar: The Last Airbender Eternal|261|C||Land|||This land enters
Thriving Heath|Avatar: The Last Airbender Eternal|262|C||Land|||This land enters tapped. As it enters, choose a color other than white.${T}: Add {W} or one mana of the chosen color.| Thriving Heath|Avatar: The Last Airbender Eternal|262|C||Land|||This land enters tapped. As it enters, choose a color other than white.${T}: Add {W} or one mana of the chosen color.|
Thriving Isle|Avatar: The Last Airbender Eternal|263|C||Land|||This land enters tapped. As it enters, choose a color other than blue.${T}: Add {U} or one mana of the chosen color.| Thriving Isle|Avatar: The Last Airbender Eternal|263|C||Land|||This land enters tapped. As it enters, choose a color other than blue.${T}: Add {U} or one mana of the chosen color.|
Thriving Moor|Avatar: The Last Airbender Eternal|264|C||Land|||This land enters tapped. As it enters, choose a color other than black.${T}: Add {B} or one mana of the chosen color.| Thriving Moor|Avatar: The Last Airbender Eternal|264|C||Land|||This land enters tapped. As it enters, choose a color other than black.${T}: Add {B} or one mana of the chosen color.|
Aang, Air Nomad|Avatar: The Last Airbender Eternal|265|R|{3}{W}{W}|Legendary Creature - Human Avatar Ally|5|4|Flying$Vigilance$Other creatures you control have vigilance.|
Aang's Defense|Avatar: The Last Airbender Eternal|266|C|{W}|Instant|||Target blocking creature you control gets +2/+2 until end of turn.$Draw a card.|
Aardvark Sloth|Avatar: The Last Airbender Eternal|267|C|{3}{W}|Creature - Sloth Beast|3|3|Lifelink|
Appa, Aang's Companion|Avatar: The Last Airbender Eternal|268|U|{3}{W}|Legendary Creature - Bison Ally|2|4|Flying$Whenever Appa attacks, another target attacking creature without flying gains flying until end of turn.|
Katara, Heroic Healer|Avatar: The Last Airbender Eternal|269|U|{4}{W}|Legendary Creature - Human Warrior Ally|2|3|Lifelink$When Katara enters, put a +1/+1 counter on each other creature you control.|
Momo, Rambunctious Rascal|Avatar: The Last Airbender Eternal|270|U|{2}{W}|Legendary Creature - Lemur Bat Ally|1|1|Flying$When Momo enters, he deals 4 damage to target tapped creature an opponent controls.|
Path to Redemption|Avatar: The Last Airbender Eternal|271|C|{1}{W}|Enchantment - Aura|||Enchant creature$Enchanted creature can't attack or block.${5}, Sacrifice this Aura: Exile enchanted creature. Create a 1/1 white Ally creature token. Activate only during your turn.|
Razor Rings|Avatar: The Last Airbender Eternal|272|C|{1}{W}|Instant|||Razor Rings deals 4 damage to target attacking or blocking creature. You gain life equal to the excess damage dealt this way.|
Sledding Otter-Penguin|Avatar: The Last Airbender Eternal|273|C|{2}{W}|Creature - Otter Bird|2|3|{3}: Put a +1/+1 counter on this creature.|
Sokka, Wolf Cove's Protector|Avatar: The Last Airbender Eternal|274|U|{2}{W}|Legendary Creature - Human Warrior Ally|3|3|Vigilance|
Tundra Wall|Avatar: The Last Airbender Eternal|275|C|{1}{W}|Creature - Wall|0|4|Defender|
Wolf Cove Villager|Avatar: The Last Airbender Eternal|276|C|{W}|Creature - Human Peasant|2|2|This creature enters tapped.|
Capital Guard|Avatar: The Last Airbender Eternal|277|C|{1}{R}|Creature - Human Soldier|2|2||
Dragon Moose|Avatar: The Last Airbender Eternal|278|C|{3}{R}|Creature - Dragon Elk|3|3|Haste|
Explosive Shot|Avatar: The Last Airbender Eternal|279|C|{1}{R}|Sorcery|||Explosive Shot deals 4 damage to target creature.|
Fire Nation Soldier|Avatar: The Last Airbender Eternal|280|C|{2}{R}|Creature - Human Soldier|3|2|Haste|
Fire Nation's Conquest|Avatar: The Last Airbender Eternal|281|U|{2}{R}|Enchantment|||Creatures you control get +1/+0.|
Iroh, Firebending Instructor|Avatar: The Last Airbender Eternal|282|U|{2}{R}|Legendary Creature - Human Noble Ally|2|2|Whenever Iroh attacks, attacking creatures get +1/+1 until end of turn.|
Komodo Rhino|Avatar: The Last Airbender Eternal|283|C|{3}{R}|Creature - Lizard Rhino|5|2|Trample|
Run Amok|Avatar: The Last Airbender Eternal|284|C|{1}{R}|Instant|||Target attacking creature gets +3/+3 and gains trample until end of turn.|
Warship Scout|Avatar: The Last Airbender Eternal|285|C|{R}|Creature - Human Scout|2|1||
Zhao, the Seething Flame|Avatar: The Last Airbender Eternal|286|U|{4}{R}|Legendary Creature - Human Soldier|5|5|Menace|
Zuko, Avatar Hunter|Avatar: The Last Airbender Eternal|287|R|{3}{R}{R}|Legendary Creature - Human Noble|4|5|Reach$Whenever you cast a red spell, create a 2/2 red Soldier creature token.|
Zuko's Offense|Avatar: The Last Airbender Eternal|288|C|{R}|Sorcery|||Zuko's Offense deals 2 damage to any target.|
Mountain|Avatar: The Last Airbender Eternal|289|C||Basic Land - Mountain|||({T}: Add {R}.)|
Mountain|Avatar: The Last Airbender Eternal|290|C||Basic Land - Mountain|||({T}: Add {R}.)|
Mountain|Avatar: The Last Airbender Eternal|291|C||Basic Land - Mountain|||({T}: Add {R}.)|
Mountain|Avatar: The Last Airbender Eternal|292|C||Basic Land - Mountain|||({T}: Add {R}.)|
Mountain|Avatar: The Last Airbender Eternal|293|C||Basic Land - Mountain|||({T}: Add {R}.)|
Mountain|Avatar: The Last Airbender Eternal|294|C||Basic Land - Mountain|||({T}: Add {R}.)|
Mountain|Avatar: The Last Airbender Eternal|295|C||Basic Land - Mountain|||({T}: Add {R}.)|
Mountain|Avatar: The Last Airbender Eternal|296|C||Basic Land - Mountain|||({T}: Add {R}.)|
Plains|Avatar: The Last Airbender Eternal|297|C||Basic Land - Plains|||({T}: Add {W}.)|
Plains|Avatar: The Last Airbender Eternal|298|C||Basic Land - Plains|||({T}: Add {W}.)|
Plains|Avatar: The Last Airbender Eternal|299|C||Basic Land - Plains|||({T}: Add {W}.)|
Plains|Avatar: The Last Airbender Eternal|300|C||Basic Land - Plains|||({T}: Add {W}.)|
Plains|Avatar: The Last Airbender Eternal|301|C||Basic Land - Plains|||({T}: Add {W}.)|
Plains|Avatar: The Last Airbender Eternal|302|C||Basic Land - Plains|||({T}: Add {W}.)|
Plains|Avatar: The Last Airbender Eternal|303|C||Basic Land - Plains|||({T}: Add {W}.)|
Plains|Avatar: The Last Airbender Eternal|304|C||Basic Land - Plains|||({T}: Add {W}.)|