From 91a431f72c5ad9847b4e4f7a8e90e437bcbd4582 Mon Sep 17 00:00:00 2001 From: im-inuenc Date: Fri, 28 Mar 2025 01:37:54 +0100 Subject: [PATCH 01/49] Angelic Aberration bugfix --- Mage.Sets/src/mage/cards/a/AngelicAberration.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/AngelicAberration.java b/Mage.Sets/src/mage/cards/a/AngelicAberration.java index 465c3af5888..fdd11ac5842 100644 --- a/Mage.Sets/src/mage/cards/a/AngelicAberration.java +++ b/Mage.Sets/src/mage/cards/a/AngelicAberration.java @@ -17,8 +17,8 @@ import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.PowerPredicate; -import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.filter.predicate.mageobject.BasePowerPredicate; +import mage.filter.predicate.mageobject.BaseToughnessPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.EldraziAngelToken; @@ -70,8 +70,8 @@ class AngelicAberrationEffect extends OneShotEffect { static { filter.add(Predicates.or( - new PowerPredicate(ComparisonType.OR_LESS, 1), - new ToughnessPredicate(ComparisonType.OR_LESS, 1) + new BasePowerPredicate(ComparisonType.OR_LESS, 1), + new BaseToughnessPredicate(ComparisonType.OR_LESS, 1) )); } From ff3174877a9ba1d5ac127dd378c07a9ba04c0e24 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 28 Mar 2025 10:12:01 -0400 Subject: [PATCH 02/49] Remove gold from ObjectColor (#13470) * remove gold * rework Sword of Dungeons and Dragons, add comments about color * rework Call to Arms, most common color condition --- Mage.Sets/src/mage/cards/c/CallToArms.java | 89 ++++------- .../cards/s/SwordOfDungeonsAndDragons.java | 111 +++++--------- Mage/src/main/java/mage/ObjectColor.java | 139 ++++-------------- .../common/MostCommonColorCondition.java | 77 +++++----- .../game/permanent/token/DragonTokenGold.java | 10 +- 5 files changed, 133 insertions(+), 293 deletions(-) diff --git a/Mage.Sets/src/mage/cards/c/CallToArms.java b/Mage.Sets/src/mage/cards/c/CallToArms.java index a2c4ccb20e9..2b0bd85b998 100644 --- a/Mage.Sets/src/mage/cards/c/CallToArms.java +++ b/Mage.Sets/src/mage/cards/c/CallToArms.java @@ -1,6 +1,5 @@ package mage.cards.c; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.StateTriggeredAbility; @@ -8,8 +7,7 @@ import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.condition.common.MostCommonColorCondition; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.Effect; +import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.ChooseColorEffect; import mage.abilities.effects.common.ChooseOpponentEffect; import mage.abilities.effects.common.SacrificeSourceEffect; @@ -18,40 +16,45 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Layer; import mage.constants.Outcome; -import mage.constants.SubLayer; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class CallToArms extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + } + public CallToArms(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); // As Call to Arms enters the battlefield, choose a color and an opponent. - Ability ability = new AsEntersBattlefieldAbility( - new ChooseColorEffect(Outcome.Detriment) - ); - ability.addEffect(new ChooseOpponentEffect( - Outcome.Benefit - ).setText("and an opponent")); + Ability ability = new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Detriment)); + ability.addEffect(new ChooseOpponentEffect(Outcome.Benefit).setText("and an opponent")); this.addAbility(ability); // White creatures get +1/+1 as long as the chosen color is the most common color among nontoken permanents the chosen player controls but isn't tied for most common. - this.addAbility(new SimpleStaticAbility( - new CallToArmsEffect() - )); + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, false), + CallToArmsCondition.instance, "white creatures get +1/+1 as long as the chosen color " + + "is the most common color among nontoken permanents the chosen player controls but isn't tied for most common" + ))); // When the chosen color isn't the most common color among nontoken permanents the chosen player controls or is tied for most common, sacrifice Call to Arms. this.addAbility(new CallToArmsStateTriggeredAbility()); @@ -67,46 +70,17 @@ public final class CallToArms extends CardImpl { } } -class CallToArmsEffect extends ContinuousEffectImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("White creatures"); - - static { - filter.add(new ColorPredicate(ObjectColor.WHITE)); - } - - public CallToArmsEffect() { - super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, Outcome.Benefit); - staticText = "White creatures get +1/+1 as long as the chosen color " - + "is the most common color among nontoken permanents " - + "the chosen player controls but isn't tied for most common."; - } - - private CallToArmsEffect(final CallToArmsEffect effect) { - super(effect); - } - - @Override - public CallToArmsEffect copy() { - return new CallToArmsEffect(this); - } +enum CallToArmsCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); - UUID playerId = (UUID) game.getState().getValue(source.getSourceId() + ChooseOpponentEffect.VALUE_KEY); - if (permanent != null) { - Player opponent = game.getPlayer(playerId); - if (opponent != null) { - ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); - Condition condition = new MostCommonColorCondition(color, true, new ControllerIdPredicate(playerId)); - if (condition.apply(game, source)) { - Effect effect = new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, false); - return effect.apply(game, source); - } - } - } - return false; + Player opponent = game.getPlayer((UUID) game.getState().getValue(source.getSourceId() + ChooseOpponentEffect.VALUE_KEY)); + return permanent != null && opponent != null && new MostCommonColorCondition( + (ObjectColor) game.getState().getValue(permanent.getId() + "_color"), true, + Predicates.and(TokenPredicate.FALSE, new ControllerIdPredicate(opponent.getId())) + ).apply(game, source); } } @@ -129,17 +103,6 @@ class CallToArmsStateTriggeredAbility extends StateTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - Permanent permanent = game.getPermanent(getSourceId()); - UUID playerId = (UUID) game.getState().getValue(getSourceId() + ChooseOpponentEffect.VALUE_KEY); - if (permanent != null) { - Player opponent = game.getPlayer(playerId); - if (opponent != null) { - ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); - Condition condition = new MostCommonColorCondition(color, true, new ControllerIdPredicate(playerId)); - return !condition.apply(game, this); - } - } - return false; + return !CallToArmsCondition.instance.apply(game, this); } - } diff --git a/Mage.Sets/src/mage/cards/s/SwordOfDungeonsAndDragons.java b/Mage.Sets/src/mage/cards/s/SwordOfDungeonsAndDragons.java index 52ceb304a95..076482c618c 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfDungeonsAndDragons.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfDungeonsAndDragons.java @@ -1,15 +1,9 @@ - - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EquipAbility; @@ -18,50 +12,51 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AttachmentType; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.game.permanent.token.DragonTokenGold; import mage.players.Player; -import mage.target.common.TargetControlledCreaturePermanent; -import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; /** + * This creates a "gold" token which is represented as a creature with all colors + * as the color gold is not supported in the black-bordered game rules * * @author Saga */ public final class SwordOfDungeonsAndDragons extends CardImpl { - + private static final FilterCard filter = new FilterCard("Rogues and from Clerics"); - static {filter.add(Predicates.or( - SubType.ROGUE.getPredicate(), - SubType.CLERIC.getPredicate() - )); + + static { + filter.add(Predicates.or( + SubType.ROGUE.getPredicate(), + SubType.CLERIC.getPredicate() + )); } public SwordOfDungeonsAndDragons(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +2/+2 and has protection from Rogues and from Clerics. Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2)); - Effect effect = new GainAbilityAttachedEffect(new ProtectionAbility(filter), AttachmentType.EQUIPMENT); - effect.setText("and has protection from Rogues and from Clerics"); - ability.addEffect(effect); + ability.addEffect(new GainAbilityAttachedEffect( + new ProtectionAbility(filter), AttachmentType.EQUIPMENT + ).setText("and has protection from Rogues and from Clerics")); this.addAbility(ability); // Whenever equipped creature deals combat damage to a player, you create a 4/4 gold Dragon creature token with flying and roll a d20. If you roll a 20, repeat this process. - this.addAbility(new SwordOfDungeonsAndDragonsAbility()); + this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility( + new SwordOfDungeonsAndDragonsEffect(), "equipped creature", false + )); // Equip {2} - this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2), new TargetControlledCreaturePermanent(), false)); + this.addAbility(new EquipAbility(2)); } private SwordOfDungeonsAndDragons(final SwordOfDungeonsAndDragons card) { @@ -74,49 +69,12 @@ public final class SwordOfDungeonsAndDragons extends CardImpl { } } -class SwordOfDungeonsAndDragonsAbility extends TriggeredAbilityImpl { - - public SwordOfDungeonsAndDragonsAbility() { - super(Zone.BATTLEFIELD, new SwordOfDungeonsAndDragonsEffect(),false); - } - - private SwordOfDungeonsAndDragonsAbility(final SwordOfDungeonsAndDragonsAbility ability) { - super(ability); - } - - @Override - public SwordOfDungeonsAndDragonsAbility copy() { - return new SwordOfDungeonsAndDragonsAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event; - Permanent p = game.getPermanent(event.getSourceId()); - if (damageEvent.isCombatDamage() && p != null && p.getAttachments().contains(this.getSourceId())) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - } - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever equipped creature deals combat damage to a player, you create a 4/4 gold Dragon creature token with flying and roll a d20. If you roll a 20, repeat this process."; - } -} - class SwordOfDungeonsAndDragonsEffect extends OneShotEffect { - - public SwordOfDungeonsAndDragonsEffect() { + + SwordOfDungeonsAndDragonsEffect() { super(Outcome.Benefit); + staticText = "you create a 4/4 gold Dragon creature token with flying " + + "and roll a d20. If you roll a 20, repeat this process"; } private SwordOfDungeonsAndDragonsEffect(final SwordOfDungeonsAndDragonsEffect effect) { @@ -131,16 +89,15 @@ class SwordOfDungeonsAndDragonsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - int count = 1; - int amount = controller.rollDice(outcome, source, game, 20); - - while (amount == 20) { - count += 1; - amount = controller.rollDice(outcome, source, game, 20); - } - return new CreateTokenEffect(new DragonTokenGold(), count).apply(game, source); + if (controller == null) { + return false; } - return false; + for (int i = 0; i < 1000; i++) { // just in case loop goes too long + new DragonTokenGold().putOntoBattlefield(1, game, source); + if (controller.rollDice(outcome, source, game, 20) != 20) { + break; + } + } + return true; } } diff --git a/Mage/src/main/java/mage/ObjectColor.java b/Mage/src/main/java/mage/ObjectColor.java index e85e739ca24..b4caa2d6a13 100644 --- a/Mage/src/main/java/mage/ObjectColor.java +++ b/Mage/src/main/java/mage/ObjectColor.java @@ -5,10 +5,7 @@ import mage.constants.ColoredManaSymbol; import mage.util.Copyable; import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; +import java.util.*; public class ObjectColor implements Serializable, Copyable, Comparable { @@ -19,17 +16,13 @@ public class ObjectColor implements Serializable, Copyable, Compara public static final ObjectColor GREEN = new ObjectColor("G"); public static final ObjectColor COLORLESS = new ObjectColor(); - - public static final ObjectColor GOLD = new ObjectColor("O"); // Not multicolored - Sword of Dungeons & Dragons TODO: remove this, it shouldn't have been added - +private static final ListallColors= Arrays.asList(WHITE,BLUE,BLACK,RED,GREEN); private boolean white; private boolean blue; private boolean black; private boolean red; private boolean green; - private boolean gold; - public ObjectColor() { } @@ -51,10 +44,6 @@ public class ObjectColor implements Serializable, Copyable, Compara case 'G': green = true; break; - - case 'O': - gold = true; - break; } } } @@ -65,8 +54,6 @@ public class ObjectColor implements Serializable, Copyable, Compara black = color.black; red = color.red; green = color.green; - - gold = color.gold; } /** @@ -83,8 +70,6 @@ public class ObjectColor implements Serializable, Copyable, Compara newColor.black = black || other.black; newColor.red = red || other.red; newColor.green = green || other.green; - - newColor.gold = gold || other.gold; return newColor; } @@ -102,8 +87,6 @@ public class ObjectColor implements Serializable, Copyable, Compara newColor.black = black && other.black; newColor.red = red && other.red; newColor.green = green && other.green; - - newColor.gold = gold && other.gold; return newColor; } @@ -124,10 +107,6 @@ public class ObjectColor implements Serializable, Copyable, Compara if (red) { count++; } - - if (gold) { - count++; - } return count; } @@ -176,10 +155,6 @@ public class ObjectColor implements Serializable, Copyable, Compara if (colors.size() >= 2 && secondColor - firstColor >= 3) { Collections.swap(colors, 0, 1); } - - if (this.isGold()) { - colors.add(ObjectColor.GOLD); - } return colors; } @@ -189,8 +164,6 @@ public class ObjectColor implements Serializable, Copyable, Compara this.setGreen(color != null && color.isGreen()); this.setRed(color != null && color.isRed()); this.setWhite(color != null && color.isWhite()); - - this.setGold(color != null && color.isGold()); } public void addColor(ObjectColor color) { @@ -209,10 +182,6 @@ public class ObjectColor implements Serializable, Copyable, Compara if (color.isGreen()) { setGreen(true); } - - if (color.isGold()) { - setGold(true); - } } public boolean isColorless() { @@ -220,32 +189,26 @@ public class ObjectColor implements Serializable, Copyable, Compara } public boolean hasColor() { - return white || blue || black || red || green - || gold; + return white || blue || black || red || green; } public boolean isMulticolored() { if (isColorless()) { return false; } - if (white && (blue || black || red || green - || gold)) { - return true; + if (white) { + return blue || black || red || green; } - if (blue && (black || red || green - || gold)) { - return true; + if (blue) { + return black || red || green; } - if (black && (red || green - || gold)) { - return true; + if (black) { + return red || green; } - if (red && (green - || gold)) { - return true; + if (red) { + return green; } - return green - && gold; + return false; } public boolean isWhite() { @@ -288,14 +251,6 @@ public class ObjectColor implements Serializable, Copyable, Compara this.green = green; } - public boolean isGold() { - return gold; - } - - public void setGold(boolean gold) { - this.gold = gold; - } - @Override public String toString() { StringBuilder sb = new StringBuilder(5); @@ -314,36 +269,27 @@ public class ObjectColor implements Serializable, Copyable, Compara if (green) { sb.append('G'); } - - if (gold) { - sb.append('O'); - } return sb.toString(); } public String getDescription() { - if (getColorCount() > 1) { + if (isMulticolored()) { return "multicolored"; - } else { - if (white) { - return "white"; - } - if (blue) { - return "blue"; - } - if (black) { - return "black"; - } - if (red) { - return "red"; - } - if (green) { - return "green"; - } - - if (gold) { - return "gold"; - } + } + if (white) { + return "white"; + } + if (blue) { + return "blue"; + } + if (black) { + return "black"; + } + if (red) { + return "red"; + } + if (green) { + return "green"; } return "colorless"; } @@ -372,10 +318,6 @@ public class ObjectColor implements Serializable, Copyable, Compara if (test.green != this.green) { return false; } - if (test.gold != this.gold) { - return false; - } - return true; } @@ -387,8 +329,6 @@ public class ObjectColor implements Serializable, Copyable, Compara hash = 23 * hash + (this.black ? 1 : 0); hash = 23 * hash + (this.red ? 1 : 0); hash = 23 * hash + (this.green ? 1 : 0); - - hash = 23 * hash + (this.gold ? 1 : 0); return hash; } @@ -411,10 +351,6 @@ public class ObjectColor implements Serializable, Copyable, Compara if (color.green && this.green) { return true; } - - if (color.gold && this.gold) { - return true; - } return false; } @@ -422,8 +358,7 @@ public class ObjectColor implements Serializable, Copyable, Compara // 105.4. [...] “Multicolored” is not a color. Neither is “colorless.” return !color.isColorless() && (color.white && white || color.blue && blue || color.black && black - || color.red && red || color.green && green - || color.gold && gold); + || color.red && red || color.green && green); } @Override @@ -450,8 +385,6 @@ public class ObjectColor implements Serializable, Copyable, Compara o1 = 4; } else if (this.isWhite()) { o1 = 5; - } else if (this.isGold()) { - o1 = 6; } if (o.isMulticolored()) { @@ -468,8 +401,6 @@ public class ObjectColor implements Serializable, Copyable, Compara o2 = 4; } else if (o.isWhite()) { o2 = 5; - } else if (o.isGold()) { - o2 = 6; } return o1 - o2; @@ -482,7 +413,6 @@ public class ObjectColor implements Serializable, Copyable, Compara * @return null or */ public ColoredManaSymbol getOneColoredManaSymbol() { - if (isMulticolored()) { throw new IllegalStateException("Found multicolor object, but was waiting for simple color."); } @@ -503,19 +433,10 @@ public class ObjectColor implements Serializable, Copyable, Compara return ColoredManaSymbol.W; } - if (isGold()) { - return ColoredManaSymbol.O; - } return null; } public static List getAllColors() { - List colors = new ArrayList<>(); - colors.add(ObjectColor.WHITE); - colors.add(ObjectColor.BLUE); - colors.add(ObjectColor.BLACK); - colors.add(ObjectColor.RED); - colors.add(ObjectColor.GREEN); - return colors; + return allColors; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/MostCommonColorCondition.java b/Mage/src/main/java/mage/abilities/condition/common/MostCommonColorCondition.java index 3992edf70d1..98eb08a6c12 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/MostCommonColorCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/MostCommonColorCondition.java @@ -4,72 +4,65 @@ import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.predicate.Predicate; -import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Collectors; /** - * * @author TheElk801 */ public class MostCommonColorCondition implements Condition { protected final ObjectColor compareColor; protected final boolean isMono; - protected final Predicate predicate; + protected final FilterPermanent filter; public MostCommonColorCondition(ObjectColor color) { this(color, false, null); } - //Use this one if you don't want a tie for most common and want to restrict to a player (literally only Call to Arms) + // Use this one if you don't want a tie for most common and want to restrict to a player (literally only Call to Arms) public MostCommonColorCondition(ObjectColor color, boolean isMono, Predicate predicate) { this.compareColor = color; this.isMono = isMono; - this.predicate = predicate; + if (predicate == null) { + this.filter = StaticFilters.FILTER_PERMANENT; + } else { + this.filter = new FilterPermanent(); + this.filter.add(predicate); + } } @Override public boolean apply(Game game, Ability source) { - FilterPermanent[] colorFilters = new FilterPermanent[6]; - int i = 0; - for (ObjectColor color : ObjectColor.getAllColors()) { - colorFilters[i] = new FilterPermanent(); - colorFilters[i].add(new ColorPredicate(color)); - if (predicate != null) { - colorFilters[i].add(predicate); - } - i++; - } - int[] colorCounts = new int[6]; - i = 0; - for (ObjectColor color : ObjectColor.getAllColors()) { - colorFilters[i].add(new ColorPredicate(color)); - colorCounts[i] = game.getBattlefield().count(colorFilters[i], source.getControllerId(), source, game); - i++; - } - int max = 0; - for (i = 0; i < 5; i++) { - if (colorCounts[i] > max) { - max = colorCounts[i] * 1; + Map colorMap = new HashMap<>(); + for (Permanent permanent : game + .getBattlefield() + .getActivePermanents(filter, source.getControllerId(), source, game)) { + for (char c : permanent.getColor(game).toString().toCharArray()) { + colorMap.compute("" + c, CardUtil::setOrIncrementValue); } } - i = 0; - ObjectColor commonest = new ObjectColor(); - for (ObjectColor color : ObjectColor.getAllColors()) { - if (colorCounts[i] == max) { - commonest.addColor(color); - } - i++; - } - if (compareColor.shares(commonest)) { - if (isMono) { - return !commonest.isMulticolored(); - } else { - return true; - } - } - return false; + int most = colorMap + .values() + .stream() + .mapToInt(x -> x) + .max() + .orElse(0); + ObjectColor common = new ObjectColor( + colorMap.entrySet() + .stream() + .filter(e -> e.getValue() == most) + .map(Map.Entry::getKey) + .collect(Collectors.joining()) + ); + return common.shares(compareColor) && (!isMono || common.getColorCount() == 1); } @Override diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonTokenGold.java b/Mage/src/main/java/mage/game/permanent/token/DragonTokenGold.java index dce23cdf7d5..fbc243bebb6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DragonTokenGold.java +++ b/Mage/src/main/java/mage/game/permanent/token/DragonTokenGold.java @@ -6,6 +6,8 @@ import mage.constants.CardType; import mage.constants.SubType; /** + * This token is supposed to be "gold" but the game rules don't support gold as a color in black border + * * @author Saga */ public final class DragonTokenGold extends TokenImpl { @@ -13,7 +15,11 @@ public final class DragonTokenGold extends TokenImpl { public DragonTokenGold() { super("Dragon Token", "4/4 gold Dragon creature token with flying"); cardType.add(CardType.CREATURE); - color.setGold(true); + color.setWhite(true); + color.setBlue(true); + color.setBlack(true); + color.setRed(true); + color.setGreen(true); subtype.add(SubType.DRAGON); power = new MageInt(4); toughness = new MageInt(4); @@ -27,4 +33,4 @@ public final class DragonTokenGold extends TokenImpl { public DragonTokenGold copy() { return new DragonTokenGold(this); } -} \ No newline at end of file +} From b7bebfd93f54e3562e4211f187a131d03f50afbf Mon Sep 17 00:00:00 2001 From: spjspj Date: Sat, 29 Mar 2025 01:49:50 +1100 Subject: [PATCH 03/49] Update CardViewEDHPowerLevelComparator.java --- .../CardViewEDHPowerLevelComparator.java | 151 +++++++++++++++--- 1 file changed, 127 insertions(+), 24 deletions(-) diff --git a/Mage.Client/src/main/java/mage/client/util/comparators/CardViewEDHPowerLevelComparator.java b/Mage.Client/src/main/java/mage/client/util/comparators/CardViewEDHPowerLevelComparator.java index 9f70be139de..4e456b2155c 100644 --- a/Mage.Client/src/main/java/mage/client/util/comparators/CardViewEDHPowerLevelComparator.java +++ b/Mage.Client/src/main/java/mage/client/util/comparators/CardViewEDHPowerLevelComparator.java @@ -322,7 +322,6 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { if (cn.equals("acid rain") || cn.equals("agent of treachery") || cn.equals("anafenza, the foremost") - || cn.equals("ancient tomb") || cn.equals("animar, soul of element") || cn.equals("animate artifact") || cn.equals("apocalypse") @@ -352,7 +351,6 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("cabal coffers") || cn.equals("candelabra of tawnos") || cn.equals("captain sisay") - || cn.equals("card view") || cn.equals("cataclysm") || cn.equals("catastrophe") || cn.equals("celestial dawn") @@ -368,7 +366,6 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("contamination") || cn.equals("craterhoof behemoth") || cn.equals("cryptic gateway") - || cn.equals("cyclonic rift") || cn.equals("deadeye navigator") || cn.equals("death cloud") || cn.equals("decree of annihilation") @@ -377,6 +374,7 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("demonic consultation") || cn.equals("derevi, empyrial tactician") || cn.equals("devastation") + || cn.equals("dictate of erebos") || cn.equals("dig through time") || cn.equals("divine intervention") || cn.equals("dockside extortionist") @@ -385,34 +383,35 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("drannith magistrate") || cn.equals("dross scorpion") || cn.equals("earthcraft") + || cn.equals("edgar markov") || cn.equals("edric, spymaster of trest") || cn.equals("elesh norn, grand cenobite") + || cn.equals("elesh norn, mother of machines") || cn.equals("embargo") || cn.equals("emrakul, the promised end") || cn.equals("enter the infinite") || cn.equals("entomb") || cn.equals("epicenter") || cn.equals("erratic portal") - || cn.equals("expropriate") || cn.equals("exquisite blood") || cn.equals("fall of the thran") - || cn.equals("fierce guardianship") + || cn.equals("farewell") + || cn.equals("flashfires") || cn.equals("food chain") || cn.equals("force of negation") - || cn.equals("force of will") || cn.equals("future sight") || cn.equals("gaddock teeg") - || cn.equals("gaea's cradle") || cn.equals("genesis chamber") || cn.equals("ghave, guru of spores") || cn.equals("gilded drake") || cn.equals("glenn, the voice of calm") || cn.equals("global ruin") || cn.equals("golos, tireless pilgrim") - || cn.equals("grand arbiter augustin iv") || cn.equals("grave pact") || cn.equals("grave titan") || cn.equals("great whale") + || cn.equals("gregor, shrewd magistrate") + || cn.equals("greymond, avacyn's stalwart") || cn.equals("grim monolith") || cn.equals("grip of chaos") || cn.equals("gush") @@ -421,21 +420,23 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("hokori, dust drinker") || cn.equals("humility") || cn.equals("impending disaster") - || cn.equals("imperial seal") || cn.equals("intruder alarm") || cn.equals("invoke prejudice") || cn.equals("iona, shield of emeria") - || cn.equals("jin-gitaxias, core augur") + || cn.equals("jeweled lotus") + || cn.equals("jin-gitaxias, progress tyrant") || cn.equals("jokulhaups") || cn.equals("kaalia of the vast") || cn.equals("karador, ghost chieftain") || cn.equals("karakas") || cn.equals("karn, silver golem") + || cn.equals("karn, the great creator") || cn.equals("kataki, war's wage") || cn.equals("keldon firebombers") || cn.equals("kiki-jiki, mirror breaker") - || cn.equals("kinnan, bonder prodigy") || cn.equals("knowledge pool") + || cn.equals("koma, cosmos serpent") + || cn.equals("korvold, fae-cursed king") || cn.equals("kozilek, butcher of truth") || cn.equals("krark-clan ironworks") || cn.equals("krenko, mob boss") @@ -452,10 +453,10 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("maelstrom wanderer") || cn.equals("magister sphinx") || cn.equals("malfegor") + || cn.equals("malik, grim manipulator") || cn.equals("mana breach") || cn.equals("mana crypt") || cn.equals("mana drain") - || cn.equals("mana vault") || cn.equals("mana vortex") || cn.equals("master of cruelties") || cn.equals("memnarch") @@ -468,6 +469,7 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("minion reflector") || cn.equals("mycosynth lattice") || cn.equals("myr turbine") + || cn.equals("nadu, winged wisdom") || cn.equals("narset, enlightened master") || cn.equals("narset, parter of veils") || cn.equals("nath of the gilt-leaf") @@ -487,8 +489,8 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("oloro, ageless ascetic") || cn.equals("omniscience") || cn.equals("opalescence") - || cn.equals("opposition agent") || cn.equals("oppression") + || cn.equals("orcish bowmasters") || cn.equals("ornithopter") || cn.equals("overwhelming splendor") || cn.equals("palinchron") @@ -504,7 +506,6 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("purphoros, god of the forge") || cn.equals("ravages of war") || cn.equals("reclamation sage") - || cn.equals("rhystic study") || cn.equals("rick, steadfast leader") || cn.equals("rings of brighthearth") || cn.equals("rising waters") @@ -515,12 +516,11 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("seedborn muse") || cn.equals("sen triplets") || cn.equals("sensei's divining top") - || cn.equals("serra's sanctum") + || cn.equals("sheoldred, the apocalypse") || cn.equals("sheoldred, whispering one") || cn.equals("sire of insanity") || cn.equals("skithiryx, the blight dragon") || cn.equals("smokestack") - || cn.equals("smothering tithe") || cn.equals("sol ring") || cn.equals("sorin markov") || cn.equals("splinter twin") @@ -532,8 +532,6 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("storm cauldron") || cn.equals("strip mine") || cn.equals("sunder") - || cn.equals("survival of the fittest") - || cn.equals("table view") || cn.equals("tainted aether") || cn.equals("tangle wire") || cn.equals("tectonic break") @@ -543,21 +541,19 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("teferi, master of time") || cn.equals("teferi, time raveler") || cn.equals("temporal manipulation") - || cn.equals("tergrid, god of fright") - || cn.equals("text view") || cn.equals("tezzeret the seeker") - || cn.equals("thassa's oracle") || cn.equals("the chain veil") - || cn.equals("the tabernacle at pendrell vale") || cn.equals("thieves' auction") || cn.equals("thoughts of ruin") || cn.equals("thrasios, triton hero") + || cn.equals("time sieve") || cn.equals("time stretch") || cn.equals("time warp") || cn.equals("tinker") || cn.equals("tooth and nail") || cn.equals("torment of hailfire") || cn.equals("torpor orb") + || cn.equals("toxrill, the corrosive") || cn.equals("training grounds") || cn.equals("treasure cruise") || cn.equals("triskelavus") @@ -566,18 +562,20 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("turnabout") || cn.equals("ugin, the spirit dragon") || cn.equals("ulamog, the ceaseless hunger") + || cn.equals("ulamog, the defiler") || cn.equals("ulamog, the infinite gyre") || cn.equals("umbral mantle") || cn.equals("urabrask the hidden") - || cn.equals("urza, lord high artificer") || cn.equals("uyo, silent prophet") || cn.equals("void winnower") || cn.equals("voltaic key") - || cn.equals("vorinclex, voice of hunger") + || cn.equals("vorinclex, monstrous raider") || cn.equals("wake of destruction") || cn.equals("warp world") + || cn.equals("winter moon") || cn.equals("winter orb") || cn.equals("workhorse") + || cn.equals("worldfire") || cn.equals("worldgorger dragon") || cn.equals("worthy cause") || cn.equals("xanathar, guild kingpin") @@ -586,6 +584,111 @@ public class CardViewEDHPowerLevelComparator implements CardViewComparator { || cn.equals("zur the enchanter")) { thisMaxPower = Math.max(thisMaxPower, 12); } + + // Parts of infinite combos + if (cn.equals("animate artifact") || cn.equals("animar, soul of element") + || cn.equals("archaeomancer") + || cn.equals("ashnod's altar") || cn.equals("azami, lady of scrolls") + || cn.equals("aura flux") + || cn.equals("basalt monolith") || cn.equals("brago, king eternal") + || cn.equals("candelabra of tawnos") || cn.equals("cephalid aristocrat") + || cn.equals("cephalid illusionist") || cn.equals("changeling berserker") + || cn.equals("consecrated sphinx") + || cn.equals("cyclonic rift") + || cn.equals("the chain veil") + || cn.equals("cinderhaze wretch") || cn.equals("cryptic gateway") + || cn.equals("deadeye navigator") || cn.equals("derevi, empyrial tactician") + || cn.equals("doubling season") || cn.equals("dross scorpion") + || cn.equals("earthcraft") || cn.equals("erratic portal") + || cn.equals("enter the infinite") || cn.equals("omniscience") + || cn.equals("exquisite blood") || cn.equals("future sight") + || cn.equals("genesis chamber") + || cn.equals("ghave, guru of spores") + || cn.equals("grave pact") + || cn.equals("grave titan") || cn.equals("great whale") + || cn.equals("grim monolith") || cn.equals("gush") + || cn.equals("hellkite charger") || cn.equals("intruder alarm") + || cn.equals("helm of obedience") + || cn.equals("hermit druid") + || cn.equals("humility") + || cn.equals("iona, shield of emeria") + || cn.equals("karn, silver golem") || cn.equals("kiki-jiki, mirror breaker") + || cn.equals("krark-clan ironworks") || cn.equals("krenko, mob boss") + || cn.equals("krosan restorer") || cn.equals("laboratory maniac") + || cn.equals("leonin relic-warder") || cn.equals("leyline of the void") + || cn.equals("memnarch") + || cn.equals("meren of clan nel toth") || cn.equals("mikaeus, the unhallowed") + || cn.equals("mindcrank") || cn.equals("mindslaver") + || cn.equals("minion reflector") || cn.equals("mycosynth lattice") + || cn.equals("myr turbine") || cn.equals("narset, enlightened master") + || cn.equals("nekusar, the mindrazer") || cn.equals("norin the wary") + || cn.equals("notion thief") + || cn.equals("opalescence") || cn.equals("ornithopter") + || cn.equals("paradox engine") + || cn.equals("purphoros, god of the forge") + || cn.equals("peregrine drake") || cn.equals("palinchron") + || cn.equals("planar portal") || cn.equals("power artifact") + || cn.equals("rings of brighthearth") || cn.equals("rite of replication") + || cn.equals("sanguine bond") || cn.equals("sensei's divining top") + || cn.equals("splinter twin") || cn.equals("stony silence") + || cn.equals("sunder") + || cn.equals("storm cauldron") || cn.equals("teferi's puzzle box") + || cn.equals("tangle wire") + || cn.equals("teferi, mage of zhalfir") + || cn.equals("tezzeret the seeker") || cn.equals("time stretch") + || cn.equals("time warp") || cn.equals("training grounds") + || cn.equals("triskelavus") || cn.equals("triskelion") + || cn.equals("turnabout") || cn.equals("umbral mantle") + || cn.equals("uyo, silent prophet") || cn.equals("voltaic key") + || cn.equals("workhorse") || cn.equals("worldgorger dragon") + || cn.equals("worthy cause") || cn.equals("yawgmoth's will") + || cn.equals("zealous conscripts")) { + thisMaxPower = Math.max(thisMaxPower, 15); + } + + // Game changers + if (cn.equals("ad nauseam") + || cn.equals("ancient tomb") + || cn.equals("bolas's citadel") + || cn.equals("chrome mox") + || cn.equals("cyclonic rift") + || cn.equals("demonic tutor") + || cn.equals("drannith magistrate") + || cn.equals("enlightened tutor") + || cn.equals("expropriate") + || cn.equals("fierce guardianship") + || cn.equals("force of will") + || cn.equals("gaea's cradle") + || cn.equals("glacial chasm") + || cn.equals("grand arbiter augustin iv") + || cn.equals("grim monolith") + || cn.equals("imperial seal") + || cn.equals("jeska's will") + || cn.equals("jin-gitaxias, core augur") + || cn.equals("kinnan, bonder prodigy") + || cn.equals("lion's eye diamond") + || cn.equals("mana vault") + || cn.equals("mox diamond") + || cn.equals("mystical tutor") + || cn.equals("opposition agent") + || cn.equals("rhystic study") + || cn.equals("serra's sanctum") + || cn.equals("smothering tithe") + || cn.equals("survival of the fittest") + || cn.equals("tergrid, god of fright") + || cn.equals("thassa's oracle") + || cn.equals("the one ring") + || cn.equals("the tabernacle at pendrell vale") + || cn.equals("trinisphere") + || cn.equals("trouble in pairs") + || cn.equals("underworld breach") + || cn.equals("urza, lord high artificer") + || cn.equals("vampiric tutor") + || cn.equals("vorinclex, voice of hunger") + || cn.equals("winota, joiner of forces") + || cn.equals("yuriko, the tiger's shadow")) { + thisMaxPower = Math.max(thisMaxPower, 20); + } return thisMaxPower; } From a3592ad39147b324448c42bf1b84ceec4665b175 Mon Sep 17 00:00:00 2001 From: spjspj Date: Sat, 29 Mar 2025 02:02:50 +1100 Subject: [PATCH 04/49] Update edh power level calculations Update the edh power level calculators with the game changers and latest salty EDHREC cards (2024) --- .../src/mage/deck/AbstractCommander.java | 374 +++++++++++------- 1 file changed, 230 insertions(+), 144 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java index 0b6165ae087..332be55033c 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java @@ -581,85 +581,271 @@ public abstract class AbstractCommander extends Constructed { } String cn = card.getName().toLowerCase(Locale.ENGLISH); - if (cn.equals("ancient tomb") + // Saltiest cards (edhrec) + if (cn.equals("acid rain") + || cn.equals("agent of treachery") || cn.equals("anafenza, the foremost") + || cn.equals("animar, soul of element") + || cn.equals("animate artifact") + || cn.equals("apocalypse") + || cn.equals("archaeomancer") || cn.equals("arcum dagsson") || cn.equals("armageddon") + || cn.equals("ashnod's altar") + || cn.equals("atraxa, praetors' voice") + || cn.equals("aura flux") || cn.equals("aura shards") + || cn.equals("avacyn, angel of hope") || cn.equals("azami, lady of scrolls") || cn.equals("azusa, lost but seeking") || cn.equals("back to basics") || cn.equals("bane of progress") || cn.equals("basalt monolith") + || cn.equals("bend or break") || cn.equals("blightsteel collossus") + || cn.equals("blightsteel colossus") || cn.equals("blood moon") + || cn.equals("boil") + || cn.equals("boiling seas") + || cn.equals("brago, king eternal") || cn.equals("braids, cabal minion") + || cn.equals("bribery") + || cn.equals("burning sands") || cn.equals("cabal coffers") + || cn.equals("candelabra of tawnos") || cn.equals("captain sisay") + || cn.equals("cataclysm") + || cn.equals("catastrophe") || cn.equals("celestial dawn") + || cn.equals("cephalid aristocrat") + || cn.equals("cephalid illusionist") + || cn.equals("changeling berserker") || cn.equals("child of alara") + || cn.equals("chulane, teller of tales") + || cn.equals("cinderhaze wretch") || cn.equals("coalition relic") + || cn.equals("confusion in the ranks") + || cn.equals("consecrated sphinx") + || cn.equals("contamination") || cn.equals("craterhoof behemoth") + || cn.equals("cryptic gateway") + || cn.equals("deadeye navigator") + || cn.equals("death cloud") + || cn.equals("decree of annihilation") + || cn.equals("decree of silence") || cn.equals("deepglow skate") + || cn.equals("demonic consultation") || cn.equals("derevi, empyrial tactician") + || cn.equals("devastation") + || cn.equals("dictate of erebos") || cn.equals("dig through time") + || cn.equals("divine intervention") + || cn.equals("dockside extortionist") + || cn.equals("doomsday") + || cn.equals("doubling season") + || cn.equals("drannith magistrate") + || cn.equals("dross scorpion") + || cn.equals("earthcraft") + || cn.equals("edgar markov") || cn.equals("edric, spymaster of trest") || cn.equals("elesh norn, grand cenobite") + || cn.equals("elesh norn, mother of machines") + || cn.equals("embargo") + || cn.equals("emrakul, the promised end") + || cn.equals("enter the infinite") || cn.equals("entomb") - || cn.equals("force of will") + || cn.equals("epicenter") + || cn.equals("erratic portal") + || cn.equals("exquisite blood") + || cn.equals("fall of the thran") + || cn.equals("farewell") + || cn.equals("flashfires") || cn.equals("food chain") + || cn.equals("force of negation") + || cn.equals("future sight") || cn.equals("gaddock teeg") - || cn.equals("gaea's cradle") - || cn.equals("grand arbiter augustin iv") - || cn.equals("grim monolith") + || cn.equals("genesis chamber") + || cn.equals("ghave, guru of spores") + || cn.equals("gilded drake") + || cn.equals("glenn, the voice of calm") + || cn.equals("global ruin") + || cn.equals("golos, tireless pilgrim") + || cn.equals("grave pact") + || cn.equals("grave titan") + || cn.equals("great whale") + || cn.equals("gregor, shrewd magistrate") + || cn.equals("greymond, avacyn's stalwart") + || cn.equals("grip of chaos") + || cn.equals("gush") + || cn.equals("hellkite charger") || cn.equals("hermit druid") || cn.equals("hokori, dust drinker") || cn.equals("humility") - || cn.equals("imperial seal") + || cn.equals("impending disaster") + || cn.equals("intruder alarm") + || cn.equals("invoke prejudice") || cn.equals("iona, shield of emeria") - || cn.equals("jin-gitaxias, core augur") + || cn.equals("jeweled lotus") + || cn.equals("jin-gitaxias, progress tyrant") + || cn.equals("jokulhaups") + || cn.equals("kaalia of the vast") || cn.equals("karador, ghost chieftain") || cn.equals("karakas") + || cn.equals("karn, silver golem") + || cn.equals("karn, the great creator") || cn.equals("kataki, war's wage") + || cn.equals("keldon firebombers") + || cn.equals("kiki-jiki, mirror breaker") || cn.equals("knowledge pool") + || cn.equals("koma, cosmos serpent") + || cn.equals("korvold, fae-cursed king") + || cn.equals("kozilek, butcher of truth") + || cn.equals("krark-clan ironworks") + || cn.equals("krenko, mob boss") + || cn.equals("krosan restorer") + || cn.equals("laboratory maniac") + || cn.equals("land equilibrium") + || cn.equals("leonin relic-warder") + || cn.equals("leovold, emissary of trest") + || cn.equals("leyline of the void") || cn.equals("linvala, keeper of silence") || cn.equals("living death") || cn.equals("llawan, cephalid empress") || cn.equals("loyal retainers") || cn.equals("maelstrom wanderer") + || cn.equals("magister sphinx") || cn.equals("malfegor") - || cn.equals("master of cruelties") + || cn.equals("malik, grim manipulator") + || cn.equals("mana breach") || cn.equals("mana crypt") || cn.equals("mana drain") - || cn.equals("mana vault") + || cn.equals("mana vortex") + || cn.equals("master of cruelties") + || cn.equals("memnarch") + || cn.equals("meren of clan nel toth") || cn.equals("michiko konda, truth seeker") + || cn.equals("mikaeus the unhallowed") + || cn.equals("mikaeus, the unhallowed") + || cn.equals("mindcrank") + || cn.equals("mindslaver") + || cn.equals("minion reflector") + || cn.equals("mycosynth lattice") + || cn.equals("myr turbine") + || cn.equals("nadu, winged wisdom") + || cn.equals("narset, enlightened master") + || cn.equals("narset, parter of veils") || cn.equals("nath of the gilt-leaf") || cn.equals("natural order") || cn.equals("necrotic ooze") + || cn.equals("negan, the cold-blooded") + || cn.equals("nekusar, the mindrazer") + || cn.equals("nether void") + || cn.equals("nexus of fate") || cn.equals("nicol bolas") + || cn.equals("norin the wary") + || cn.equals("notion thief") || cn.equals("numot, the devastator") || cn.equals("oath of druids") + || cn.equals("obliterate") + || cn.equals("oko, thief of crowns") + || cn.equals("oloro, ageless ascetic") + || cn.equals("omniscience") + || cn.equals("opalescence") + || cn.equals("oppression") + || cn.equals("orcish bowmasters") + || cn.equals("ornithopter") + || cn.equals("overwhelming splendor") + || cn.equals("palinchron") + || cn.equals("paradox engine") || cn.equals("pattern of rebirth") + || cn.equals("peregrine drake") + || cn.equals("planar portal") + || cn.equals("possessed portal") + || cn.equals("power artifact") + || cn.equals("price of glory") + || cn.equals("prossh, skyraider of kher") || cn.equals("protean hulk") || cn.equals("purphoros, god of the forge") || cn.equals("ravages of war") || cn.equals("reclamation sage") + || cn.equals("rick, steadfast leader") + || cn.equals("rings of brighthearth") + || cn.equals("rising waters") + || cn.equals("rite of replication") + || cn.equals("ruination") + || cn.equals("sanguine bond") + || cn.equals("scrambleverse") + || cn.equals("seedborn muse") || cn.equals("sen triplets") - || cn.equals("serra's sanctum") + || cn.equals("sensei's divining top") + || cn.equals("sheoldred, the apocalypse") || cn.equals("sheoldred, whispering one") + || cn.equals("sire of insanity") + || cn.equals("skithiryx, the blight dragon") + || cn.equals("smokestack") || cn.equals("sol ring") + || cn.equals("sorin markov") + || cn.equals("splinter twin") || cn.equals("spore frog") || cn.equals("stasis") + || cn.equals("static orb") + || cn.equals("stony silence") + || cn.equals("storage matrix") + || cn.equals("storm cauldron") || cn.equals("strip mine") - || cn.equals("the tabernacle at pendrell vale") + || cn.equals("sunder") + || cn.equals("tainted aether") + || cn.equals("tangle wire") + || cn.equals("tectonic break") + || cn.equals("teferi's protection") + || cn.equals("teferi's puzzle box") + || cn.equals("teferi, mage of zhalfir") + || cn.equals("teferi, master of time") + || cn.equals("teferi, time raveler") + || cn.equals("temporal manipulation") + || cn.equals("tezzeret the seeker") + || cn.equals("the chain veil") + || cn.equals("thieves' auction") + || cn.equals("thoughts of ruin") + || cn.equals("thrasios, triton hero") + || cn.equals("time sieve") + || cn.equals("time stretch") + || cn.equals("time warp") || cn.equals("tinker") + || cn.equals("tooth and nail") + || cn.equals("torment of hailfire") + || cn.equals("torpor orb") + || cn.equals("toxrill, the corrosive") + || cn.equals("training grounds") || cn.equals("treasure cruise") + || cn.equals("triskelavus") + || cn.equals("triskelion") + || cn.equals("triumph of the hordes") + || cn.equals("turnabout") + || cn.equals("ugin, the spirit dragon") + || cn.equals("ulamog, the ceaseless hunger") + || cn.equals("ulamog, the defiler") + || cn.equals("ulamog, the infinite gyre") + || cn.equals("umbral mantle") || cn.equals("urabrask the hidden") - || cn.equals("vorinclex, voice of hunger") + || cn.equals("uyo, silent prophet") + || cn.equals("void winnower") + || cn.equals("voltaic key") + || cn.equals("vorinclex, monstrous raider") + || cn.equals("wake of destruction") + || cn.equals("warp world") + || cn.equals("winter moon") || cn.equals("winter orb") + || cn.equals("workhorse") + || cn.equals("worldfire") + || cn.equals("worldgorger dragon") + || cn.equals("worthy cause") + || cn.equals("xanathar, guild kingpin") + || cn.equals("yawgmoth's will") + || cn.equals("zealous conscripts") || cn.equals("zur the enchanter")) { - thisMaxPower = Math.max(thisMaxPower, 12); - } + thisMaxPower = Math.max(thisMaxPower, 12); + } // Parts of infinite combos if (cn.equals("animate artifact") || cn.equals("animar, soul of element") @@ -719,154 +905,54 @@ public abstract class AbstractCommander extends Constructed { || cn.equals("workhorse") || cn.equals("worldgorger dragon") || cn.equals("worthy cause") || cn.equals("yawgmoth's will") || cn.equals("zealous conscripts")) { - thisMaxPower = Math.max(thisMaxPower, 15); - numberInfinitePieces++; - } - - // Saltiest cards (edhrec) - if (cn.equals("acid rain") - || cn.equals("agent of treachery") - || cn.equals("apocalypse") - || cn.equals("armageddon") - || cn.equals("atraxa, praetors' voice") - || cn.equals("aura shards") - || cn.equals("avacyn, angel of hope") - || cn.equals("back to basics") - || cn.equals("bend or break") - || cn.equals("blightsteel colossus") - || cn.equals("blood moon") - || cn.equals("boil") - || cn.equals("boiling seas") - || cn.equals("bribery") - || cn.equals("burning sands") - || cn.equals("card view") - || cn.equals("cataclysm") - || cn.equals("catastrophe") - || cn.equals("chulane, teller of tales") - || cn.equals("confusion in the ranks") - || cn.equals("consecrated sphinx") - || cn.equals("contamination") - || cn.equals("craterhoof behemoth") + thisMaxPower = Math.max(thisMaxPower, 15); + numberInfinitePieces++; + } + + // Game changers + if (cn.equals("ad nauseam") + || cn.equals("ancient tomb") + || cn.equals("bolas's citadel") + || cn.equals("chrome mox") || cn.equals("cyclonic rift") - || cn.equals("death cloud") - || cn.equals("decree of annihilation") - || cn.equals("decree of silence") - || cn.equals("demonic consultation") - || cn.equals("derevi, empyrial tactician") - || cn.equals("devastation") - || cn.equals("divine intervention") - || cn.equals("dockside extortionist") - || cn.equals("doomsday") - || cn.equals("doubling season") + || cn.equals("demonic tutor") || cn.equals("drannith magistrate") - || cn.equals("elesh norn, grand cenobite") - || cn.equals("embargo") - || cn.equals("emrakul, the promised end") - || cn.equals("epicenter") + || cn.equals("enlightened tutor") || cn.equals("expropriate") - || cn.equals("fall of the thran") || cn.equals("fierce guardianship") - || cn.equals("food chain") - || cn.equals("force of negation") || cn.equals("force of will") - || cn.equals("gaddock teeg") || cn.equals("gaea's cradle") - || cn.equals("gilded drake") - || cn.equals("glenn, the voice of calm") - || cn.equals("global ruin") - || cn.equals("golos, tireless pilgrim") + || cn.equals("glacial chasm") || cn.equals("grand arbiter augustin iv") - || cn.equals("grip of chaos") - || cn.equals("hokori, dust drinker") - || cn.equals("humility") - || cn.equals("impending disaster") - || cn.equals("invoke prejudice") - || cn.equals("iona, shield of emeria") + || cn.equals("grim monolith") + || cn.equals("imperial seal") + || cn.equals("jeska's will") || cn.equals("jin-gitaxias, core augur") - || cn.equals("jokulhaups") - || cn.equals("keldon firebombers") || cn.equals("kinnan, bonder prodigy") - || cn.equals("kozilek, butcher of truth") - || cn.equals("land equilibrium") - || cn.equals("linvala, keeper of silence") - || cn.equals("magister sphinx") - || cn.equals("mana breach") - || cn.equals("mana crypt") - || cn.equals("mana drain") - || cn.equals("mana vortex") - || cn.equals("mindslaver") - || cn.equals("narset, enlightened master") - || cn.equals("narset, parter of veils") - || cn.equals("negan, the cold-blooded") - || cn.equals("nether void") - || cn.equals("nexus of fate") - || cn.equals("notion thief") - || cn.equals("obliterate") - || cn.equals("oko, thief of crowns") - || cn.equals("oloro, ageless ascetic") - || cn.equals("omniscience") + || cn.equals("lion's eye diamond") + || cn.equals("mana vault") + || cn.equals("mox diamond") + || cn.equals("mystical tutor") || cn.equals("opposition agent") - || cn.equals("oppression") - || cn.equals("overwhelming splendor") - || cn.equals("palinchron") - || cn.equals("paradox engine") - || cn.equals("possessed portal") - || cn.equals("price of glory") - || cn.equals("protean hulk") - || cn.equals("ravages of war") || cn.equals("rhystic study") - || cn.equals("rick, steadfast leader") - || cn.equals("rising waters") - || cn.equals("ruination") - || cn.equals("scrambleverse") - || cn.equals("seedborn muse") - || cn.equals("sen triplets") - || cn.equals("sire of insanity") - || cn.equals("skithiryx, the blight dragon") - || cn.equals("smokestack") + || cn.equals("serra's sanctum") || cn.equals("smothering tithe") - || cn.equals("sorin markov") - || cn.equals("stasis") - || cn.equals("static orb") - || cn.equals("storage matrix") - || cn.equals("sunder") || cn.equals("survival of the fittest") - || cn.equals("table view") - || cn.equals("tainted aether") - || cn.equals("tectonic break") - || cn.equals("teferi's protection") - || cn.equals("teferi, master of time") - || cn.equals("teferi, time raveler") - || cn.equals("temporal manipulation") || cn.equals("tergrid, god of fright") - || cn.equals("text view") || cn.equals("thassa's oracle") + || cn.equals("the one ring") || cn.equals("the tabernacle at pendrell vale") - || cn.equals("thieves' auction") - || cn.equals("thoughts of ruin") - || cn.equals("thrasios, triton hero") - || cn.equals("time stretch") - || cn.equals("time warp") - || cn.equals("tooth and nail") - || cn.equals("torment of hailfire") - || cn.equals("torpor orb") - || cn.equals("triumph of the hordes") - || cn.equals("ugin, the spirit dragon") - || cn.equals("ulamog, the ceaseless hunger") - || cn.equals("ulamog, the infinite gyre") + || cn.equals("trinisphere") + || cn.equals("trouble in pairs") + || cn.equals("underworld breach") || cn.equals("urza, lord high artificer") - || cn.equals("void winnower") + || cn.equals("vampiric tutor") || cn.equals("vorinclex, voice of hunger") - || cn.equals("wake of destruction") - || cn.equals("warp world") - || cn.equals("winter orb") - || cn.equals("xanathar, guild kingpin") - || cn.equals("zur the enchanter")) { - thisMaxPower = Math.max(thisMaxPower, 15); - } - edhPowerLevel += thisMaxPower; - } - + || cn.equals("winota, joiner of forces") + || cn.equals("yuriko, the tiger's shadow")) { + thisMaxPower = Math.max(thisMaxPower, 20); + } + ObjectColor color = null; for (Card commander : deck.getSideboard()) { int thisMaxPower = 0; From 5d36650ca61ba5d9ad13ca847f86ab3788c91b20 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 10:23:35 -0400 Subject: [PATCH 05/49] [TDM] Implement Unsparing Boltcaster --- .../src/mage/cards/u/UnsparingBoltcaster.java | 52 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + Utils/mtg-cards-data.txt | 1 + 3 files changed, 54 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/u/UnsparingBoltcaster.java diff --git a/Mage.Sets/src/mage/cards/u/UnsparingBoltcaster.java b/Mage.Sets/src/mage/cards/u/UnsparingBoltcaster.java new file mode 100644 index 00000000000..b9bfc685171 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnsparingBoltcaster.java @@ -0,0 +1,52 @@ +package mage.cards.u; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.predicate.permanent.WasDealtDamageThisTurnPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnsparingBoltcaster extends CardImpl { + + private static final FilterPermanent filter + = new FilterOpponentsCreaturePermanent("creature an opponent controls that was dealt damage this turn"); + + static { + filter.add(WasDealtDamageThisTurnPredicate.instance); + } + + public UnsparingBoltcaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When this creature enters, it deals 5 damage to target creature an opponent controls that was dealt damage this turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(5)); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private UnsparingBoltcaster(final UnsparingBoltcaster card) { + super(card); + } + + @Override + public UnsparingBoltcaster copy() { + return new UnsparingBoltcaster(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index af45f5fbec6..305bedd18c7 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -158,6 +158,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Unending Whisper", 62, Rarity.COMMON, mage.cards.u.UnendingWhisper.class)); cards.add(new SetCardInfo("United Battlefront", 32, Rarity.RARE, mage.cards.u.UnitedBattlefront.class)); cards.add(new SetCardInfo("Unrooted Ancestor", 96, Rarity.UNCOMMON, mage.cards.u.UnrootedAncestor.class)); + cards.add(new SetCardInfo("Unsparing Boltcaster", 130, Rarity.UNCOMMON, mage.cards.u.UnsparingBoltcaster.class)); cards.add(new SetCardInfo("Ureni's Rebuff", 63, Rarity.UNCOMMON, mage.cards.u.UrenisRebuff.class)); cards.add(new SetCardInfo("Venerated Stormsinger", 97, Rarity.UNCOMMON, mage.cards.v.VeneratedStormsinger.class)); cards.add(new SetCardInfo("Voice of Victory", 33, Rarity.RARE, mage.cards.v.VoiceOfVictory.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index d0c4db18293..92dc2faa708 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -57305,6 +57305,7 @@ Summit Intimidator|Tarkir: Dragonstorm|125|C|{3}{R}|Creature - Yeti|4|3|Reach$Wh Sunset Strikemaster|Tarkir: Dragonstorm|126|U|{1}{R}|Creature - Human Monk|3|1|{T}: Add {R}.${2}{R}, {T}, Sacrifice this creature: It deals 6 damage to target creature with flying.| Tersa Lightshatter|Tarkir: Dragonstorm|127|R|{2}{R}|Legendary Creature - Orc Wizard|3|3|Haste$When Tersa Lightshatter enters, discard up to two cards, then draw that many cards.$Whenever Tersa Lightshatter attacks, if there are seven or more cards in your graveyard, exile a card at random from your graveyard. You may play that card this turn.| Underfoot Underdogs|Tarkir: Dragonstorm|129|C|{2}{R}|Creature - Goblin Warrior|1|2|When this creature enters, create a 1/1 red Goblin creature token.${1}, {T}: Target creature you control with power 2 or less can't be blocked this turn.| +Unsparing Boltcaster|Tarkir: Dragonstorm|130|U|{2}{R}|Creature - Ogre Wizard|3|3|When this creature enters, it deals 5 damage to target creature an opponent controls that was dealt damage this turn.| War Effort|Tarkir: Dragonstorm|131|U|{3}{R}|Enchantment|||Creatures you control get +1/+0.$Whenever you attack, create a 1/1 red Warrior creature token that's tapped and attacking. Sacrifice it at the beginning of the next end step.| Zurgo's Vanguard|Tarkir: Dragonstorm|133|U|{2}{R}|Creature - Dog Soldier|*|3|Mobilize 1$This creature's power is equal to the number of creatures you control.| Attuned Hunter|Tarkir: Dragonstorm|135|U|{2}{G}|Creature - Human Ranger|3|3|Trample$Whenever one or more cards leave your graveyard during your turn, put a +1/+1 counter on this creature.| From 796c9a8492b4a236a5ca8bf0a0392c779fdac57a Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 14:32:14 -0400 Subject: [PATCH 06/49] [TDM] Implement Roar of Endless Song --- .../src/mage/cards/r/RoarOfEndlessSong.java | 84 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 85 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/RoarOfEndlessSong.java diff --git a/Mage.Sets/src/mage/cards/r/RoarOfEndlessSong.java b/Mage.Sets/src/mage/cards/r/RoarOfEndlessSong.java new file mode 100644 index 00000000000..bc52ca9988f --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RoarOfEndlessSong.java @@ -0,0 +1,84 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.Elephant55Token; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RoarOfEndlessSong extends CardImpl { + + public RoarOfEndlessSong(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{U}{R}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I, II -- Create a 5/5 green Elephant creature token. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_II, + new CreateTokenEffect(new Elephant55Token())); + + // III -- Double the power and toughness of each creature you control until end of turn. + sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new RoarOfEndlessSongEffect()); + this.addAbility(sagaAbility); + } + + private RoarOfEndlessSong(final RoarOfEndlessSong card) { + super(card); + } + + @Override + public RoarOfEndlessSong copy() { + return new RoarOfEndlessSong(this); + } +} + +class RoarOfEndlessSongEffect extends OneShotEffect { + + RoarOfEndlessSongEffect() { + super(Outcome.Benefit); + staticText = "double the power and toughness of each creature you control until end of turn"; + } + + private RoarOfEndlessSongEffect(final RoarOfEndlessSongEffect effect) { + super(effect); + } + + @Override + public RoarOfEndlessSongEffect copy() { + return new RoarOfEndlessSongEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getControllerId(), source, game + )) { + game.addEffect(new BoostTargetEffect( + permanent.getPower().getValue(), + permanent.getToughness().getValue() + ).setTargetPointer(new FixedTarget(permanent, game)), source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 305bedd18c7..f3756a655a6 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -123,6 +123,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Reigning Victor", 216, Rarity.COMMON, mage.cards.r.ReigningVictor.class)); cards.add(new SetCardInfo("Ringing Strike Mastery", 53, Rarity.COMMON, mage.cards.r.RingingStrikeMastery.class)); cards.add(new SetCardInfo("Roamer's Routine", 154, Rarity.COMMON, mage.cards.r.RoamersRoutine.class)); + cards.add(new SetCardInfo("Roar of Endless Song", 220, Rarity.RARE, mage.cards.r.RoarOfEndlessSong.class)); cards.add(new SetCardInfo("Roiling Dragonstorm", 55, Rarity.UNCOMMON, mage.cards.r.RoilingDragonstorm.class)); cards.add(new SetCardInfo("Rugged Highlands", 265, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); cards.add(new SetCardInfo("Salt Road Packbeast", 23, Rarity.COMMON, mage.cards.s.SaltRoadPackbeast.class)); From 316ea237124406f1db7eabe2ee0a06440de45192 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 14:36:59 -0400 Subject: [PATCH 07/49] [TDM] Implement Dragonstorm Globe --- .../src/mage/cards/d/DragonstormGlobe.java | 42 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/d/DragonstormGlobe.java diff --git a/Mage.Sets/src/mage/cards/d/DragonstormGlobe.java b/Mage.Sets/src/mage/cards/d/DragonstormGlobe.java new file mode 100644 index 00000000000..4656501b33c --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DragonstormGlobe.java @@ -0,0 +1,42 @@ +package mage.cards.d; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.EntersWithCountersControlledEffect; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DragonstormGlobe extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.DRAGON, "Dragon"); + + public DragonstormGlobe(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + // Each Dragon you control enters with an additional +1/+1 counter on it. + this.addAbility(new SimpleStaticAbility(new EntersWithCountersControlledEffect( + filter, CounterType.P1P1.createInstance(), false + ))); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + } + + private DragonstormGlobe(final DragonstormGlobe card) { + super(card); + } + + @Override + public DragonstormGlobe copy() { + return new DragonstormGlobe(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index f3756a655a6..eb6a5b889b5 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -68,6 +68,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Dragonbroods' Relic", 140, Rarity.UNCOMMON, mage.cards.d.DragonbroodsRelic.class)); cards.add(new SetCardInfo("Dragonologist", 42, Rarity.RARE, mage.cards.d.Dragonologist.class)); cards.add(new SetCardInfo("Dragonstorm Forecaster", 43, Rarity.UNCOMMON, mage.cards.d.DragonstormForecaster.class)); + cards.add(new SetCardInfo("Dragonstorm Globe", 241, Rarity.COMMON, mage.cards.d.DragonstormGlobe.class)); cards.add(new SetCardInfo("Dusyut Earthcarver", 141, Rarity.COMMON, mage.cards.d.DusyutEarthcarver.class)); cards.add(new SetCardInfo("Duty Beyond Death", 10, Rarity.UNCOMMON, mage.cards.d.DutyBeyondDeath.class)); cards.add(new SetCardInfo("Embermouth Sentinel", 242, Rarity.COMMON, mage.cards.e.EmbermouthSentinel.class)); From 10dbfc58e3085369de348f88f84c747ca964ccc3 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 14:39:36 -0400 Subject: [PATCH 08/49] [TDM] Implement Felothar, Dawn of the Abzan --- .../mage/cards/f/FelotharDawnOfTheAbzan.java | 56 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 57 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/f/FelotharDawnOfTheAbzan.java diff --git a/Mage.Sets/src/mage/cards/f/FelotharDawnOfTheAbzan.java b/Mage.Sets/src/mage/cards/f/FelotharDawnOfTheAbzan.java new file mode 100644 index 00000000000..cc4a8f8a44a --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FelotharDawnOfTheAbzan.java @@ -0,0 +1,56 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DoWhenCostPaid; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.keyword.TrampleAbility; +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.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FelotharDawnOfTheAbzan extends CardImpl { + + public FelotharDawnOfTheAbzan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{B}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever Felothar enters or attacks, you may sacrifice a nonland permanent. When you do, put a +1/+1 counter on each creature you control. + this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DoWhenCostPaid( + new ReflexiveTriggeredAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), + StaticFilters.FILTER_CONTROLLED_CREATURE + ), false), + new SacrificeTargetCost(StaticFilters.FILTER_PERMANENT_NON_LAND), + "Sacrifice a nonland permanent?" + ))); + } + + private FelotharDawnOfTheAbzan(final FelotharDawnOfTheAbzan card) { + super(card); + } + + @Override + public FelotharDawnOfTheAbzan copy() { + return new FelotharDawnOfTheAbzan(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index eb6a5b889b5..65dcd0fbe7d 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -76,6 +76,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Equilibrium Adept", 106, Rarity.UNCOMMON, mage.cards.e.EquilibriumAdept.class)); cards.add(new SetCardInfo("Evolving Wilds", 255, Rarity.COMMON, mage.cards.e.EvolvingWilds.class)); cards.add(new SetCardInfo("Fangkeeper's Familiar", 183, Rarity.RARE, mage.cards.f.FangkeepersFamiliar.class)); + cards.add(new SetCardInfo("Felothar, Dawn of the Abzan", 184, Rarity.RARE, mage.cards.f.FelotharDawnOfTheAbzan.class)); cards.add(new SetCardInfo("Forest", 285, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Fortress Kin-Guard", 12, Rarity.COMMON, mage.cards.f.FortressKinGuard.class)); cards.add(new SetCardInfo("Fresh Start", 46, Rarity.UNCOMMON, mage.cards.f.FreshStart.class)); From 842612a37a268ffc32866ebddd058b15710a2427 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 14:59:46 -0400 Subject: [PATCH 09/49] [TDM] Implement Nature's Rhythm --- Mage.Sets/src/mage/cards/n/NaturesRhythm.java | 57 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 58 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/n/NaturesRhythm.java diff --git a/Mage.Sets/src/mage/cards/n/NaturesRhythm.java b/Mage.Sets/src/mage/cards/n/NaturesRhythm.java new file mode 100644 index 00000000000..d86db87f2c1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NaturesRhythm.java @@ -0,0 +1,57 @@ +package mage.cards.n; + +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.keyword.HarmonizeAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NaturesRhythm extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("a creature card with mana value X or less"); + + static { + filter.add(NaturesRhythmPredicate.instance); + } + + public NaturesRhythm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{G}{G}"); + + // Search your library for a creature card with mana value X or less, put it onto the battlefield, then shuffle. + this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter))); + + // Harmonize {X}{G}{G}{G}{G} + this.addAbility(new HarmonizeAbility(this, "{X}{G}{G}{G}{G}")); + } + + private NaturesRhythm(final NaturesRhythm card) { + super(card); + } + + @Override + public NaturesRhythm copy() { + return new NaturesRhythm(this); + } +} + +enum NaturesRhythmPredicate implements ObjectSourcePlayerPredicate { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input.getObject().getManaValue() <= GetXValue.instance.calculate(game, input.getSource(), null); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 65dcd0fbe7d..0afdfafe8bc 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -112,6 +112,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Mystic Monastery", 262, Rarity.UNCOMMON, mage.cards.m.MysticMonastery.class)); cards.add(new SetCardInfo("Narset's Rebuke", 114, Rarity.COMMON, mage.cards.n.NarsetsRebuke.class)); cards.add(new SetCardInfo("Narset, Jeskai Waymaster", 209, Rarity.RARE, mage.cards.n.NarsetJeskaiWaymaster.class)); + cards.add(new SetCardInfo("Nature's Rhythm", 150, Rarity.RARE, mage.cards.n.NaturesRhythm.class)); cards.add(new SetCardInfo("Neriv, Heart of the Storm", 210, Rarity.MYTHIC, mage.cards.n.NerivHeartOfTheStorm.class)); cards.add(new SetCardInfo("Nomad Outpost", 263, Rarity.UNCOMMON, mage.cards.n.NomadOutpost.class)); cards.add(new SetCardInfo("Opulent Palace", 264, Rarity.UNCOMMON, mage.cards.o.OpulentPalace.class)); From 769097cfa368fbb19e9f57ed96d6945b2c4eb99d Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 15:20:41 -0400 Subject: [PATCH 10/49] fix error --- .../src/mage/deck/AbstractCommander.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java index 332be55033c..fa47ac8d512 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AbstractCommander.java @@ -844,8 +844,8 @@ public abstract class AbstractCommander extends Constructed { || cn.equals("yawgmoth's will") || cn.equals("zealous conscripts") || cn.equals("zur the enchanter")) { - thisMaxPower = Math.max(thisMaxPower, 12); - } + thisMaxPower = Math.max(thisMaxPower, 12); + } // Parts of infinite combos if (cn.equals("animate artifact") || cn.equals("animar, soul of element") @@ -905,10 +905,10 @@ public abstract class AbstractCommander extends Constructed { || cn.equals("workhorse") || cn.equals("worldgorger dragon") || cn.equals("worthy cause") || cn.equals("yawgmoth's will") || cn.equals("zealous conscripts")) { - thisMaxPower = Math.max(thisMaxPower, 15); - numberInfinitePieces++; - } - + thisMaxPower = Math.max(thisMaxPower, 15); + numberInfinitePieces++; + } + // Game changers if (cn.equals("ad nauseam") || cn.equals("ancient tomb") @@ -950,9 +950,10 @@ public abstract class AbstractCommander extends Constructed { || cn.equals("vorinclex, voice of hunger") || cn.equals("winota, joiner of forces") || cn.equals("yuriko, the tiger's shadow")) { - thisMaxPower = Math.max(thisMaxPower, 20); - } - + thisMaxPower = Math.max(thisMaxPower, 20); + } + } + ObjectColor color = null; for (Card commander : deck.getSideboard()) { int thisMaxPower = 0; From fcbf22380e3a3f0f42cafa60aa51aec43c1f9ba4 Mon Sep 17 00:00:00 2001 From: PurpleCrowbar <26198472+PurpleCrowbar@users.noreply.github.com> Date: Sat, 29 Mar 2025 01:16:21 +0000 Subject: [PATCH 11/49] [TDM] Implement Teeming Dragonstorm --- .../src/mage/cards/t/TeemingDragonstorm.java | 41 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 2 + .../game/permanent/token/Soldier22Token.java | 29 +++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TeemingDragonstorm.java create mode 100644 Mage/src/main/java/mage/game/permanent/token/Soldier22Token.java diff --git a/Mage.Sets/src/mage/cards/t/TeemingDragonstorm.java b/Mage.Sets/src/mage/cards/t/TeemingDragonstorm.java new file mode 100644 index 00000000000..0683450554e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TeemingDragonstorm.java @@ -0,0 +1,41 @@ +package mage.cards.t; + +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.game.permanent.token.Soldier22Token; + +import java.util.UUID; + +/** + * @author PurpleCrowbar + */ +public final class TeemingDragonstorm extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.DRAGON, "a Dragon"); + + public TeemingDragonstorm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); + + // When this enchantment enters, create two 2/2 white Soldier creature tokens. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new Soldier22Token(), 2), false)); + + // When a Dragon you control enters, return this enchantment to its owner's hand. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new ReturnToHandSourceEffect(), filter)); + } + + private TeemingDragonstorm (final TeemingDragonstorm card) { + super(card); + } + + @Override + public TeemingDragonstorm copy() { + return new TeemingDragonstorm(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 0afdfafe8bc..1178deda0d8 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -150,6 +150,8 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Sunset Strikemaster", 126, Rarity.UNCOMMON, mage.cards.s.SunsetStrikemaster.class)); cards.add(new SetCardInfo("Swamp", 281, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swiftwater Cliffs", 268, Rarity.COMMON, mage.cards.s.SwiftwaterCliffs.class)); + cards.add(new SetCardInfo("Teeming Dragonstorm", 30, Rarity.UNCOMMON, mage.cards.t.TeemingDragonstorm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Teeming Dragonstorm", 293, Rarity.UNCOMMON, mage.cards.t.TeemingDragonstorm.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Tempest Hawk", 31, Rarity.COMMON, mage.cards.t.TempestHawk.class)); cards.add(new SetCardInfo("Temur Devotee", 61, Rarity.COMMON, mage.cards.t.TemurDevotee.class)); cards.add(new SetCardInfo("Temur Monument", 248, Rarity.UNCOMMON, mage.cards.t.TemurMonument.class)); diff --git a/Mage/src/main/java/mage/game/permanent/token/Soldier22Token.java b/Mage/src/main/java/mage/game/permanent/token/Soldier22Token.java new file mode 100644 index 00000000000..0ddf938b3c1 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/Soldier22Token.java @@ -0,0 +1,29 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author PurpleCrowbar + */ +public final class Soldier22Token extends TokenImpl { + + public Soldier22Token() { + super("Soldier Token", "2/2 white Soldier creature token"); + cardType.add(CardType.CREATURE); + color.setWhite(true); + subtype.add(SubType.SOLDIER); + power = new MageInt(2); + toughness = new MageInt(2); + } + + private Soldier22Token(final Soldier22Token token) { + super(token); + } + + @Override + public Soldier22Token copy() { + return new Soldier22Token(this); + } +} From 2286dd2bbd975c4561e9ddad80ed44614acbc157 Mon Sep 17 00:00:00 2001 From: PurpleCrowbar <26198472+PurpleCrowbar@users.noreply.github.com> Date: Sat, 29 Mar 2025 01:32:37 +0000 Subject: [PATCH 12/49] Fix Great Arashin City --- .../src/mage/cards/g/GreatArashinCity.java | 6 ++-- .../token/NoFlyingSpiritWhiteToken.java | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 Mage/src/main/java/mage/game/permanent/token/NoFlyingSpiritWhiteToken.java diff --git a/Mage.Sets/src/mage/cards/g/GreatArashinCity.java b/Mage.Sets/src/mage/cards/g/GreatArashinCity.java index 9166e95fedc..ce375db023c 100644 --- a/Mage.Sets/src/mage/cards/g/GreatArashinCity.java +++ b/Mage.Sets/src/mage/cards/g/GreatArashinCity.java @@ -16,7 +16,7 @@ import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; -import mage.game.permanent.token.SpiritWhiteToken; +import mage.game.permanent.token.NoFlyingSpiritWhiteToken; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -47,9 +47,9 @@ public final class GreatArashinCity extends CardImpl { this.addAbility(new BlackManaAbility()); // {1}{B}, {T}, Exile a creature card from your graveyard: Create a 1/1 white Spirit creature token. - Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new SpiritWhiteToken()), new ManaCostsImpl<>("{1}{B}")); + Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new NoFlyingSpiritWhiteToken()), new ManaCostsImpl<>("{1}{B}")); ability.addCost(new TapSourceCost()); - ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE))); + ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE)).withSourceExileZone(false)); this.addAbility(ability); } diff --git a/Mage/src/main/java/mage/game/permanent/token/NoFlyingSpiritWhiteToken.java b/Mage/src/main/java/mage/game/permanent/token/NoFlyingSpiritWhiteToken.java new file mode 100644 index 00000000000..60e7644cc70 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/NoFlyingSpiritWhiteToken.java @@ -0,0 +1,29 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author PurpleCrowbar + */ +public final class NoFlyingSpiritWhiteToken extends TokenImpl { + + public NoFlyingSpiritWhiteToken() { + super("Spirit Token", "1/1 white Spirit creature token"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.SPIRIT); + color.setWhite(true); + power = new MageInt(1); + toughness = new MageInt(1); + } + + private NoFlyingSpiritWhiteToken(final NoFlyingSpiritWhiteToken token) { + super(token); + } + + @Override + public NoFlyingSpiritWhiteToken copy() { + return new NoFlyingSpiritWhiteToken(this); + } +} From 89189b4d3b58c85de9c40eb883ae12219f454c46 Mon Sep 17 00:00:00 2001 From: xenohedron <12538125+xenohedron@users.noreply.github.com> Date: Fri, 28 Mar 2025 21:46:32 -0400 Subject: [PATCH 13/49] fix verify --- Mage.Sets/src/mage/sets/UnknownEvent.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/UnknownEvent.java b/Mage.Sets/src/mage/sets/UnknownEvent.java index 776949d124a..21975fb4b22 100644 --- a/Mage.Sets/src/mage/sets/UnknownEvent.java +++ b/Mage.Sets/src/mage/sets/UnknownEvent.java @@ -1,4 +1,3 @@ - package mage.sets; import mage.cards.ExpansionSet; @@ -17,7 +16,7 @@ public final class UnknownEvent extends ExpansionSet { } private UnknownEvent() { - super("Unknown Event", "DA1", ExpansionSet.buildDate(2023, 2, 15), SetType.JOKE_SET); + super("Unknown Event", "UNK", ExpansionSet.buildDate(2023, 2, 15), SetType.JOKE_SET); this.hasBasicLands = false; this.hasBoosters = false; From b254b9528da7b40fe599ab3b1cc00746a592d8a8 Mon Sep 17 00:00:00 2001 From: padfoothelix Date: Sat, 29 Mar 2025 02:52:15 +0100 Subject: [PATCH 14/49] [WHO] Implement The Second Doctor (#13435) --- .../src/mage/cards/t/TheSecondDoctor.java | 141 ++++++++++++++++++ Mage.Sets/src/mage/sets/DoctorWho.java | 14 +- 2 files changed, 148 insertions(+), 7 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/t/TheSecondDoctor.java diff --git a/Mage.Sets/src/mage/cards/t/TheSecondDoctor.java b/Mage.Sets/src/mage/cards/t/TheSecondDoctor.java new file mode 100644 index 00000000000..3553ed8bf51 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheSecondDoctor.java @@ -0,0 +1,141 @@ +package mage.cards.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; +import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author padfoothelix + */ +public final class TheSecondDoctor extends CardImpl { + + public TheSecondDoctor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.TIME_LORD); + this.subtype.add(SubType.DOCTOR); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Players have no maximum hand size. + this.addAbility(new SimpleStaticAbility(new MaximumHandSizeControllerEffect( + Integer.MAX_VALUE, Duration.WhileOnBattlefield, + MaximumHandSizeControllerEffect.HandSizeModification.SET, TargetController.ANY + ))); + + // How Civil of You -- At the beginning of your end step, each player may draw a card. Each opponent who does can't attack you or permanents you control during their next turn. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new TheSecondDoctorEffect()).withFlavorWord("How Civil of You")); + } + + private TheSecondDoctor(final TheSecondDoctor card) { + super(card); + } + + @Override + public TheSecondDoctor copy() { + return new TheSecondDoctor(this); + } +} + +class TheSecondDoctorEffect extends OneShotEffect { + TheSecondDoctorEffect() { + super(Outcome.Benefit); + this.staticText = "each player may draw a card. Each opponent who does can't attack you or permanents you control during their next turn."; + } + + private TheSecondDoctorEffect(final TheSecondDoctorEffect effect) { + super(effect); + } + + @Override + public TheSecondDoctorEffect copy() { + return new TheSecondDoctorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null + && player.chooseUse(Outcome.DrawCard, "Draw a card ?", source, game) + && player.drawCards(1, source, game) > 0 + && game.getOpponents(controller.getId()).contains(playerId)) { + RestrictionEffect effect = new TheSecondDoctorCantAttackEffect(player.getId()); + game.addEffect(effect, source); + } + } + return true; + } +} + +class TheSecondDoctorCantAttackEffect extends RestrictionEffect { + + private final UUID opponentId; + + public TheSecondDoctorCantAttackEffect(UUID opponentId) { + super(Duration.UntilEndOfYourNextTurn); + this.opponentId = opponentId; + staticText = ""; + } + + private TheSecondDoctorCantAttackEffect(final TheSecondDoctorCantAttackEffect effect) { + super(effect); + this.opponentId = effect.opponentId; + } + + @Override + public TheSecondDoctorCantAttackEffect copy() { + return new TheSecondDoctorCantAttackEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + if (opponentId != null) { + setStartingControllerAndTurnNum(game, opponentId, game.getActivePlayerId()); + } else { + discard(); + } + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return game.isActivePlayer(opponentId); + } + + @Override + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + UUID controllerId = source.getControllerId(); + // defender is null + if (defenderId == null) { + return true; + } + // defender is a permanent + Permanent defender = game.getPermanent(defenderId); + if (defender != null) { + return !defender.isControlledBy(controllerId); + } + // defender is a player + return !defenderId.equals(controllerId); + } +} diff --git a/Mage.Sets/src/mage/sets/DoctorWho.java b/Mage.Sets/src/mage/sets/DoctorWho.java index b70357f6180..c0009b9bb88 100644 --- a/Mage.Sets/src/mage/sets/DoctorWho.java +++ b/Mage.Sets/src/mage/sets/DoctorWho.java @@ -1010,13 +1010,13 @@ public final class DoctorWho extends ExpansionSet { cards.add(new SetCardInfo("The Rani", 754, Rarity.RARE, mage.cards.t.TheRani.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Sea Devils", 108, Rarity.RARE, mage.cards.t.TheSeaDevils.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Sea Devils", 713, Rarity.RARE, mage.cards.t.TheSeaDevils.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", "553z", Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", 1031, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", 1144, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", 156, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", 440, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", 553, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); - //cards.add(new SetCardInfo("The Second Doctor", 761, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", "553z", Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", 1031, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", 1144, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", 156, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", 440, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", 553, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("The Second Doctor", 761, Rarity.RARE, mage.cards.t.TheSecondDoctor.class, NON_FULL_USE_VARIOUS)); //cards.add(new SetCardInfo("The Seventh Doctor", "558z", Rarity.RARE, mage.cards.t.TheSeventhDoctor.class, NON_FULL_USE_VARIOUS)); //cards.add(new SetCardInfo("The Seventh Doctor", 1033, Rarity.RARE, mage.cards.t.TheSeventhDoctor.class, NON_FULL_USE_VARIOUS)); //cards.add(new SetCardInfo("The Seventh Doctor", 1149, Rarity.RARE, mage.cards.t.TheSeventhDoctor.class, NON_FULL_USE_VARIOUS)); From fa909b2b40f1847646ce82d43188becaf6924cb7 Mon Sep 17 00:00:00 2001 From: PurpleCrowbar <26198472+PurpleCrowbar@users.noreply.github.com> Date: Sat, 29 Mar 2025 01:52:34 +0000 Subject: [PATCH 15/49] Add TDM token images for implemented tokens --- .../dl/sources/ScryfallImageSupportTokens.java | 16 ++++++++++++++++ Mage/src/main/resources/tokens-database.txt | 17 +++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java index d8dc2cd18c2..55602d438ad 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java @@ -2615,6 +2615,22 @@ public class ScryfallImageSupportTokens { put("DRC/Zombie Army", "https://api.scryfall.com/cards/tdrc/8/en?format=image"); put("DRC/Zombie Warrior", "https://api.scryfall.com/cards/tdrc/9/en?format=image"); + // TDM + put("TDM/Bird", "https://api.scryfall.com/cards/ttdm/2/en?format=image"); + put("TDM/Dragon", "https://api.scryfall.com/cards/ttdm/11/en?format=image"); + put("TDM/Elephant", "https://api.scryfall.com/cards/ttdm/14/en?format=image"); + put("TDM/Goblin", "https://api.scryfall.com/cards/ttdm/12/en?format=image"); + put("TDM/Monk", "https://api.scryfall.com/cards/ttdm/3/en?format=image"); + put("TDM/Reliquary Dragon", "https://api.scryfall.com/cards/ttdm/15/en?format=image"); + put("TDM/Soldier/1", "https://api.scryfall.com/cards/ttdm/4/en?format=image"); + put("TDM/Soldier/2", "https://api.scryfall.com/cards/ttdm/5/en?format=image"); + put("TDM/Spirit/1", "https://api.scryfall.com/cards/ttdm/9/en?format=image"); + put("TDM/Spirit/2", "https://api.scryfall.com/cards/ttdm/6/en?format=image"); + // TODO: 2/2 and 3/3 Spirit tokens (no relevant cards revealed, token not implemented) + put("TDM/Treasure", "https://api.scryfall.com/cards/ttdm/16/en?format=image"); + put("TDM/Warrior", "https://api.scryfall.com/cards/ttdm/13/en?format=image"); + put("TDM/Zombie Druid", "https://api.scryfall.com/cards/ttdm/10/en?format=image"); + // TDC put("TDC/Angel", "https://api.scryfall.com/cards/ttdc/2/en?format=image"); put("TDC/Citizen", "https://api.scryfall.com/cards/ttdc/26/en?format=image"); diff --git a/Mage/src/main/resources/tokens-database.txt b/Mage/src/main/resources/tokens-database.txt index 2064f6cd4ef..39c9c643fd3 100644 --- a/Mage/src/main/resources/tokens-database.txt +++ b/Mage/src/main/resources/tokens-database.txt @@ -2482,6 +2482,23 @@ |Generate|TOK:DRC|Zombie Army|||ZombieArmyToken| |Generate|TOK:DRC|Zombie Warrior|||GodEternalOketraToken| +# TDM +|Generate|TOK:TDM|Bird|||BirdToken| +|Generate|TOK:TDM|Dragon|||DragonToken| +|Generate|TOK:TDM|Elephant|||Elephant55Token| +|Generate|TOK:TDM|Goblin|||GoblinToken| +|Generate|TOK:TDM|Monk|||MonasteryMentorToken| +|Generate|TOK:TDM|Reliquary Dragon|||ReliquaryDragonToken| +|Generate|TOK:TDM|Soldier|1||SoldierToken| +|Generate|TOK:TDM|Soldier|2||Soldier22Token| +|Generate|TOK:TDM|Spirit|1||SpiritXXToken| +|Generate|TOK:TDM|Spirit|2||NoFlyingSpiritWhiteToken| +# TODO: 2/2 Spirit (no relevant cards revealed, token not implemented) +# TODO: 3/3 Spirit (no relevant cards revealed, token not implemented) +|Generate|TOK:TDM|Treasure|||TreasureToken| +|Generate|TOK:TDM|Warrior|||RedWarriorToken| +|Generate|TOK:TDM|Zombie Druid|||ZombieDruidToken| + # TDC |Generate|TOK:TDC|Angel|||AngelVigilanceToken| |Generate|TOK:TDC|Citizen|||CitizenGreenWhiteToken| From 299c7dc56f80740ee33d3573b9fd16930d4ba125 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 21:47:51 -0400 Subject: [PATCH 16/49] [TDM] update spoiler and reprints --- .../src/mage/sets/TarkirDragonstorm.java | 6 +-- Utils/mtg-cards-data.txt | 44 ++++++++++++++++++- 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 1178deda0d8..9f2391c1230 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -12,7 +12,7 @@ import java.util.List; */ public final class TarkirDragonstorm extends ExpansionSet { - private static final List unfinished = Arrays.asList("Channeled Dragonfire", "Glacial Dragonhunt", "Mammoth Bellow", "Nature's Rhythm", "Roamer's Routine", "Songcrafter Mage", "Synchronized Charge", "Unending Whisper", "Ureni's Rebuff", "Winternight Stories"); + private static final List unfinished = Arrays.asList("Channeled Dragonfire", "Glacial Dragonhunt", "Mammoth Bellow", "Nature's Rhythm", "Roamer's Routine", "Songcrafter Mage", "Synchronized Charge", "Unending Whisper", "Ureni's Rebuff", "Wild Ride", "Winternight Stories"); private static final TarkirDragonstorm instance = new TarkirDragonstorm(); public static TarkirDragonstorm getInstance() { @@ -150,14 +150,14 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Sunset Strikemaster", 126, Rarity.UNCOMMON, mage.cards.s.SunsetStrikemaster.class)); cards.add(new SetCardInfo("Swamp", 281, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swiftwater Cliffs", 268, Rarity.COMMON, mage.cards.s.SwiftwaterCliffs.class)); - cards.add(new SetCardInfo("Teeming Dragonstorm", 30, Rarity.UNCOMMON, mage.cards.t.TeemingDragonstorm.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Teeming Dragonstorm", 293, Rarity.UNCOMMON, mage.cards.t.TeemingDragonstorm.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Teeming Dragonstorm", 30, Rarity.UNCOMMON, mage.cards.t.TeemingDragonstorm.class)); cards.add(new SetCardInfo("Tempest Hawk", 31, Rarity.COMMON, mage.cards.t.TempestHawk.class)); cards.add(new SetCardInfo("Temur Devotee", 61, Rarity.COMMON, mage.cards.t.TemurDevotee.class)); cards.add(new SetCardInfo("Temur Monument", 248, Rarity.UNCOMMON, mage.cards.t.TemurMonument.class)); cards.add(new SetCardInfo("Temur Tawnyback", 229, Rarity.COMMON, mage.cards.t.TemurTawnyback.class)); cards.add(new SetCardInfo("Thornwood Falls", 269, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); cards.add(new SetCardInfo("Tranquil Cove", 270, Rarity.COMMON, mage.cards.t.TranquilCove.class)); + cards.add(new SetCardInfo("Twin Bolt", 128, Rarity.COMMON, mage.cards.t.TwinBolt.class)); cards.add(new SetCardInfo("Ugin, Eye of the Storms", 1, Rarity.MYTHIC, mage.cards.u.UginEyeOfTheStorms.class)); cards.add(new SetCardInfo("Underfoot Underdogs", 129, Rarity.COMMON, mage.cards.u.UnderfootUnderdogs.class)); cards.add(new SetCardInfo("Undergrowth Leopard", 165, Rarity.COMMON, mage.cards.u.UndergrowthLeopard.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 92dc2faa708..9a845ef758c 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -57200,6 +57200,7 @@ Cloud, Planet's Champion|Final Fantasy|552|M|{3}{R}{W}|Legendary Creature - Huma Sephiroth, Planet's Heir|Final Fantasy|553|M|{4}{U}{B}|Legendary Creature - Human Avatar Soldier|4|4|Vigilance$When Sephiroth enters, creatures your opponents control get -2/-2 until end of turn.$Whenever a creature an opponent controls dies, put a +1/+1 counter on Sephiroth.| Ugin, Eye of the Storms|Tarkir: Dragonstorm|1|M|{7}|Legendary Planeswalker - Ugin|7|When you cast this spell, exile up to one target permanent that's one or more colors.$Whenever you cast a colorless spell, exile up to one target permanent that's one or more colors.$+2: You gain 3 life and draw a card.$0: Add {C}{C}{C}.$-11: Search your library for any number of colorless nonland cards, exile them, then shuffle. Until end of turn, you may cast those cards without paying their mana costs.| Anafenza, Unyielding Lineage|Tarkir: Dragonstorm|2|R|{2}{W}|Legendary Creature - Spirit Soldier|2|2|Flash$First strike$Whenever another nontoken creature you control dies, Anafenza endures 2.| +Arashin Sunshield|Tarkir: Dragonstorm|3|C|{3}{W}|Creature - Human Warrior|3|4|When this creature enters, exile up to two target cards from a single graveyard.${W}, {T}: Tap target creature.| Bearer of Glory|Tarkir: Dragonstorm|4|C|{1}{W}|Creature - Human Soldier|2|1|During your turn, this creature has first strike.${4}{W}: Creatures you control get +1/+1 until end of turn.| Clarion Conqueror|Tarkir: Dragonstorm|5|R|{2}{W}|Creature - Dragon|3|3|Flying$Activated abilities of artifacts, creatures, and planeswalkers can't be activated.| Coordinated Maneuver|Tarkir: Dragonstorm|6|C|{1}{W}|Instant|||Choose one --$* Coordinated Maneuver deals damage equal to the number of creatures you control to target creature or planeswalker.$* Destroy target enchantment.| @@ -57209,10 +57210,12 @@ Dragonback Lancer|Tarkir: Dragonstorm|9|C|{3}{W}|Creature - Human Soldier|3|3|Fl Duty Beyond Death|Tarkir: Dragonstorm|10|U|{1}{W}|Instant|||As an additional cost to cast this spell, sacrifice a creature.$Creatures you control gain indestructible until end of turn. Put a +1/+1 counter on each creature you control.| Elspeth, Storm Slayer|Tarkir: Dragonstorm|11|M|{3}{W}{W}|Legendary Planeswalker - Elspeth|5|If one or more tokens would be created under your control, twice that many of those tokens are created instead.$+1: Create a 1/1 white Soldier creature token.$0: Put a +1/+1 counter on each creature you control. Those creatures gain flying until your next turn.$-3: Destroy target creature an opponent controls with mana value 3 or greater.| Fortress Kin-Guard|Tarkir: Dragonstorm|12|C|{1}{W}|Creature - Dog Soldier|1|2|When this creature enters, it endures 1.| +Furious Forebear|Tarkir: Dragonstorm|13|U|{1}{W}|Creature - Spirit Warrior|3|1|Whenever a creature you control dies while this card is in your graveyard, you may pay {1}{W}. If you do, return this card from your graveyard to your hand.| Lightfoot Technique|Tarkir: Dragonstorm|14|C|{1}{W}|Instant|||Put a +1/+1 counter on target creature. It gains flying and indestructible until end of turn.| Loxodon Battle Priest|Tarkir: Dragonstorm|15|U|{4}{W}|Creature - Elephant Cleric|3|5|At the beginning of combat on your turn, put a +1/+1 counter on another target creature you control.| Mardu Devotee|Tarkir: Dragonstorm|16|C|{W}|Creature - Human Scout|1|2|When this creature enters, scry 2.${1}: Add {R}, {W}, or {B}. Activate only once each turn.| Osseous Exhale|Tarkir: Dragonstorm|17|C|{1}{W}|Instant|||As an additional cost to cast this spell, you may behold a Dragon.$Osseous Exhale deals 5 damage to target attacking or blocking creature. If a Dragon was beheld, you gain 2 life.| +Poised Practitioner|Tarkir: Dragonstorm|18|C|{2}{W}|Creature - Human Monk|2|3|Flurry -- Whenever you cast your second spell each turn, put a +1/+1 counter on this creature. Scry 1.| Rally the Monastery|Tarkir: Dragonstorm|19|U|{3}{W}|Instant|||This spell costs {2} less to cast if you've cast another spell this turn.$Choose one --$* Create two 1/1 white Monk creature tokens with prowess.$* Up to two target creatures you control each get +2/+2 until end of turn.$* Destroy target creature with power 4 or greater.| Rebellious Strike|Tarkir: Dragonstorm|20|C|{1}{W}|Instant|||Target creature gets +3/+0 until end of turn.$Draw a card.| Riling Dawnbreaker|Tarkir: Dragonstorm|21|C|{4}{W}|Creature - Dragon|3|4|Flying, vigilance$At the beginning of combat on your turn, another target creature you control gets +1/+0 until end of turn.| @@ -57222,6 +57225,7 @@ Salt Road Packbeast|Tarkir: Dragonstorm|23|C|{5}{W}|Creature - Beast|4|3|This sp Smile at Death|Tarkir: Dragonstorm|24|M|{3}{W}{W}|Enchantment|||At the beginning of your upkeep, return up to two target creature cards with power 2 or less from your graveyard to the battlefield. Put a +1/+1 counter on each of those creatures.| Starry-Eyed Skyrider|Tarkir: Dragonstorm|25|U|{2}{W}|Creature - Human Scout|1|3|Flying$Whenever this creature attacks, another target creature you control gains flying until end of turn.$Attacking tokens you control have flying.| Static Snare|Tarkir: Dragonstorm|26|U|{4}{W}|Enchantment|||Flash$This spell costs {1} less to cast for each attacking creature.$When this enchantment enters, exile target artifact or creature an opponent controls until this enchantment leaves the battlefield.| +Stormbeacon Blade|Tarkir: Dragonstorm|27|U|{1}{W}|Artifact - Equipment|||Equipped creature gets +3/+0.$Whenever equipped creature attacks, draw a card if you control three or more attacking creatures.$Equip {2}| Stormplain Detainment|Tarkir: Dragonstorm|28|C|{2}{W}|Enchantment|||When this enchantment enters, exile target nonland permanent an opponent controls until this enchantment leaves the battlefield.| Sunpearl Kirin|Tarkir: Dragonstorm|29|U|{1}{W}|Creature - Kirin|2|1|Flash$Flying$When this creature enters, return up to one other target nonland permanent you control to its owner's hand. If it was a token, draw a card.| Teeming Dragonstorm|Tarkir: Dragonstorm|30|U|{3}{W}|Enchantment|||When this enchantment enters, create two 2/2 white Soldier creature tokens.$When a Dragon you control enters, return this enchantment to its owner's hand.| @@ -57233,21 +57237,26 @@ Aegis Sculptor|Tarkir: Dragonstorm|35|U|{3}{U}|Creature - Bird Wizard|2|3|Flying Agent of Kotis|Tarkir: Dragonstorm|36|C|{1}{U}|Creature - Human Rogue|2|1|Renew -- {3}{U}, Exile this card from your graveyard: Put two +1/+1 counters on target creature. Activate only as a sorcery.| Ambling Stormshell|Tarkir: Dragonstorm|37|R|{3}{U}{U}|Creature - Turtle|5|9|Ward {2}$Whenever this creature attacks, put three stun counters on it and draw three cards.$Whenever you cast a Turtle spell, untap this creature.| Bewildering Blizzard|Tarkir: Dragonstorm|38|U|{4}{U}{U}|Instant|||Draw three cards. Creatures your opponents control get -3/-0 until end of turn.| +Constrictor Sage|Tarkir: Dragonstorm|39|U|{4}{U}|Creature - Snake Wizard|4|4|When this creature enters, tap target creature an opponent controls and put a stun counter on it.$Renew -- 2{U}, Exile this card from your graveyard: Tap target creature an opponent controls and put a stun counter on it. Activate only as a sorcery.| Dirgur Island Dragon|Tarkir: Dragonstorm|40|C|{5}{U}|Creature - Dragon|4|4|Flying$Ward {2}| Skimming Strike|Tarkir: Dragonstorm|40|C|{1}{U}|Instant - Omen|4|4|Tap up to one target creature. Draw a card.| Dispelling Exhale|Tarkir: Dragonstorm|41|C|{1}{U}|Instant|||As an additional cost to cast this spell, you may behold a Dragon.$Counter target spell unless its controller pays {2}. If a Dragon was beheld, counter that spell unless its controller pays {4} instead.| Dragonologist|Tarkir: Dragonstorm|42|R|{2}{U}|Creature - Human Wizard|1|3|When this creature enters, look at the top six cards of your library. You may reveal an instant, sorcery, or Dragon card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.$Untapped Dragons you control have hexproof.| Dragonstorm Forecaster|Tarkir: Dragonstorm|43|U|{U}|Creature - Human Scout|0|3|{2}, {T}: Search your library for a card named Dragonstorm Globe or Boulderborn Dragon, reveal it, put it into your hand, then shuffle.| Essence Anchor|Tarkir: Dragonstorm|44|U|{2}{U}|Artifact|||At the beginning of your upkeep, surveil 1.${T}: Create a 2/2 black Zombie Druid creature token. Activate only during your turn and only if a card left your graveyard this turn.| +Focus the Mind|Tarkir: Dragonstorm|45|C|{4}{U}|Instant|||This spell costs {2} less to cast if you've cast another spell this turn.$Draw three cards, then discard a card.| Fresh Start|Tarkir: Dragonstorm|46|U|{1}{U}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature gets -5/-0 and loses all abilities.| Highspire Bell-Ringer|Tarkir: Dragonstorm|47|C|{2}{U}|Creature - Djinn Monk|1|4|Flying$The second spell you cast each turn costs {1} less to cast.| Humbling Elder|Tarkir: Dragonstorm|48|C|{U}|Creature - Human Monk|1|2|Flash$When this creature enters, target creature an opponent controls gets -2/-0 until end of turn.| +Iceridge Serpent|Tarkir: Dragonstorm|49|C|{4}{U}|Creature - Serpent|3|3|When this creature enters, return target creature an opponent controls to its owner's hand.| Kishla Trawlers|Tarkir: Dragonstorm|50|U|{2}{U}|Creature - Human Citizen|3|2|When this creature enters, you may exile a creature card from your graveyard. When you do, return target instant or sorcery card from your graveyard to your hand.| Marang River Regent|Tarkir: Dragonstorm|51|R|{4}{U}{U}|Creature - Dragon|6|7|Flying$When this creature enters, return up to two other target nonland permanents to their owners' hands.| Coil and Catch|Tarkir: Dragonstorm|51|R|{3}{U}|Instant - Omen|6|7|Draw three cards, then discard a card.| Naga Fleshcrafter|Tarkir: Dragonstorm|52|R|{3}{U}|Creature - Snake Shapeshifter|0|0|You may have this creature enter as a copy of any creature on the battlefield.$Renew -- {2}{U}, Exile this card from your graveyard: Put a +1/+1 counter on target nonlegendary creature you control. Each other creature you control becomes a copy of that creature until end of turn. Activate only as a sorcery.| Ringing Strike Mastery|Tarkir: Dragonstorm|53|C|{U}|Enchantment - Aura|||Enchant creature$When this Aura enters, tap enchanted creature.$Enchanted creature doesn't untap during its controller's untap step.$Enchanted creature has "{5}: Untap this creature."| +Riverwalk Technique|Tarkir: Dragonstorm|54|C|{3}{U}|Instant|||Choose one --$* The owner of target nonland permanent puts it on their choice of the top or bottom of their library.$* Counter target noncreature spell.| Roiling Dragonstorm|Tarkir: Dragonstorm|55|U|{1}{U}|Enchantment|||When this enchantment enters, draw two cards, then discard a card.$When a Dragon you control enters, return this enchantment to its owner's hand.| +Sibsig Appraiser|Tarkir: Dragonstorm|56|C|{2}{U}|Creature - Zombie Advisor|2|1|When this creature enters, look at the top two cards of your library. Put one of them into your hand and the other into your graveyard.| Snowmelt Stag|Tarkir: Dragonstorm|57|C|{3}{U}|Creature - Elemental Elk|2|5|Vigilance$During your turn, this creature has base power and toughness 5/2.${5}{U}{U}: This creature can't be blocked this turn.| Spectral Denial|Tarkir: Dragonstorm|58|U|{X}{U}|Instant|||This spell costs {1} less to cast for each creature you control with power 4 or greater.$Counter target spell unless its controller pays {X}.| Stillness in Motion|Tarkir: Dragonstorm|59|R|{1}{U}|Enchantment|||At the beginning of your upkeep, mill three cards. Then if you have no cards in your library, exile this enchantment and put five cards from your graveyard on top of your library in any order.| @@ -57255,9 +57264,14 @@ Taigam, Master Opportunist|Tarkir: Dragonstorm|60|M|{1}{U}|Legendary Creature - Temur Devotee|Tarkir: Dragonstorm|61|C|{1}{U}|Creature - Human Druid|3|3|Defender${1}: Add {G}, {U}, or {R}. Activate only once each turn.| Unending Whisper|Tarkir: Dragonstorm|62|C|{U}|Sorcery|||Draw a card.$Harmonize {5}{U}| Ureni's Rebuff|Tarkir: Dragonstorm|63|U|{1}{U}|Sorcery|||Return target creature to its owner's hand.$Harmonize {5}{U}| +Veteran Ice Climber|Tarkir: Dragonstorm|64|U|{1}{U}|Creature - Human Scout|1|3|Vigilance$This creature can't be blocked.$Whenever this creature attacks, up to one target player mills cards equal to this creature's power.| +Wingblade Disciple|Tarkir: Dragonstorm|65|U|{2}{U}|Creature - Human Monk|2|2|Flying$Flurry -- Whenever you cast your second spell each turn, create a 1/1 white Bird creature token with flying.| Wingspan Stride|Tarkir: Dragonstorm|66|C|{U}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +1/+1 and has flying.${2}{U}: Return this Aura to its owner's hand.| Winternight Stories|Tarkir: Dragonstorm|67|R|{2}{U}|Sorcery|||Draw three cards. Then discard two cards unless you discard a creature card.$Harmonize {4}{U}| Abzan Devotee|Tarkir: Dragonstorm|68|C|{1}{B}|Creature - Dog Cleric|2|1|{1}: Add {W}, {B}, or {G}. Activate only once each turn.${2}{B}: Return this card from your graveyard to your hand.| +Adorned Crocodile|Tarkir: Dragonstorm|69|C|{4}{B}|Creature - Crocodile|5|3|When this creature dies, create a 2/2 black Zombie Druid creature token. Renew -, Exile this card from your graveyard: Put a +1/+1 counter on target creature. Activate only as a sorcery.| +Aggressive Negotiations|Tarkir: Dragonstorm|70|C|{2}{B}|Sorcery|||Target opponent reveals their hand. You choose a nonland card from it and exile that card. Put a +1/+1 counter on up to one target creature you control.| +Alchemist's Assistant|Tarkir: Dragonstorm|71|U|{1}{B}|Creature - Monkey|2|1|Lifelink$Renew -- {1}{B}, Exile this card from your graveyard: Put a lifelink counter on target creature. Activate only as a sorcery.| Alesha's Legacy|Tarkir: Dragonstorm|72|C|{1}{B}|Instant|||Target creature you control gains deathtouch and indestructible until end of turn.| Avenger of the Fallen|Tarkir: Dragonstorm|73|R|{2}{B}|Creature - Human Warrior|2|4|Deathtouch$Mobilize X, where X is the number of creature cards in your graveyard.| Caustic Exhale|Tarkir: Dragonstorm|74|C|{B}|Instant|||As an additional cost to cast this spell, behold a Dragon or pay {1}.$Target creature gets -3/-3 until end of turn.| @@ -57268,14 +57282,22 @@ Desperate Measures|Tarkir: Dragonstorm|78|U|{B}|Instant|||Target creature gets + Dragon's Prey|Tarkir: Dragonstorm|79|C|{2}{B}|Instant|||This spell costs {2} more to cast if it targets a Dragon.$Destroy target creature.| Feral Deathgorger|Tarkir: Dragonstorm|80|C|{5}{B}|Creature - Dragon|3|5|Flying, deathtouch$When this creature enters, exile up to two target cards from a single graveyard.| Dusk Sight|Tarkir: Dragonstorm|80|C|{1}{B}|Sorcery - Omen|3|5|Put a +1/+1 counter on up to one target creature. Draw a card.| +Gurmag Rakshasa|Tarkir: Dragonstorm|81|U|{4}{B}{B}|Creature - Demon|5|5|Menace$When this creature enters, target creature an opponent controls gets -2/-2 until end of turn and target creature you control gets +2/+2 until end of turn.| +Hundred-Battle Veteran|Tarkir: Dragonstorm|82|U|{3}{B}|Creature - Zombie Warrior|4|2|As long as there are three or more different kinds of counters among creatures you control, this creature gets +2/+4.$You may cast this card from your graveyard. If you do, it enters with a finality counter on it.| +Kin-Tree Nurturer|Tarkir: Dragonstorm|83|C|{2}{B}|Creature - Human Druid|2|1|Lifelink$When this creature enters, it endures 1.| Krumar Initiate|Tarkir: Dragonstorm|84|U|{1}{B}|Creature - Human Cleric|2|2|{X}{B}, {T}, Pay X life: This creature endures X. Activate only as a sorcery.| +Nightblade Brigade|Tarkir: Dragonstorm|85|C|{2}{B}|Creature - Goblin Soldier|1|3|Deathtouch$Mobilize 1$When this creature enters, surveil 1.| Qarsi Revenant|Tarkir: Dragonstorm|86|R|{1}{B}{B}|Creature - Vampire|3|3|Flying, deathtouch, lifelink$Renew -- {2}{B}, Exile this card from your graveyard: Put a flying counter, a deathtouch counter, and a lifelink counter on target creature. Activate only as a sorcery.| Rot-Curse Rakshasa|Tarkir: Dragonstorm|87|M|{1}{B}|Creature - Demon|5|5|Trample$Decayed$Renew -- {X}{B}{B}, Exile this card from your graveyard: Put a decayed counter on each of X target creatures. Activate only as a sorcery.| +Salt Road Skirmish|Tarkir: Dragonstorm|88|U|{3}{B}|Sorcery|||Destroy target creature. Create two 1/1 red Warrior creature tokens. They gain haste until end of turn. Sacrifice them at the beginning of the next end step.| +Sandskitter Outrider|Tarkir: Dragonstorm|89|C|{3}{B}|Creature - Goblin Soldier|2|1|Menace$When this creature enters, it endures 2.| Scavenger Regent|Tarkir: Dragonstorm|90|R|{3}{B}|Creature - Dragon|4|4|Flying$Ward--Discard a card.| Exude Toxin|Tarkir: Dragonstorm|90|R|{X}{B}{B}|Sorcery - Omen|4|4|Each non-Dragon creature gets -X/-X until end of turn.| The Sibsig Ceremony|Tarkir: Dragonstorm|91|R|{B}{B}{B}|Legendary Enchantment|||Creature spells you cast cost {2} less to cast.$Whenever a creature you control enters, if you cast it, destroy that creature, then create a 2/2 black Zombie Druid creature token.| Sidisi, Regent of the Mire|Tarkir: Dragonstorm|92|R|{1}{B}|Legendary Creature - Zombie Snake Warlock|1|3|{T}, Sacrifice a creature you control with mana value X other than Sidisi: Return target creature card with mana value X plus 1 from your graveyard to the battlefield. Activate only as a sorcery.| Sinkhole Surveyor|Tarkir: Dragonstorm|93|R|{1}{B}|Creature - Bird Scout|1|3|Flying$Whenever this creature attacks, you lose 1 life and this creature endures 1.| +Strategic Betrayal|Tarkir: Dragonstorm|94|U|{1}{B}|Sorcery|||Target opponent exiles a creature they control and their graveyard.| +Unburied Earthcarver|Tarkir: Dragonstorm|95|C|{1}{B}|Creature - Human Warrior|2|2|{2}, Sacrifice another creature: Put a +1/+1 counter on this creature.| Unrooted Ancestor|Tarkir: Dragonstorm|96|U|{2}{B}|Creature - Spirit Cleric|3|2|Flash${1}, Sacrifice another creature: This creature gains indestructible until end of turn. Tap it.| Venerated Stormsinger|Tarkir: Dragonstorm|97|U|{3}{B}|Creature - Orc Cleric|3|3|Mobilize 1$Whenever this creature or another creature you control dies, each opponent loses 1 life and you gain 1 life.| Wail of War|Tarkir: Dragonstorm|98|U|{2}{B}|Instant|||Choose one --$* Creatures target opponent controls get -1/-1 until end of turn.$* Return up to two target creature cards from your graveyard to your hand.| @@ -57288,41 +57310,57 @@ Devoted Duelist|Tarkir: Dragonstorm|104|C|{1}{R}|Creature - Goblin Monk|2|1|Hast Dracogenesis|Tarkir: Dragonstorm|105|M|{6}{R}{R}|Enchantment|||You may cast Dragon spells without paying their mana costs.| Equilibrium Adept|Tarkir: Dragonstorm|106|U|{3}{R}|Creature - Dog Monk|2|4|When this creature enters, exile the top card of your library. Until the end of your next turn, you may play that card.$Flurry -- Whenever you cast your second spell each turn, this creature gains double strike until end of turn.| Fire-Rim Form|Tarkir: Dragonstorm|107|C|{1}{R}|Enchantment - Aura|||Flash$Enchant creature$When this Aura enters, enchanted creature gains first strike until end of turn.$Enchanted creature gets +2/+0.| +Fleeting Effigy|Tarkir: Dragonstorm|108|U|{R}|Creature - Elemental|2|2|Haste$At the beginning of your end step, return this creature to its owner's hand.$2{R}: This creature gets +2/+0 until end of turn.| +Iridescent Tiger|Tarkir: Dragonstorm|109|U|{4}{R}|Creature - Cat|3|4|When this creature enters, if you cast it, add {W}{U}{B}{R}{G}.| Jeskai Devotee|Tarkir: Dragonstorm|110|C|{1}{R}|Creature - Orc Monk|2|2|Flurry -- Whenever you cast your second spell each turn, this creature gets +1/+1 until end of turn.${1}: Add {U}, {R}, or {W}. Activate only once each turn.| Magmatic Hellkite|Tarkir: Dragonstorm|111|R|{2}{R}{R}|Creature - Dragon|4|5|Flying$When this creature enters, destroy target nonbasic land an opponent controls. Its controller searches their library for a basic land card, puts it onto the battlefield tapped with a stun counter on it, then shuffles.| Meticulous Artisan|Tarkir: Dragonstorm|112|C|{3}{R}|Creature - Djinn Artificer|3|3|Prowess$When this creature enters, create a Treasure token.| Molten Exhale|Tarkir: Dragonstorm|113|C|{1}{R}|Sorcery|||You may cast this spell as though it had flash if you behold a Dragon as an additional cost to cast it.$Molten Exhale deals 4 damage to target creature or planeswalker.| Narset's Rebuke|Tarkir: Dragonstorm|114|C|{4}{R}|Instant|||Narset's Rebuke deals 5 damage to target creature. Add {U}{R}{W}. If that creature would die this turn, exile it instead.| +Overwhelming Surge|Tarkir: Dragonstorm|115|U|{2}{R}|Instant|||Choose one or both --$* Overwhelming Surge deals 3 damage to target creature.$* Destroy target noncreature artifact.| +Rescue Leopard|Tarkir: Dragonstorm|116|C|{2}{R}|Creature - Cat|4|2|Whenever this creature becomes tapped, you may discard a card. If you do, draw a card.| Reverberating Summons|Tarkir: Dragonstorm|117|U|{1}{R}|Enchantment|||At the beginning of each combat, if you've cast two or more spells this turn, this enchantment becomes a 3/3 Monk creature with haste in addition to its other types until end of turn.${1}{R}, Discard your hand, Sacrifice this enchantment: Draw two cards.| Sarkhan, Dragon Ascendant|Tarkir: Dragonstorm|118|R|{1}{R}|Legendary Creature - Human Druid|2|2|When Sarkhan enters, you may behold a Dragon. If you do, create a Treasure token.$Whenever a Dragon you control enters, put a +1/+1 counter on Sarkhan. Until end of turn, Sarkhan becomes a Dragon in addition to its other types and gains flying.| Seize Opportunity|Tarkir: Dragonstorm|119|C|{2}{R}|Instant|||Choose one --$* Exile the top two cards of your library. Until the end of your next turn, you may play those cards.$* Up to two target creatures each get +2/+1 until end of turn.| Shock Brigade|Tarkir: Dragonstorm|120|C|{1}{R}|Creature - Goblin Soldier|1|3|Menace$Mobilize 1| Shocking Sharpshooter|Tarkir: Dragonstorm|121|U|{1}{R}|Creature - Human Archer|1|3|Reach$Whenever another creature you control enters, this creature deals 1 damage to target opponent.| +Stadium Headliner|Tarkir: Dragonstorm|122|R|{R}|Creature - Goblin Warrior|1|1|Mobilize 1${1}{R}, Sacrifice this creature: It deals damage equal to the number of creatures you control to target creature.| Stormscale Scion|Tarkir: Dragonstorm|123|M|{4}{R}{R}|Creature - Dragon|4|4|Flying$Other Dragons you control get +1/+1.$Storm| Stormshriek Feral|Tarkir: Dragonstorm|124|C|{4}{R}|Creature - Dragon|3|3|Flying, haste${1}{R}: This creature gets +1/+0 until end of turn.| Flush Out|Tarkir: Dragonstorm|124|C|{1}{R}|Sorcery - Omen|3|3|Discard a card. If you do, draw two cards.| Summit Intimidator|Tarkir: Dragonstorm|125|C|{3}{R}|Creature - Yeti|4|3|Reach$When this creature enters, target creature can't block this turn.| Sunset Strikemaster|Tarkir: Dragonstorm|126|U|{1}{R}|Creature - Human Monk|3|1|{T}: Add {R}.${2}{R}, {T}, Sacrifice this creature: It deals 6 damage to target creature with flying.| Tersa Lightshatter|Tarkir: Dragonstorm|127|R|{2}{R}|Legendary Creature - Orc Wizard|3|3|Haste$When Tersa Lightshatter enters, discard up to two cards, then draw that many cards.$Whenever Tersa Lightshatter attacks, if there are seven or more cards in your graveyard, exile a card at random from your graveyard. You may play that card this turn.| +Twin Bolt|Tarkir: Dragonstorm|128|C|{1}{R}|Instant|||Twin Bolt deals 2 damage divided as you choose among one or two targets.| Underfoot Underdogs|Tarkir: Dragonstorm|129|C|{2}{R}|Creature - Goblin Warrior|1|2|When this creature enters, create a 1/1 red Goblin creature token.${1}, {T}: Target creature you control with power 2 or less can't be blocked this turn.| Unsparing Boltcaster|Tarkir: Dragonstorm|130|U|{2}{R}|Creature - Ogre Wizard|3|3|When this creature enters, it deals 5 damage to target creature an opponent controls that was dealt damage this turn.| War Effort|Tarkir: Dragonstorm|131|U|{3}{R}|Enchantment|||Creatures you control get +1/+0.$Whenever you attack, create a 1/1 red Warrior creature token that's tapped and attacking. Sacrifice it at the beginning of the next end step.| +Wild Ride|Tarkir: Dragonstorm|132|C|{R}|Sorcery|||Target creature gets +3/+0 and gains haste until end of turn.$Harmonize 4{R}| Zurgo's Vanguard|Tarkir: Dragonstorm|133|U|{2}{R}|Creature - Dog Soldier|*|3|Mobilize 1$This creature's power is equal to the number of creatures you control.| +Ainok Wayfarer|Tarkir: Dragonstorm|134|C|{1}{G}|Creature - Dog Scout|1|1|When this creature enters, mill three cards. You may put a land card from among them into your hand. If you don't, put a +1/+1 counter on this creature.| Attuned Hunter|Tarkir: Dragonstorm|135|U|{2}{G}|Creature - Human Ranger|3|3|Trample$Whenever one or more cards leave your graveyard during your turn, put a +1/+1 counter on this creature.| Bloomvine Regent|Tarkir: Dragonstorm|136|R|{3}{G}{G}|Creature - Dragon|4|5|Flying$Whenever this creature or another Dragon you control enters, you gain 3 life.| Claim Territory|Tarkir: Dragonstorm|136|R|{2}{G}|Sorcery - Omen|4|5|Search your library for up to two basic Forest cards, reveal them, put one onto the battlefield tapped and the other into your hand, then shuffle.| +Champion of Dusan|Tarkir: Dragonstorm|137|C|{2}{G}|Creature - Human Warrior|4|2|Trample$Renew -- {1}{G}, Exile this card from your graveyard: Put a +1/+1 counter and a trample counter on target creature. Activate only as a sorcery.| Craterhoof Behemoth|Tarkir: Dragonstorm|138|M|{5}{G}{G}{G}|Creature - Beast|5|5|Haste$When this creature enters, creatures you control gain trample and get +X/+X until end of turn, where X is the number of creatures you control.| +Dragon Sniper|Tarkir: Dragonstorm|139|U|{G}|Creature - Human Archer|1|1|Vigilance, reach, deathtouch| Dragonbroods' Relic|Tarkir: Dragonstorm|140|U|{1}{G}|Artifact|||{T}, Tap an untapped creature you control: Add one mana of any color.${3}{W}{U}{B}{R}{G}, Sacrifice this artifact: Create a 4/4 Dragon creature token named Reliquary Dragon that's all colors. It has flying, lifelink, and "When this token enters, it deals 3 damage to any target." Activate only as a sorcery.| Dusyut Earthcarver|Tarkir: Dragonstorm|141|C|{5}{G}|Creature - Elephant Druid|4|4|Reach$When this creature enters, it endures 3.| Encroaching Dragonstorm|Tarkir: Dragonstorm|142|U|{3}{G}|Enchantment|||When this enchantment enters, search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle.$When a Dragon you control enters, return this enchantment to its owner's hand.| +Formation Breaker|Tarkir: Dragonstorm|143|U|{1}{G}|Creature - Beast|2|1|Creatures with power less than this creature's power can't block it.$As long as you control a creature with a counter on it, this creature gets +1/+2| Herd Heirloom|Tarkir: Dragonstorm|144|R|{1}{G}|Artifact|||{T}: Add one mana of any color. Spend this mana only to cast a creature spell.${T}: Until end of turn, target creature you control with power 4 or greater gains trample and "Whenever this creature deals combat damage to a player, draw a card."| Heritage Reclamation|Tarkir: Dragonstorm|145|C|{1}{G}|Instant|||Choose one --$* Destroy target artifact.$* Destroy target enchantment.$* Exile up to one target card from a graveyard. Draw a card.| +Inspirited Vanguard|Tarkir: Dragonstorm|146|U|{4}{G}|Creature - Human Soldier|3|2|Whenever this creature enters or attacks, it endures 2.| +Knockout Maneuver|Tarkir: Dragonstorm|147|U|{2}{G}|Sorcery|||Put a +1/+1 counter on target creature you control, then it deals damage equal to its power to target creature an opponent controls.| Krotiq Nestguard|Tarkir: Dragonstorm|148|C|{2}{G}|Creature - Insect|4|4|Defender${2}{G}: This creature can attack this turn as though it didn't have defender.| Lasyd Prowler|Tarkir: Dragonstorm|149|R|{2}{G}{G}|Creature - Snake Ranger|5|5|When this creature enters, you may mill cards equal to the number of lands you control.$Renew -- {1}{G}, Exile this card from your graveyard: Put X +1/+1 counters on target creature, where X is the number of land cards in your graveyard. Activate only as a sorcery.| Nature's Rhythm|Tarkir: Dragonstorm|150|R|{X}{G}{G}|Sorcery|||Search your library for a creature card with mana value X or less, put it onto the battlefield, then shuffle.$Harmonize {X}{G}{G}{G}{G}| Piercing Exhale|Tarkir: Dragonstorm|151|C|{1}{G}|Instant|||As an additional cost to cast this spell, you may behold a Dragon.$Target creature you control deals damage equal to its power to target creature or planeswalker. If a Dragon was beheld, surveil 2.| +Rainveil Rejuvenator|Tarkir: Dragonstorm|152|U|{3}{G}|Creature - Elephant Druid|2|4|When this creature enters, you may mill three cards.${T}: Add an amount of {G} equal to this creature's power.| Rite of Renewal|Tarkir: Dragonstorm|153|U|{3}{G}|Sorcery|||Return up to two target permanent cards from your graveyard to your hand. Target player shuffles up to four target cards from their graveyard into their library. Exile Rite of Renewal.| Roamer's Routine|Tarkir: Dragonstorm|154|C|{2}{G}|Sorcery|||Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.$Harmonize {4}{G}| +Sage of the Fang|Tarkir: Dragonstorm|155|U|{2}{G}|Creature - Human Druid|2|2|When this creature enters, put a +1/+1 counter on target creature.$Renew -- {3}{G}, Exile this card from your graveyard: Put a +1/+1 counter on target creature, then double the number of +1/+1 counters on that creature.| +Sagu Pummeler|Tarkir: Dragonstorm|156|C|{3}{G}|Creature - Beast|4|4|Reach$Renew -- {4}{G}, Exile this card from your graveyard: Put two +1/+1 counters and a reach counter on target creature. Activate only as a sorcery.| Sagu Wildling|Tarkir: Dragonstorm|157|C|{4}{G}|Creature - Dragon|3|3|Flying$When this creature enters, you gain 3 life.| Roost Seek|Tarkir: Dragonstorm|157|C|{G}|Sorcery - Omen|3|3|Search your library for a basic land card, reveal it, put it into your hand, then shuffle.| Sarkhan's Resolve|Tarkir: Dragonstorm|158|C|{1}{G}|Instant|||Choose one --$* Target creature gets +3/+3 until end of turn.$* Destroy target creature with flying.| @@ -57330,11 +57368,12 @@ Snakeskin Veil|Tarkir: Dragonstorm|159|C|{G}|Instant|||Put a +1/+1 counter on ta Sultai Devotee|Tarkir: Dragonstorm|160|C|{1}{G}|Creature - Zombie Snake Druid|2|1|Deathtouch${1}: Add {B}, {G}, or {U}. Activate only once each turn.| Surrak, Elusive Hunter|Tarkir: Dragonstorm|161|R|{2}{G}|Legendary Creature - Human Warrior|4|3|This spell can't be countered.$Trample$Whenever a creature you control or a creature spell you control becomes the target of a spell or ability an opponent controls, draw a card.| Synchronized Charge|Tarkir: Dragonstorm|162|U|{1}{G}|Sorcery|||Distribute two +1/+1 counters among one or two target creatures you control. Creatures you control with counters on them gain vigilance and trample until end of turn.$Harmonize {4}{G}| +Trade Route Envoy|Tarkir: Dragonstorm|163|C|{3}{G}|Creature - Dog Soldier|4|3|When this creature enters, draw a card if you control a creature with a counter on it. If you don't draw a card this way, put a +1/+1 counter on this creature.| Traveling Botanist|Tarkir: Dragonstorm|164|U|{1}{G}|Creature - Dog Scout|2|3|Whenever this creature becomes tapped, look at the top card of your library. If it's a land card, you may reveal it and put it into your hand. If you don't put the card into your hand, you may put it into your graveyard.| Undergrowth Leopard|Tarkir: Dragonstorm|165|C|{1}{G}|Creature - Cat|2|2|Vigilance${1}, Sacrifice this creature: Destroy target artifact or enchantment.| Warden of the Grove|Tarkir: Dragonstorm|166|R|{2}{G}|Creature - Hydra|2|2|At the beginning of your end step, put a +1/+1 counter on this creature.$Whenever another nontoken creature you control enters, it endures X, where X is the number of counters on this creature.| All-Out Assault|Tarkir: Dragonstorm|167|M|{2}{R}{W}{B}|Enchantment|||Creatures you control get +1/+1 and have deathtouch.$When this enchantment enters, if it's your main phase, there is an additional combat phase after this phase followed by an additional main phase. When you next attack this turn, untap each creature you control.| -Armament Dragon|Tarkir: Dragonstorm|168|U|{3}{W}{B}{G}|Creature -- Dragon|3|4|Flying$When this creature enters, distribute three +1/+1 counters among one, two, or three target creatures you control.| +Armament Dragon|Tarkir: Dragonstorm|168|U|{3}{W}{B}{G}|Creature - Dragon|3|4|Flying$When this creature enters, distribute three +1/+1 counters among one, two, or three target creatures you control.| Auroral Procession|Tarkir: Dragonstorm|169|U|{G}{U}|Instant|||Return target card from your graveyard to your hand.| Awaken the Honored Dead|Tarkir: Dragonstorm|170|R|{B}{G}{U}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- Destroy target nonland permanent.$II -- Mill three cards.$III -- You may discard a card. When you do, return target creature or land card from your graveyard to your hand.| Barrensteppe Siege|Tarkir: Dragonstorm|171|R|{2}{W}{B}|Enchantment|||As this enchantment enters, choose Abzan or Mardu.$* Abzan -- At the beginning of your end step, put a +1/+1 counter on each creature you control.$* Mardu -- At the beginning of your end step, if a creature died under your control this turn, each opponent sacrifices a creature of their choice.| @@ -57347,6 +57386,7 @@ Defibrillating Current|Tarkir: Dragonstorm|177|U|{2/R}{2/W}{2/B}|Sorcery|||Defib Disruptive Stormbrood|Tarkir: Dragonstorm|178|U|{4}{G}|Creature - Dragon|3|3|Flying$When this creature enters, destroy up to one target artifact or enchantment.| Petty Revenge|Tarkir: Dragonstorm|178|U|{1}{B}|Sorcery - Omen|3|3|Destroy target creature with power 3 or less.| Dragonback Assault|Tarkir: Dragonstorm|179|M|{3}{G}{U}{R}|Enchantment|||When this enchantment enters, it deals 3 damage to each creature and each planeswalker.$Landfall -- Whenever a land you control enters, create a 4/4 red Dragon creature token with flying.| +Dragonclaw Strike|Tarkir: Dragonstorm|180|U|{2/U}{2/R}{2/G}|Sorcery|||Double the power and toughness of target creature you control until end of turn. Then it fights up to one target creature an opponent controls.| Effortless Master|Tarkir: Dragonstorm|181|U|{2}{U}{R}|Creature - Orc Monk|4|3|Vigilance$Menace$This creature enters with two +1/+1 counters on it if you've cast two or more spells this turn.| Eshki Dragonclaw|Tarkir: Dragonstorm|182|R|{1}{G}{U}{R}|Legendary Creature - Human Warrior|4|4|Vigilance, trample, ward {1}$At the beginning of combat on your turn, if you've cast both a creature spell and a noncreature spell this turn, draw a card and put two +1/+1 counters on Eshki Dragonclaw.| Fangkeeper's Familiar|Tarkir: Dragonstorm|183|R|{1}{B}{G}{U}|Creature - Snake|3|3|Flash$When this creature enters, choose one --$* You gain 3 life and surveil 3.$* Destroy target enchantment.$* Counter target creature spell.| @@ -57384,6 +57424,7 @@ Absorb Essence|Tarkir: Dragonstorm|213|U|{1}{W}|Instant - Omen|4|4|Target creatu Rakshasa's Bargain|Tarkir: Dragonstorm|214|U|{2/B}{2/G}{2/U}|Instant|||Look at the top four cards of your library. Put two of them into your hand and the rest into your graveyard.| Rediscover the Way|Tarkir: Dragonstorm|215|R|{U}{R}{W}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I, II -- Look at the top three cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order.$III -- Whenever you cast a noncreature spell this turn, target creature you control gains double strike until end of turn.| Reigning Victor|Tarkir: Dragonstorm|216|C|{2/R}{2/W}{2/B}|Creature - Orc Warrior|3|3|Mobilize 1$When this creature enters, target creature gets +1/+0 and gains indestructible until end of turn.| +Reputable Merchant|Tarkir: Dragonstorm|217|C|{2/W}{2/B}{2/G}|Creature - Human Citizen|2|2|When this creature enters or dies, put a +1/+1 counter on target creature you control.| Revival of the Ancestors|Tarkir: Dragonstorm|218|R|{1}{W}{B}{G}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I -- Create three 1/1 white Spirit creature tokens.$II -- Distribute three +1/+1 counters among one, two, or three target creatures you control.$III -- Creatures you control gain trample and lifelink until end of turn.| Riverwheel Sweep|Tarkir: Dragonstorm|219|U|{2/U}{2/R}{2/W}|Sorcery|||Tap target creature. Put three stun counters on it.$Exile the top two cards of your library. Choose one of them. Until the end of your next turn, you may play that card.| Roar of Endless Song|Tarkir: Dragonstorm|220|R|{2}{G}{U}{R}|Enchantment - Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I, II -- Create a 5/5 green Elephant creature token.$III -- Double the power and toughness of each creature you control until end of turn.| @@ -57446,7 +57487,6 @@ Island|Tarkir: Dragonstorm|279|C||Basic Land - Island|||({T}: Add {U}.)| Swamp|Tarkir: Dragonstorm|281|C||Basic Land - Swamp|||({T}: Add {B}.)| Mountain|Tarkir: Dragonstorm|283|C||Basic Land - Mountain|||({T}: Add {R}.)| Forest|Tarkir: Dragonstorm|285|C||Basic Land - Forest|||({T}: Add {G}.)| -Strategic Betrayal|Tarkir: Dragonstorm|422|U|{1}{B}|Sorcery|||Target opponent exiles a creature they control and their graveyard.| Betor, Ancestor's Voice|Tarkir: Dragonstorm Commander|1|M|{2}{W}{B}{G}|Legendary Creature - Spirit Dragon|3|5|Flying, lifelink$At the beginning of your end step, put a number of +1/+1 counters on up to one other target creature you control equal to the amount of life you gained this turn. Return up to one target creature card with mana value less than or equal to the amount of life you lost this turn from your graveyard to the battlefield.| Elsha, Threefold Master|Tarkir: Dragonstorm Commander|2|M|{U}{R}{W}|Legendary Creature - Djinn Monk|1|1|Trample$Prowess$Whenever Elsha deals combat damage to a player, create that many 1/1 white Monk creature tokens with prowess.| Eshki, Temur's Roar|Tarkir: Dragonstorm Commander|3|M|{G}{U}{R}|Legendary Creature - Human Warrior|2|2|Whenever you cast a creature spell, put a +1/+1 counter on Eshki. If that spell's power is 4 or greater, draw a card. If that spell's power is 6 or greater, Eshki deals damage equal to Eshki's power to each opponent.| From 8a98d2c40fce141c7080e9eb41ac1f31d427de2e Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 21:57:18 -0400 Subject: [PATCH 17/49] [TDM] Implement Wingblade Disciple --- .../src/mage/cards/w/WingbladeDisciple.java | 43 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 44 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WingbladeDisciple.java diff --git a/Mage.Sets/src/mage/cards/w/WingbladeDisciple.java b/Mage.Sets/src/mage/cards/w/WingbladeDisciple.java new file mode 100644 index 00000000000..e1c925d30e7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WingbladeDisciple.java @@ -0,0 +1,43 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.FlurryAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.BirdToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WingbladeDisciple extends CardImpl { + + public WingbladeDisciple(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Flurry -- Whenever you cast your second spell each turn, create a 1/1 white Bird creature token with flying. + this.addAbility(new FlurryAbility(new CreateTokenEffect(new BirdToken()))); + } + + private WingbladeDisciple(final WingbladeDisciple card) { + super(card); + } + + @Override + public WingbladeDisciple copy() { + return new WingbladeDisciple(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 9f2391c1230..8d0a49853e2 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -170,6 +170,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Voice of Victory", 33, Rarity.RARE, mage.cards.v.VoiceOfVictory.class)); cards.add(new SetCardInfo("Watcher of the Wayside", 249, Rarity.COMMON, mage.cards.w.WatcherOfTheWayside.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 271, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); + cards.add(new SetCardInfo("Wingblade Disciple", 65, Rarity.UNCOMMON, mage.cards.w.WingbladeDisciple.class)); cards.add(new SetCardInfo("Wingspan Stride", 66, Rarity.COMMON, mage.cards.w.WingspanStride.class)); cards.add(new SetCardInfo("Winternight Stories", 67, Rarity.RARE, mage.cards.w.WinternightStories.class)); cards.add(new SetCardInfo("Worthy Cost", 99, Rarity.COMMON, mage.cards.w.WorthyCost.class)); From a09943f25acf3d2c24c59967fecd4c7d4c11668e Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 21:58:02 -0400 Subject: [PATCH 18/49] [TDM] Implement Sandskitter Outrider --- .../src/mage/cards/s/SandskitterOutrider.java | 42 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SandskitterOutrider.java diff --git a/Mage.Sets/src/mage/cards/s/SandskitterOutrider.java b/Mage.Sets/src/mage/cards/s/SandskitterOutrider.java new file mode 100644 index 00000000000..1904c7d10ec --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SandskitterOutrider.java @@ -0,0 +1,42 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.EndureSourceEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SandskitterOutrider extends CardImpl { + + public SandskitterOutrider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Menace + this.addAbility(new MenaceAbility()); + + // When this creature enters, it endures 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new EndureSourceEffect(2))); + } + + private SandskitterOutrider(final SandskitterOutrider card) { + super(card); + } + + @Override + public SandskitterOutrider copy() { + return new SandskitterOutrider(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 8d0a49853e2..0e248caca0c 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -130,6 +130,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Roiling Dragonstorm", 55, Rarity.UNCOMMON, mage.cards.r.RoilingDragonstorm.class)); cards.add(new SetCardInfo("Rugged Highlands", 265, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); cards.add(new SetCardInfo("Salt Road Packbeast", 23, Rarity.COMMON, mage.cards.s.SaltRoadPackbeast.class)); + cards.add(new SetCardInfo("Sandskitter Outrider", 89, Rarity.COMMON, mage.cards.s.SandskitterOutrider.class)); cards.add(new SetCardInfo("Sandsteppe Citadel", 266, Rarity.UNCOMMON, mage.cards.s.SandsteppeCitadel.class)); cards.add(new SetCardInfo("Sarkhan's Resolve", 158, Rarity.COMMON, mage.cards.s.SarkhansResolve.class)); cards.add(new SetCardInfo("Scoured Barrens", 267, Rarity.COMMON, mage.cards.s.ScouredBarrens.class)); From c77fbe2a888f029a1a26e52d92d7e41a57b68e81 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 21:59:13 -0400 Subject: [PATCH 19/49] [TDM] Implement Sagu Pummeler --- Mage.Sets/src/mage/cards/s/SaguPummeler.java | 45 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 46 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SaguPummeler.java diff --git a/Mage.Sets/src/mage/cards/s/SaguPummeler.java b/Mage.Sets/src/mage/cards/s/SaguPummeler.java new file mode 100644 index 00000000000..dcad1d18f74 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SaguPummeler.java @@ -0,0 +1,45 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.RenewAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SaguPummeler extends CardImpl { + + public SaguPummeler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Renew -- {4}{G}, Exile this card from your graveyard: Put two +1/+1 counters and a reach counter on target creature. Activate only as a sorcery. + this.addAbility(new RenewAbility( + "{4}{G}", + CounterType.P1P1.createInstance(2), + CounterType.REACH.createInstance() + )); + } + + private SaguPummeler(final SaguPummeler card) { + super(card); + } + + @Override + public SaguPummeler copy() { + return new SaguPummeler(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 0e248caca0c..36f3aeadbf0 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -129,6 +129,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Roar of Endless Song", 220, Rarity.RARE, mage.cards.r.RoarOfEndlessSong.class)); cards.add(new SetCardInfo("Roiling Dragonstorm", 55, Rarity.UNCOMMON, mage.cards.r.RoilingDragonstorm.class)); cards.add(new SetCardInfo("Rugged Highlands", 265, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); + cards.add(new SetCardInfo("Sagu Pummeler", 156, Rarity.COMMON, mage.cards.s.SaguPummeler.class)); cards.add(new SetCardInfo("Salt Road Packbeast", 23, Rarity.COMMON, mage.cards.s.SaltRoadPackbeast.class)); cards.add(new SetCardInfo("Sandskitter Outrider", 89, Rarity.COMMON, mage.cards.s.SandskitterOutrider.class)); cards.add(new SetCardInfo("Sandsteppe Citadel", 266, Rarity.UNCOMMON, mage.cards.s.SandsteppeCitadel.class)); From efa746b8084734306549f6c873a0027dd10d2636 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 22:01:22 -0400 Subject: [PATCH 20/49] [TDM] Implement Reputable Merchant --- .../src/mage/cards/r/ReputableMerchant.java | 45 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 46 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/ReputableMerchant.java diff --git a/Mage.Sets/src/mage/cards/r/ReputableMerchant.java b/Mage.Sets/src/mage/cards/r/ReputableMerchant.java new file mode 100644 index 00000000000..808a913f665 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ReputableMerchant.java @@ -0,0 +1,45 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldOrDiesSourceTriggeredAbility; +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.counters.CounterType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ReputableMerchant extends CardImpl { + + public ReputableMerchant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2/W}{2/B}{2/G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CITIZEN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When this creature enters or dies, put a +1/+1 counter on target creature you control. + Ability ability = new EntersBattlefieldOrDiesSourceTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private ReputableMerchant(final ReputableMerchant card) { + super(card); + } + + @Override + public ReputableMerchant copy() { + return new ReputableMerchant(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 36f3aeadbf0..d6179d7f5b9 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -124,6 +124,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Rally the Monastery", 19, Rarity.UNCOMMON, mage.cards.r.RallyTheMonastery.class)); cards.add(new SetCardInfo("Rebellious Strike", 20, Rarity.COMMON, mage.cards.r.RebelliousStrike.class)); cards.add(new SetCardInfo("Reigning Victor", 216, Rarity.COMMON, mage.cards.r.ReigningVictor.class)); + cards.add(new SetCardInfo("Reputable Merchant", 217, Rarity.COMMON, mage.cards.r.ReputableMerchant.class)); cards.add(new SetCardInfo("Ringing Strike Mastery", 53, Rarity.COMMON, mage.cards.r.RingingStrikeMastery.class)); cards.add(new SetCardInfo("Roamer's Routine", 154, Rarity.COMMON, mage.cards.r.RoamersRoutine.class)); cards.add(new SetCardInfo("Roar of Endless Song", 220, Rarity.RARE, mage.cards.r.RoarOfEndlessSong.class)); From e93f48b989762e9f76ea5d4a8477cef0fdc74166 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 22:02:44 -0400 Subject: [PATCH 21/49] [TDM] Implement Poised Practitioner --- .../src/mage/cards/p/PoisedPractitioner.java | 43 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 44 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/p/PoisedPractitioner.java diff --git a/Mage.Sets/src/mage/cards/p/PoisedPractitioner.java b/Mage.Sets/src/mage/cards/p/PoisedPractitioner.java new file mode 100644 index 00000000000..5195c3a0a28 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PoisedPractitioner.java @@ -0,0 +1,43 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.FlurryAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PoisedPractitioner extends CardImpl { + + public PoisedPractitioner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flurry -- Whenever you cast your second spell each turn, put a +1/+1 counter on this creature. Scry 1. + Ability ability = new FlurryAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + ability.addEffect(new ScryEffect(1)); + this.addAbility(ability); + } + + private PoisedPractitioner(final PoisedPractitioner card) { + super(card); + } + + @Override + public PoisedPractitioner copy() { + return new PoisedPractitioner(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index d6179d7f5b9..b07b6c3b547 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -119,6 +119,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Osseous Exhale", 17, Rarity.COMMON, mage.cards.o.OsseousExhale.class)); cards.add(new SetCardInfo("Piercing Exhale", 151, Rarity.COMMON, mage.cards.p.PiercingExhale.class)); cards.add(new SetCardInfo("Plains", 277, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Poised Practitioner", 18, Rarity.COMMON, mage.cards.p.PoisedPractitioner.class)); cards.add(new SetCardInfo("Qarsi Revenant", 86, Rarity.RARE, mage.cards.q.QarsiRevenant.class)); cards.add(new SetCardInfo("Rakshasa's Bargain", 214, Rarity.UNCOMMON, mage.cards.r.RakshasasBargain.class)); cards.add(new SetCardInfo("Rally the Monastery", 19, Rarity.UNCOMMON, mage.cards.r.RallyTheMonastery.class)); From 45bd8d4ce616a7b2efc06fd1f75cb5ccf2c03eb8 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 22:03:14 -0400 Subject: [PATCH 22/49] [TDM] Implement Nightblade Brigade --- .../src/mage/cards/n/NightbladeBrigade.java | 46 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 47 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/n/NightbladeBrigade.java diff --git a/Mage.Sets/src/mage/cards/n/NightbladeBrigade.java b/Mage.Sets/src/mage/cards/n/NightbladeBrigade.java new file mode 100644 index 00000000000..2002ced44ad --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NightbladeBrigade.java @@ -0,0 +1,46 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.MobilizeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NightbladeBrigade extends CardImpl { + + public NightbladeBrigade(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Mobilize 1 + this.addAbility(new MobilizeAbility(1)); + + // When this creature enters, surveil 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SurveilEffect(1))); + } + + private NightbladeBrigade(final NightbladeBrigade card) { + super(card); + } + + @Override + public NightbladeBrigade copy() { + return new NightbladeBrigade(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index b07b6c3b547..48386dce0f3 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -114,6 +114,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Narset, Jeskai Waymaster", 209, Rarity.RARE, mage.cards.n.NarsetJeskaiWaymaster.class)); cards.add(new SetCardInfo("Nature's Rhythm", 150, Rarity.RARE, mage.cards.n.NaturesRhythm.class)); cards.add(new SetCardInfo("Neriv, Heart of the Storm", 210, Rarity.MYTHIC, mage.cards.n.NerivHeartOfTheStorm.class)); + cards.add(new SetCardInfo("Nightblade Brigade", 85, Rarity.COMMON, mage.cards.n.NightbladeBrigade.class)); cards.add(new SetCardInfo("Nomad Outpost", 263, Rarity.UNCOMMON, mage.cards.n.NomadOutpost.class)); cards.add(new SetCardInfo("Opulent Palace", 264, Rarity.UNCOMMON, mage.cards.o.OpulentPalace.class)); cards.add(new SetCardInfo("Osseous Exhale", 17, Rarity.COMMON, mage.cards.o.OsseousExhale.class)); From 2a4d2cb1c2c75b1640de4dc897763470970cdd04 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 22:04:05 -0400 Subject: [PATCH 23/49] [TDM] Implement Kin-Tree Nurturer --- .../src/mage/cards/k/KinTreeNurturer.java | 42 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 43 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/k/KinTreeNurturer.java diff --git a/Mage.Sets/src/mage/cards/k/KinTreeNurturer.java b/Mage.Sets/src/mage/cards/k/KinTreeNurturer.java new file mode 100644 index 00000000000..abba7ff3cd9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KinTreeNurturer.java @@ -0,0 +1,42 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.EndureSourceEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KinTreeNurturer extends CardImpl { + + public KinTreeNurturer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // When this creature enters, it endures 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new EndureSourceEffect(1))); + } + + private KinTreeNurturer(final KinTreeNurturer card) { + super(card); + } + + @Override + public KinTreeNurturer copy() { + return new KinTreeNurturer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 48386dce0f3..32206fe66a9 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -95,6 +95,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Jeskai Shrinekeeper", 197, Rarity.UNCOMMON, mage.cards.j.JeskaiShrinekeeper.class)); cards.add(new SetCardInfo("Jungle Hollow", 258, Rarity.COMMON, mage.cards.j.JungleHollow.class)); cards.add(new SetCardInfo("Kheru Goldkeeper", 199, Rarity.UNCOMMON, mage.cards.k.KheruGoldkeeper.class)); + cards.add(new SetCardInfo("Kin-Tree Nurturer", 83, Rarity.COMMON, mage.cards.k.KinTreeNurturer.class)); cards.add(new SetCardInfo("Kin-Tree Severance", 200, Rarity.UNCOMMON, mage.cards.k.KinTreeSeverance.class)); cards.add(new SetCardInfo("Kishla Skimmer", 201, Rarity.UNCOMMON, mage.cards.k.KishlaSkimmer.class)); cards.add(new SetCardInfo("Kishla Trawlers", 50, Rarity.UNCOMMON, mage.cards.k.KishlaTrawlers.class)); From 7a8e3d3c7d1abc4f4605d8f9ce0beae29255311f Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 22:07:37 -0400 Subject: [PATCH 24/49] [TDM] Implement Overwhelming Surge --- .../src/mage/cards/o/OverwhelmingSurge.java | 44 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 45 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/o/OverwhelmingSurge.java diff --git a/Mage.Sets/src/mage/cards/o/OverwhelmingSurge.java b/Mage.Sets/src/mage/cards/o/OverwhelmingSurge.java new file mode 100644 index 00000000000..d7734ac4db0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OverwhelmingSurge.java @@ -0,0 +1,44 @@ +package mage.cards.o; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OverwhelmingSurge extends CardImpl { + + public OverwhelmingSurge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); + + // Choose one or both -- + this.getSpellAbility().getModes().setMinModes(1); + this.getSpellAbility().getModes().setMaxModes(2); + + // * Overwhelming Surge deals 3 damage to target creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // * Destroy target noncreature artifact. + this.getSpellAbility().addMode(new Mode(new DestroyTargetEffect()) + .addTarget(new TargetPermanent(StaticFilters.FILTER_ARTIFACT_NON_CREATURE))); + } + + private OverwhelmingSurge(final OverwhelmingSurge card) { + super(card); + } + + @Override + public OverwhelmingSurge copy() { + return new OverwhelmingSurge(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 32206fe66a9..77f1b6fb172 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -119,6 +119,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Nomad Outpost", 263, Rarity.UNCOMMON, mage.cards.n.NomadOutpost.class)); cards.add(new SetCardInfo("Opulent Palace", 264, Rarity.UNCOMMON, mage.cards.o.OpulentPalace.class)); cards.add(new SetCardInfo("Osseous Exhale", 17, Rarity.COMMON, mage.cards.o.OsseousExhale.class)); + cards.add(new SetCardInfo("Overwhelming Surge", 115, Rarity.UNCOMMON, mage.cards.o.OverwhelmingSurge.class)); cards.add(new SetCardInfo("Piercing Exhale", 151, Rarity.COMMON, mage.cards.p.PiercingExhale.class)); cards.add(new SetCardInfo("Plains", 277, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Poised Practitioner", 18, Rarity.COMMON, mage.cards.p.PoisedPractitioner.class)); From c1884d156551185c9b9203c93f6eeb05cd78e0ad Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 22:08:16 -0400 Subject: [PATCH 25/49] [TDM] Implement Inspirited Vanguard --- .../src/mage/cards/i/InspiritedVanguard.java | 38 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 39 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/i/InspiritedVanguard.java diff --git a/Mage.Sets/src/mage/cards/i/InspiritedVanguard.java b/Mage.Sets/src/mage/cards/i/InspiritedVanguard.java new file mode 100644 index 00000000000..48dc148a261 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InspiritedVanguard.java @@ -0,0 +1,38 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.effects.keyword.EndureSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InspiritedVanguard extends CardImpl { + + public InspiritedVanguard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever this creature enters or attacks, it endures 2. + this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new EndureSourceEffect(2))); + } + + private InspiritedVanguard(final InspiritedVanguard card) { + super(card); + } + + @Override + public InspiritedVanguard copy() { + return new InspiritedVanguard(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 77f1b6fb172..637730e3d37 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -87,6 +87,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Hardened Tactician", 191, Rarity.UNCOMMON, mage.cards.h.HardenedTactician.class)); cards.add(new SetCardInfo("Heritage Reclamation", 145, Rarity.COMMON, mage.cards.h.HeritageReclamation.class)); cards.add(new SetCardInfo("Inevitable Defeat", 194, Rarity.RARE, mage.cards.i.InevitableDefeat.class)); + cards.add(new SetCardInfo("Inspirited Vanguard", 146, Rarity.UNCOMMON, mage.cards.i.InspiritedVanguard.class)); cards.add(new SetCardInfo("Island", 279, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jade-Cast Sentinel", 243, Rarity.COMMON, mage.cards.j.JadeCastSentinel.class)); cards.add(new SetCardInfo("Jeskai Brushmaster", 195, Rarity.UNCOMMON, mage.cards.j.JeskaiBrushmaster.class)); From 153925349465c8ee5a8ec23160edbe0170e8ba1d Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 22:09:53 -0400 Subject: [PATCH 26/49] [TDM] Implement Champion of Dusan --- .../src/mage/cards/c/ChampionOfDusan.java | 46 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 47 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/ChampionOfDusan.java diff --git a/Mage.Sets/src/mage/cards/c/ChampionOfDusan.java b/Mage.Sets/src/mage/cards/c/ChampionOfDusan.java new file mode 100644 index 00000000000..ab384f74f2b --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChampionOfDusan.java @@ -0,0 +1,46 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.RenewAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChampionOfDusan extends CardImpl { + + public ChampionOfDusan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Renew -- {1}{G}, Exile this card from your graveyard: Put a +1/+1 counter and a trample counter on target creature. Activate only as a sorcery. + this.addAbility(new RenewAbility( + "{1}{G}", + CounterType.P1P1.createInstance(), + CounterType.TRAMPLE.createInstance() + )); + } + + private ChampionOfDusan(final ChampionOfDusan card) { + super(card); + } + + @Override + public ChampionOfDusan copy() { + return new ChampionOfDusan(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 637730e3d37..3ce8f998c08 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -46,6 +46,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Breaching Dragonstorm", 101, Rarity.UNCOMMON, mage.cards.b.BreachingDragonstorm.class)); cards.add(new SetCardInfo("Call the Spirit Dragons", 174, Rarity.MYTHIC, mage.cards.c.CallTheSpiritDragons.class)); cards.add(new SetCardInfo("Caustic Exhale", 74, Rarity.COMMON, mage.cards.c.CausticExhale.class)); + cards.add(new SetCardInfo("Champion of Dusan", 137, Rarity.COMMON, mage.cards.c.ChampionOfDusan.class)); cards.add(new SetCardInfo("Channeled Dragonfire", 102, Rarity.UNCOMMON, mage.cards.c.ChanneledDragonfire.class)); cards.add(new SetCardInfo("Coordinated Maneuver", 6, Rarity.COMMON, mage.cards.c.CoordinatedManeuver.class)); cards.add(new SetCardInfo("Cori Mountain Monastery", 252, Rarity.RARE, mage.cards.c.CoriMountainMonastery.class)); From b1342f33f1244a43681d0e006ad27ca4d321dbdd Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 22:10:25 -0400 Subject: [PATCH 27/49] [TDM] Implement Dragon Sniper --- Mage.Sets/src/mage/cards/d/DragonSniper.java | 45 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 46 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/d/DragonSniper.java diff --git a/Mage.Sets/src/mage/cards/d/DragonSniper.java b/Mage.Sets/src/mage/cards/d/DragonSniper.java new file mode 100644 index 00000000000..336d59958f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DragonSniper.java @@ -0,0 +1,45 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DragonSniper extends CardImpl { + + public DragonSniper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ARCHER); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + } + + private DragonSniper(final DragonSniper card) { + super(card); + } + + @Override + public DragonSniper copy() { + return new DragonSniper(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 3ce8f998c08..cd844840d30 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -63,6 +63,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Dismal Backwater", 254, Rarity.COMMON, mage.cards.d.DismalBackwater.class)); cards.add(new SetCardInfo("Dispelling Exhale", 41, Rarity.COMMON, mage.cards.d.DispellingExhale.class)); cards.add(new SetCardInfo("Dracogenesis", 105, Rarity.MYTHIC, mage.cards.d.Dracogenesis.class)); + cards.add(new SetCardInfo("Dragon Sniper", 139, Rarity.UNCOMMON, mage.cards.d.DragonSniper.class)); cards.add(new SetCardInfo("Dragon's Prey", 79, Rarity.COMMON, mage.cards.d.DragonsPrey.class)); cards.add(new SetCardInfo("Dragonback Assault", 179, Rarity.MYTHIC, mage.cards.d.DragonbackAssault.class)); cards.add(new SetCardInfo("Dragonback Lancer", 9, Rarity.COMMON, mage.cards.d.DragonbackLancer.class)); From baeb75cca7846c7fb576f88e7bb07c9a7ce55663 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 22:12:36 -0400 Subject: [PATCH 28/49] [TDM] Implement Iridescent Tiger --- .../src/mage/cards/i/IridescentTiger.java | 41 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 42 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/i/IridescentTiger.java diff --git a/Mage.Sets/src/mage/cards/i/IridescentTiger.java b/Mage.Sets/src/mage/cards/i/IridescentTiger.java new file mode 100644 index 00000000000..d20ec915a85 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IridescentTiger.java @@ -0,0 +1,41 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.CastFromEverywhereSourceCondition; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IridescentTiger extends CardImpl { + + public IridescentTiger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When this creature enters, if you cast it, add {W}{U}{B}{R}{G}. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new BasicManaEffect(new Mana(1, 1, 1, 1, 1, 0, 0, 0)) + ).withInterveningIf(CastFromEverywhereSourceCondition.instance)); + } + + private IridescentTiger(final IridescentTiger card) { + super(card); + } + + @Override + public IridescentTiger copy() { + return new IridescentTiger(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index cd844840d30..2114d2e44ea 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -90,6 +90,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Heritage Reclamation", 145, Rarity.COMMON, mage.cards.h.HeritageReclamation.class)); cards.add(new SetCardInfo("Inevitable Defeat", 194, Rarity.RARE, mage.cards.i.InevitableDefeat.class)); cards.add(new SetCardInfo("Inspirited Vanguard", 146, Rarity.UNCOMMON, mage.cards.i.InspiritedVanguard.class)); + cards.add(new SetCardInfo("Iridescent Tiger", 109, Rarity.UNCOMMON, mage.cards.i.IridescentTiger.class)); cards.add(new SetCardInfo("Island", 279, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Jade-Cast Sentinel", 243, Rarity.COMMON, mage.cards.j.JadeCastSentinel.class)); cards.add(new SetCardInfo("Jeskai Brushmaster", 195, Rarity.UNCOMMON, mage.cards.j.JeskaiBrushmaster.class)); From a0ccbc741c47463c3a56b3113de96497c49760d4 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 22:14:00 -0400 Subject: [PATCH 29/49] [TDM] Implement Wild Ride --- Mage.Sets/src/mage/cards/w/WildRide.java | 44 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 45 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WildRide.java diff --git a/Mage.Sets/src/mage/cards/w/WildRide.java b/Mage.Sets/src/mage/cards/w/WildRide.java new file mode 100644 index 00000000000..c049cc6f6a2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WildRide.java @@ -0,0 +1,44 @@ +package mage.cards.w; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HarmonizeAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WildRide extends CardImpl { + + public WildRide(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}"); + + // Target creature gets +3/+0 and gains haste until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 3, 0, Duration.EndOfTurn + ).setText("Target creature gets +3/+0")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains haste until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Harmonize {4}{R} + this.addAbility(new HarmonizeAbility(this, "{4}{R}")); + } + + private WildRide(final WildRide card) { + super(card); + } + + @Override + public WildRide copy() { + return new WildRide(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 2114d2e44ea..0be9593d46d 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -180,6 +180,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Venerated Stormsinger", 97, Rarity.UNCOMMON, mage.cards.v.VeneratedStormsinger.class)); cards.add(new SetCardInfo("Voice of Victory", 33, Rarity.RARE, mage.cards.v.VoiceOfVictory.class)); cards.add(new SetCardInfo("Watcher of the Wayside", 249, Rarity.COMMON, mage.cards.w.WatcherOfTheWayside.class)); + cards.add(new SetCardInfo("Wild Ride", 132, Rarity.COMMON, mage.cards.w.WildRide.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 271, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); cards.add(new SetCardInfo("Wingblade Disciple", 65, Rarity.UNCOMMON, mage.cards.w.WingbladeDisciple.class)); cards.add(new SetCardInfo("Wingspan Stride", 66, Rarity.COMMON, mage.cards.w.WingspanStride.class)); From 6780f1d004ee21de3ad75e8148f1d195bf403406 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 22:15:33 -0400 Subject: [PATCH 30/49] [TDM] Implement Adorned Crocodile --- .../src/mage/cards/a/AdornedCrocodile.java | 43 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 44 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/AdornedCrocodile.java diff --git a/Mage.Sets/src/mage/cards/a/AdornedCrocodile.java b/Mage.Sets/src/mage/cards/a/AdornedCrocodile.java new file mode 100644 index 00000000000..e50e57f63db --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AdornedCrocodile.java @@ -0,0 +1,43 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.RenewAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.game.permanent.token.ZombieDruidToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AdornedCrocodile extends CardImpl { + + public AdornedCrocodile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.CROCODILE); + this.power = new MageInt(5); + this.toughness = new MageInt(3); + + // When this creature dies, create a 2/2 black Zombie Druid creature token. + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new ZombieDruidToken()))); + + // Renew -- {B}, Exile this card from your graveyard: Put a +1/+1 counter on target creature. Activate only as a sorcery. + this.addAbility(new RenewAbility("{B}", CounterType.P1P1.createInstance())); + } + + private AdornedCrocodile(final AdornedCrocodile card) { + super(card); + } + + @Override + public AdornedCrocodile copy() { + return new AdornedCrocodile(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 0be9593d46d..07e059382e5 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -26,6 +26,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Abzan Devotee", 68, Rarity.COMMON, mage.cards.a.AbzanDevotee.class)); cards.add(new SetCardInfo("Abzan Monument", 238, Rarity.UNCOMMON, mage.cards.a.AbzanMonument.class)); + cards.add(new SetCardInfo("Adorned Crocodile", 69, Rarity.COMMON, mage.cards.a.AdornedCrocodile.class)); cards.add(new SetCardInfo("Aegis Sculptor", 35, Rarity.UNCOMMON, mage.cards.a.AegisSculptor.class)); cards.add(new SetCardInfo("Agent of Kotis", 36, Rarity.COMMON, mage.cards.a.AgentOfKotis.class)); cards.add(new SetCardInfo("Alesha's Legacy", 72, Rarity.COMMON, mage.cards.a.AleshasLegacy.class)); From fce9caccb06ef420479a73e30f9eda90eabce065 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 28 Mar 2025 22:19:06 -0400 Subject: [PATCH 31/49] [TDM] Implement Sibsig Appraiser --- .../src/mage/cards/s/SibsigAppraiser.java | 41 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 42 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SibsigAppraiser.java diff --git a/Mage.Sets/src/mage/cards/s/SibsigAppraiser.java b/Mage.Sets/src/mage/cards/s/SibsigAppraiser.java new file mode 100644 index 00000000000..43af926d85b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SibsigAppraiser.java @@ -0,0 +1,41 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PutCards; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SibsigAppraiser extends CardImpl { + + public SibsigAppraiser(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // When this creature enters, look at the top two cards of your library. Put one of them into your hand and the other into your graveyard. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + 2, 1, PutCards.HAND, PutCards.GRAVEYARD + ))); + } + + private SibsigAppraiser(final SibsigAppraiser card) { + super(card); + } + + @Override + public SibsigAppraiser copy() { + return new SibsigAppraiser(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 07e059382e5..d4b565c1c25 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -149,6 +149,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Shiko, Paragon of the Way", 223, Rarity.MYTHIC, mage.cards.s.ShikoParagonOfTheWay.class)); cards.add(new SetCardInfo("Shock Brigade", 120, Rarity.COMMON, mage.cards.s.ShockBrigade.class)); cards.add(new SetCardInfo("Shocking Sharpshooter", 121, Rarity.UNCOMMON, mage.cards.s.ShockingSharpshooter.class)); + cards.add(new SetCardInfo("Sibsig Appraiser", 56, Rarity.COMMON, mage.cards.s.SibsigAppraiser.class)); cards.add(new SetCardInfo("Sinkhole Surveyor", 93, Rarity.RARE, mage.cards.s.SinkholeSurveyor.class)); cards.add(new SetCardInfo("Skirmish Rhino", 224, Rarity.UNCOMMON, mage.cards.s.SkirmishRhino.class)); cards.add(new SetCardInfo("Smile at Death", 24, Rarity.MYTHIC, mage.cards.s.SmileAtDeath.class)); From 176c63c5e974ab73d869eb936fc453b19b5737de Mon Sep 17 00:00:00 2001 From: PurpleCrowbar <26198472+PurpleCrowbar@users.noreply.github.com> Date: Sat, 29 Mar 2025 13:12:40 +0000 Subject: [PATCH 32/49] [TDC] Implement Teval's Judgement --- .../src/mage/cards/t/TevalsJudgement.java | 47 +++++++++++++++++++ .../mage/sets/TarkirDragonstormCommander.java | 2 + 2 files changed, 49 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TevalsJudgement.java diff --git a/Mage.Sets/src/mage/cards/t/TevalsJudgement.java b/Mage.Sets/src/mage/cards/t/TevalsJudgement.java new file mode 100644 index 00000000000..b08fa215541 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TevalsJudgement.java @@ -0,0 +1,47 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.CardsLeaveGraveyardTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.TreasureToken; +import mage.game.permanent.token.ZombieDruidToken; + +import java.util.UUID; + +/** + * @author PurpleCrowbar + */ +public final class TevalsJudgement extends CardImpl { + + public TevalsJudgement(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); + + // Whenever one or more cards leave your graveyard, choose one that hasn’t been chosen this turn -- + // * Draw a card. + Ability ability = new CardsLeaveGraveyardTriggeredAbility( + new DrawCardSourceControllerEffect(1) + ); + ability.getModes().setLimitUsageByOnce(true); + + // * Create a Treasure token. + ability.addMode(new Mode(new CreateTokenEffect(new TreasureToken()))); + + // * Create a 2/2 black Zombie Druid creature token. + ability.addMode(new Mode(new CreateTokenEffect(new ZombieDruidToken()))); + this.addAbility(ability); + } + + private TevalsJudgement(final TevalsJudgement card) { + super(card); + } + + @Override + public TevalsJudgement copy() { + return new TevalsJudgement(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstormCommander.java b/Mage.Sets/src/mage/sets/TarkirDragonstormCommander.java index f87dc17574a..29bebed6fff 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstormCommander.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstormCommander.java @@ -304,6 +304,8 @@ public final class TarkirDragonstormCommander extends ExpansionSet { cards.add(new SetCardInfo("Temur Ascendancy", 305, Rarity.RARE, mage.cards.t.TemurAscendancy.class)); cards.add(new SetCardInfo("Terramorphic Expanse", 408, Rarity.COMMON, mage.cards.t.TerramorphicExpanse.class)); cards.add(new SetCardInfo("Territorial Hellkite", 240, Rarity.RARE, mage.cards.t.TerritorialHellkite.class)); + cards.add(new SetCardInfo("Teval's Judgement", 28, Rarity.RARE, mage.cards.t.TevalsJudgement.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Teval's Judgement", 68, Rarity.RARE, mage.cards.t.TevalsJudgement.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Teval, the Balanced Scale", 8, Rarity.MYTHIC, mage.cards.t.TevalTheBalancedScale.class)); cards.add(new SetCardInfo("Thalisse, Reverent Medium", 306, Rarity.UNCOMMON, mage.cards.t.ThalisseReverentMedium.class)); cards.add(new SetCardInfo("Think Twice", 168, Rarity.COMMON, mage.cards.t.ThinkTwice.class)); From e45f9494a3eec100d1344b082453cbabf356a33e Mon Sep 17 00:00:00 2001 From: PurpleCrowbar <26198472+PurpleCrowbar@users.noreply.github.com> Date: Sat, 29 Mar 2025 14:35:18 +0000 Subject: [PATCH 33/49] Fix Glarb, Calamity's Augur rules text --- Mage.Sets/src/mage/cards/g/GlarbCalamitysAugur.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/g/GlarbCalamitysAugur.java b/Mage.Sets/src/mage/cards/g/GlarbCalamitysAugur.java index 164f123c72c..516bf91b1f5 100644 --- a/Mage.Sets/src/mage/cards/g/GlarbCalamitysAugur.java +++ b/Mage.Sets/src/mage/cards/g/GlarbCalamitysAugur.java @@ -54,7 +54,7 @@ public final class GlarbCalamitysAugur extends CardImpl { this.addAbility(new SimpleStaticAbility(new PlayFromTopOfLibraryEffect(filter))); // {T}: Surveil 2. - this.addAbility(new SimpleActivatedAbility(new SurveilEffect(2), new TapSourceCost())); + this.addAbility(new SimpleActivatedAbility(new SurveilEffect(2, false), new TapSourceCost())); } private GlarbCalamitysAugur(final GlarbCalamitysAugur card) { From d9d7dbd9f18ea467f2317b70ed42459def4bb542 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 10:18:44 -0400 Subject: [PATCH 34/49] [TDM] update spoiler --- Utils/mtg-cards-data.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 9a845ef758c..473865c8d09 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -57237,7 +57237,7 @@ Aegis Sculptor|Tarkir: Dragonstorm|35|U|{3}{U}|Creature - Bird Wizard|2|3|Flying Agent of Kotis|Tarkir: Dragonstorm|36|C|{1}{U}|Creature - Human Rogue|2|1|Renew -- {3}{U}, Exile this card from your graveyard: Put two +1/+1 counters on target creature. Activate only as a sorcery.| Ambling Stormshell|Tarkir: Dragonstorm|37|R|{3}{U}{U}|Creature - Turtle|5|9|Ward {2}$Whenever this creature attacks, put three stun counters on it and draw three cards.$Whenever you cast a Turtle spell, untap this creature.| Bewildering Blizzard|Tarkir: Dragonstorm|38|U|{4}{U}{U}|Instant|||Draw three cards. Creatures your opponents control get -3/-0 until end of turn.| -Constrictor Sage|Tarkir: Dragonstorm|39|U|{4}{U}|Creature - Snake Wizard|4|4|When this creature enters, tap target creature an opponent controls and put a stun counter on it.$Renew -- 2{U}, Exile this card from your graveyard: Tap target creature an opponent controls and put a stun counter on it. Activate only as a sorcery.| +Constrictor Sage|Tarkir: Dragonstorm|39|U|{4}{U}|Creature - Snake Wizard|4|4|When this creature enters, tap target creature an opponent controls and put a stun counter on it.$Renew -- {2}{U}, Exile this card from your graveyard: Tap target creature an opponent controls and put a stun counter on it. Activate only as a sorcery.| Dirgur Island Dragon|Tarkir: Dragonstorm|40|C|{5}{U}|Creature - Dragon|4|4|Flying$Ward {2}| Skimming Strike|Tarkir: Dragonstorm|40|C|{1}{U}|Instant - Omen|4|4|Tap up to one target creature. Draw a card.| Dispelling Exhale|Tarkir: Dragonstorm|41|C|{1}{U}|Instant|||As an additional cost to cast this spell, you may behold a Dragon.$Counter target spell unless its controller pays {2}. If a Dragon was beheld, counter that spell unless its controller pays {4} instead.| @@ -57335,7 +57335,7 @@ Twin Bolt|Tarkir: Dragonstorm|128|C|{1}{R}|Instant|||Twin Bolt deals 2 damage di Underfoot Underdogs|Tarkir: Dragonstorm|129|C|{2}{R}|Creature - Goblin Warrior|1|2|When this creature enters, create a 1/1 red Goblin creature token.${1}, {T}: Target creature you control with power 2 or less can't be blocked this turn.| Unsparing Boltcaster|Tarkir: Dragonstorm|130|U|{2}{R}|Creature - Ogre Wizard|3|3|When this creature enters, it deals 5 damage to target creature an opponent controls that was dealt damage this turn.| War Effort|Tarkir: Dragonstorm|131|U|{3}{R}|Enchantment|||Creatures you control get +1/+0.$Whenever you attack, create a 1/1 red Warrior creature token that's tapped and attacking. Sacrifice it at the beginning of the next end step.| -Wild Ride|Tarkir: Dragonstorm|132|C|{R}|Sorcery|||Target creature gets +3/+0 and gains haste until end of turn.$Harmonize 4{R}| +Wild Ride|Tarkir: Dragonstorm|132|C|{R}|Sorcery|||Target creature gets +3/+0 and gains haste until end of turn.$Harmonize {4}{R}| Zurgo's Vanguard|Tarkir: Dragonstorm|133|U|{2}{R}|Creature - Dog Soldier|*|3|Mobilize 1$This creature's power is equal to the number of creatures you control.| Ainok Wayfarer|Tarkir: Dragonstorm|134|C|{1}{G}|Creature - Dog Scout|1|1|When this creature enters, mill three cards. You may put a land card from among them into your hand. If you don't, put a +1/+1 counter on this creature.| Attuned Hunter|Tarkir: Dragonstorm|135|U|{2}{G}|Creature - Human Ranger|3|3|Trample$Whenever one or more cards leave your graveyard during your turn, put a +1/+1 counter on this creature.| @@ -57347,7 +57347,7 @@ Dragon Sniper|Tarkir: Dragonstorm|139|U|{G}|Creature - Human Archer|1|1|Vigilanc Dragonbroods' Relic|Tarkir: Dragonstorm|140|U|{1}{G}|Artifact|||{T}, Tap an untapped creature you control: Add one mana of any color.${3}{W}{U}{B}{R}{G}, Sacrifice this artifact: Create a 4/4 Dragon creature token named Reliquary Dragon that's all colors. It has flying, lifelink, and "When this token enters, it deals 3 damage to any target." Activate only as a sorcery.| Dusyut Earthcarver|Tarkir: Dragonstorm|141|C|{5}{G}|Creature - Elephant Druid|4|4|Reach$When this creature enters, it endures 3.| Encroaching Dragonstorm|Tarkir: Dragonstorm|142|U|{3}{G}|Enchantment|||When this enchantment enters, search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle.$When a Dragon you control enters, return this enchantment to its owner's hand.| -Formation Breaker|Tarkir: Dragonstorm|143|U|{1}{G}|Creature - Beast|2|1|Creatures with power less than this creature's power can't block it.$As long as you control a creature with a counter on it, this creature gets +1/+2| +Formation Breaker|Tarkir: Dragonstorm|143|U|{1}{G}|Creature - Beast|2|1|Creatures with power less than this creature's power can't block it.$As long as you control a creature with a counter on it, this creature gets +1/+2.| Herd Heirloom|Tarkir: Dragonstorm|144|R|{1}{G}|Artifact|||{T}: Add one mana of any color. Spend this mana only to cast a creature spell.${T}: Until end of turn, target creature you control with power 4 or greater gains trample and "Whenever this creature deals combat damage to a player, draw a card."| Heritage Reclamation|Tarkir: Dragonstorm|145|C|{1}{G}|Instant|||Choose one --$* Destroy target artifact.$* Destroy target enchantment.$* Exile up to one target card from a graveyard. Draw a card.| Inspirited Vanguard|Tarkir: Dragonstorm|146|U|{4}{G}|Creature - Human Soldier|3|2|Whenever this creature enters or attacks, it endures 2.| @@ -57404,7 +57404,7 @@ Inevitable Defeat|Tarkir: Dragonstorm|194|R|{1}{R}{W}{B}|Instant|||This spell ca Jeskai Brushmaster|Tarkir: Dragonstorm|195|U|{1}{U}{R}{W}|Creature - Orc Monk|2|4|Double strike$Prowess| Jeskai Revelation|Tarkir: Dragonstorm|196|M|{4}{U}{R}{W}|Instant|||Return target spell or permanent to its owner's hand. Jeskai Revelation deals 4 damage to any target. Create two 1/1 white Monk creature tokens with prowess. Draw two cards. You gain 4 life.| Jeskai Shrinekeeper|Tarkir: Dragonstorm|197|U|{2}{U}{R}{W}|Creature - Dragon|3|3|Flying, haste$Whenever this creature deals combat damage to a player, you gain 1 life and draw a card.| -Karakyk Guardian|Tarkir: Dragonstorm|198|U|{3}{G}{U}{R}|Creature -- Dragon|6|5|Flying, vigilance, trample$This creature has hexproof if it hasn't dealt damage yet.| +Karakyk Guardian|Tarkir: Dragonstorm|198|U|{3}{G}{U}{R}|Creature - Dragon|6|5|Flying, vigilance, trample$This creature has hexproof if it hasn't dealt damage yet.| Kheru Goldkeeper|Tarkir: Dragonstorm|199|U|{1}{B}{G}{U}|Creature - Dragon|3|3|Flying$Whenever one or more cards leave your graveyard during your turn, create a Treasure token.$Renew -- {2}{B}{G}{U}, Exile this card from your graveyard: Put two +1/+1 counters and a flying counter on target creature. Activate only as a sorcery.| Kin-Tree Severance|Tarkir: Dragonstorm|200|U|{2/W}{2/B}{2/G}|Instant|||Exile target permanent with mana value 3 or greater.| Kishla Skimmer|Tarkir: Dragonstorm|201|U|{G}{U}|Creature - Bird Scout|2|2|Flying$Whenever a card leaves your graveyard during your turn, draw a card. This ability triggers only once each turn.| From eafa45a54910f5938bd8fd03eaf008e34dbc9461 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 10:21:24 -0400 Subject: [PATCH 35/49] [TDC] fix Teval's Judgment name --- .../t/{TevalsJudgement.java => TevalsJudgment.java} | 10 +++++----- .../src/mage/sets/TarkirDragonstormCommander.java | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) rename Mage.Sets/src/mage/cards/t/{TevalsJudgement.java => TevalsJudgment.java} (83%) diff --git a/Mage.Sets/src/mage/cards/t/TevalsJudgement.java b/Mage.Sets/src/mage/cards/t/TevalsJudgment.java similarity index 83% rename from Mage.Sets/src/mage/cards/t/TevalsJudgement.java rename to Mage.Sets/src/mage/cards/t/TevalsJudgment.java index b08fa215541..3f50b543be4 100644 --- a/Mage.Sets/src/mage/cards/t/TevalsJudgement.java +++ b/Mage.Sets/src/mage/cards/t/TevalsJudgment.java @@ -16,9 +16,9 @@ import java.util.UUID; /** * @author PurpleCrowbar */ -public final class TevalsJudgement extends CardImpl { +public final class TevalsJudgment extends CardImpl { - public TevalsJudgement(UUID ownerId, CardSetInfo setInfo) { + public TevalsJudgment(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); // Whenever one or more cards leave your graveyard, choose one that hasn’t been chosen this turn -- @@ -36,12 +36,12 @@ public final class TevalsJudgement extends CardImpl { this.addAbility(ability); } - private TevalsJudgement(final TevalsJudgement card) { + private TevalsJudgment(final TevalsJudgment card) { super(card); } @Override - public TevalsJudgement copy() { - return new TevalsJudgement(this); + public TevalsJudgment copy() { + return new TevalsJudgment(this); } } diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstormCommander.java b/Mage.Sets/src/mage/sets/TarkirDragonstormCommander.java index 29bebed6fff..15997a8fce0 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstormCommander.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstormCommander.java @@ -304,8 +304,8 @@ public final class TarkirDragonstormCommander extends ExpansionSet { cards.add(new SetCardInfo("Temur Ascendancy", 305, Rarity.RARE, mage.cards.t.TemurAscendancy.class)); cards.add(new SetCardInfo("Terramorphic Expanse", 408, Rarity.COMMON, mage.cards.t.TerramorphicExpanse.class)); cards.add(new SetCardInfo("Territorial Hellkite", 240, Rarity.RARE, mage.cards.t.TerritorialHellkite.class)); - cards.add(new SetCardInfo("Teval's Judgement", 28, Rarity.RARE, mage.cards.t.TevalsJudgement.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Teval's Judgement", 68, Rarity.RARE, mage.cards.t.TevalsJudgement.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Teval's Judgment", 28, Rarity.RARE, mage.cards.t.TevalsJudgment.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Teval's Judgment", 68, Rarity.RARE, mage.cards.t.TevalsJudgment.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Teval, the Balanced Scale", 8, Rarity.MYTHIC, mage.cards.t.TevalTheBalancedScale.class)); cards.add(new SetCardInfo("Thalisse, Reverent Medium", 306, Rarity.UNCOMMON, mage.cards.t.ThalisseReverentMedium.class)); cards.add(new SetCardInfo("Think Twice", 168, Rarity.COMMON, mage.cards.t.ThinkTwice.class)); From 164ad388d4d37dcaa630f51aef6f41663e3c0282 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 10:23:45 -0400 Subject: [PATCH 36/49] [TDM] Implement Alchemist's Assistant --- .../src/mage/cards/a/AlchemistsAssistant.java | 41 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 42 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/AlchemistsAssistant.java diff --git a/Mage.Sets/src/mage/cards/a/AlchemistsAssistant.java b/Mage.Sets/src/mage/cards/a/AlchemistsAssistant.java new file mode 100644 index 00000000000..9681199b1be --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AlchemistsAssistant.java @@ -0,0 +1,41 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.RenewAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AlchemistsAssistant extends CardImpl { + + public AlchemistsAssistant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.MONKEY); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Renew -- {1}{B}, Exile this card from your graveyard: Put a lifelink counter on target creature. Activate only as a sorcery. + this.addAbility(new RenewAbility("{1}{B}", CounterType.LIFELINK.createInstance())); + } + + private AlchemistsAssistant(final AlchemistsAssistant card) { + super(card); + } + + @Override + public AlchemistsAssistant copy() { + return new AlchemistsAssistant(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index d4b565c1c25..83c9736810b 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -29,6 +29,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Adorned Crocodile", 69, Rarity.COMMON, mage.cards.a.AdornedCrocodile.class)); cards.add(new SetCardInfo("Aegis Sculptor", 35, Rarity.UNCOMMON, mage.cards.a.AegisSculptor.class)); cards.add(new SetCardInfo("Agent of Kotis", 36, Rarity.COMMON, mage.cards.a.AgentOfKotis.class)); + cards.add(new SetCardInfo("Alchemist's Assistant", 71, Rarity.UNCOMMON, mage.cards.a.AlchemistsAssistant.class)); cards.add(new SetCardInfo("Alesha's Legacy", 72, Rarity.COMMON, mage.cards.a.AleshasLegacy.class)); cards.add(new SetCardInfo("Ambling Stormshell", 37, Rarity.RARE, mage.cards.a.AmblingStormshell.class)); cards.add(new SetCardInfo("Anafenza, Unyielding Lineage", 2, Rarity.RARE, mage.cards.a.AnafenzaUnyieldingLineage.class)); From 68d4fb5e95e1a05a54577fe768ea2e7c812624a8 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 10:26:08 -0400 Subject: [PATCH 37/49] [TDM] Implement Arashin Sunshield --- .../src/mage/cards/a/ArashinSunshield.java | 54 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 55 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/ArashinSunshield.java diff --git a/Mage.Sets/src/mage/cards/a/ArashinSunshield.java b/Mage.Sets/src/mage/cards/a/ArashinSunshield.java new file mode 100644 index 00000000000..3ea6618a2aa --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArashinSunshield.java @@ -0,0 +1,54 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInASingleGraveyard; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArashinSunshield extends CardImpl { + + public ArashinSunshield(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When this creature enters, exile up to two target cards from a single graveyard. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect()); + ability.addTarget(new TargetCardInASingleGraveyard(0, 2, StaticFilters.FILTER_CARDS_NON_LAND)); + this.addAbility(ability); + + // {W}, {T}: Tap target creature. + ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl<>("{W}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private ArashinSunshield(final ArashinSunshield card) { + super(card); + } + + @Override + public ArashinSunshield copy() { + return new ArashinSunshield(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 83c9736810b..011de5447d8 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -33,6 +33,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Alesha's Legacy", 72, Rarity.COMMON, mage.cards.a.AleshasLegacy.class)); cards.add(new SetCardInfo("Ambling Stormshell", 37, Rarity.RARE, mage.cards.a.AmblingStormshell.class)); cards.add(new SetCardInfo("Anafenza, Unyielding Lineage", 2, Rarity.RARE, mage.cards.a.AnafenzaUnyieldingLineage.class)); + cards.add(new SetCardInfo("Arashin Sunshield", 3, Rarity.COMMON, mage.cards.a.ArashinSunshield.class)); cards.add(new SetCardInfo("Armament Dragon", 168, Rarity.UNCOMMON, mage.cards.a.ArmamentDragon.class)); cards.add(new SetCardInfo("Attuned Hunter", 135, Rarity.UNCOMMON, mage.cards.a.AttunedHunter.class)); cards.add(new SetCardInfo("Auroral Procession", 169, Rarity.UNCOMMON, mage.cards.a.AuroralProcession.class)); From d7f9e5951c6b6ee665c869b918084d15a736af8e Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 10:27:42 -0400 Subject: [PATCH 38/49] [TDM] Implement Humbling Elder --- Mage.Sets/src/mage/cards/h/HumblingElder.java | 46 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 47 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/h/HumblingElder.java diff --git a/Mage.Sets/src/mage/cards/h/HumblingElder.java b/Mage.Sets/src/mage/cards/h/HumblingElder.java new file mode 100644 index 00000000000..a79977a93c4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HumblingElder.java @@ -0,0 +1,46 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HumblingElder extends CardImpl { + + public HumblingElder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MONK); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // When this creature enters, target creature an opponent controls gets -2/-0 until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-2, 0)); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private HumblingElder(final HumblingElder card) { + super(card); + } + + @Override + public HumblingElder copy() { + return new HumblingElder(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 011de5447d8..786056a3ad4 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -91,6 +91,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Gurmag Nightwatch", 190, Rarity.COMMON, mage.cards.g.GurmagNightwatch.class)); cards.add(new SetCardInfo("Hardened Tactician", 191, Rarity.UNCOMMON, mage.cards.h.HardenedTactician.class)); cards.add(new SetCardInfo("Heritage Reclamation", 145, Rarity.COMMON, mage.cards.h.HeritageReclamation.class)); + cards.add(new SetCardInfo("Humbling Elder", 48, Rarity.COMMON, mage.cards.h.HumblingElder.class)); cards.add(new SetCardInfo("Inevitable Defeat", 194, Rarity.RARE, mage.cards.i.InevitableDefeat.class)); cards.add(new SetCardInfo("Inspirited Vanguard", 146, Rarity.UNCOMMON, mage.cards.i.InspiritedVanguard.class)); cards.add(new SetCardInfo("Iridescent Tiger", 109, Rarity.UNCOMMON, mage.cards.i.IridescentTiger.class)); From f02542efb004870198dffcd03e1026fa0d184813 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 10:28:51 -0400 Subject: [PATCH 39/49] [TDM] Implement Iceridge Serpent --- .../src/mage/cards/i/IceridgeSerpent.java | 41 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 42 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/i/IceridgeSerpent.java diff --git a/Mage.Sets/src/mage/cards/i/IceridgeSerpent.java b/Mage.Sets/src/mage/cards/i/IceridgeSerpent.java new file mode 100644 index 00000000000..db31c1be839 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IceridgeSerpent.java @@ -0,0 +1,41 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IceridgeSerpent extends CardImpl { + + public IceridgeSerpent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.SERPENT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When this creature enters, return target creature an opponent controls to its owner's hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect()); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private IceridgeSerpent(final IceridgeSerpent card) { + super(card); + } + + @Override + public IceridgeSerpent copy() { + return new IceridgeSerpent(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 786056a3ad4..31a424c90ed 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -92,6 +92,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Hardened Tactician", 191, Rarity.UNCOMMON, mage.cards.h.HardenedTactician.class)); cards.add(new SetCardInfo("Heritage Reclamation", 145, Rarity.COMMON, mage.cards.h.HeritageReclamation.class)); cards.add(new SetCardInfo("Humbling Elder", 48, Rarity.COMMON, mage.cards.h.HumblingElder.class)); + cards.add(new SetCardInfo("Iceridge Serpent", 49, Rarity.COMMON, mage.cards.i.IceridgeSerpent.class)); cards.add(new SetCardInfo("Inevitable Defeat", 194, Rarity.RARE, mage.cards.i.InevitableDefeat.class)); cards.add(new SetCardInfo("Inspirited Vanguard", 146, Rarity.UNCOMMON, mage.cards.i.InspiritedVanguard.class)); cards.add(new SetCardInfo("Iridescent Tiger", 109, Rarity.UNCOMMON, mage.cards.i.IridescentTiger.class)); From 5798c361fa46784cc14671cae736ce2e0ac0ea3f Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 10:32:20 -0400 Subject: [PATCH 40/49] [TDM] Implement Rescue Leopard --- Mage.Sets/src/mage/cards/r/RescueLeopard.java | 41 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 42 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/RescueLeopard.java diff --git a/Mage.Sets/src/mage/cards/r/RescueLeopard.java b/Mage.Sets/src/mage/cards/r/RescueLeopard.java new file mode 100644 index 00000000000..e74c4610a5c --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RescueLeopard.java @@ -0,0 +1,41 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.BecomesTappedSourceTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RescueLeopard extends CardImpl { + + public RescueLeopard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Whenever this creature becomes tapped, you may discard a card. If you do, draw a card. + this.addAbility(new BecomesTappedSourceTriggeredAbility( + new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()) + )); + } + + private RescueLeopard(final RescueLeopard card) { + super(card); + } + + @Override + public RescueLeopard copy() { + return new RescueLeopard(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 31a424c90ed..1f8d4621959 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -138,6 +138,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Rebellious Strike", 20, Rarity.COMMON, mage.cards.r.RebelliousStrike.class)); cards.add(new SetCardInfo("Reigning Victor", 216, Rarity.COMMON, mage.cards.r.ReigningVictor.class)); cards.add(new SetCardInfo("Reputable Merchant", 217, Rarity.COMMON, mage.cards.r.ReputableMerchant.class)); + cards.add(new SetCardInfo("Rescue Leopard", 116, Rarity.COMMON, mage.cards.r.RescueLeopard.class)); cards.add(new SetCardInfo("Ringing Strike Mastery", 53, Rarity.COMMON, mage.cards.r.RingingStrikeMastery.class)); cards.add(new SetCardInfo("Roamer's Routine", 154, Rarity.COMMON, mage.cards.r.RoamersRoutine.class)); cards.add(new SetCardInfo("Roar of Endless Song", 220, Rarity.RARE, mage.cards.r.RoarOfEndlessSong.class)); From 4bc0a755139e203943802270396cfe811cd9e06f Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 10:36:58 -0400 Subject: [PATCH 41/49] [TDM] Implement Unburied Earthcarver --- .../src/mage/cards/u/UnburiedEarthcarver.java | 47 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 48 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/u/UnburiedEarthcarver.java diff --git a/Mage.Sets/src/mage/cards/u/UnburiedEarthcarver.java b/Mage.Sets/src/mage/cards/u/UnburiedEarthcarver.java new file mode 100644 index 00000000000..96d624833d2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnburiedEarthcarver.java @@ -0,0 +1,47 @@ +package mage.cards.u; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnburiedEarthcarver extends CardImpl { + + public UnburiedEarthcarver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {2}, Sacrifice another creature: Put a +1/+1 counter on this creature. + Ability ability = new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new GenericManaCost(2) + ); + ability.addCost(new SacrificeTargetCost(StaticFilters.FILTER_ANOTHER_CREATURE)); + this.addAbility(ability); + } + + private UnburiedEarthcarver(final UnburiedEarthcarver card) { + super(card); + } + + @Override + public UnburiedEarthcarver copy() { + return new UnburiedEarthcarver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 1f8d4621959..00ac70147a2 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -177,6 +177,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Tranquil Cove", 270, Rarity.COMMON, mage.cards.t.TranquilCove.class)); cards.add(new SetCardInfo("Twin Bolt", 128, Rarity.COMMON, mage.cards.t.TwinBolt.class)); cards.add(new SetCardInfo("Ugin, Eye of the Storms", 1, Rarity.MYTHIC, mage.cards.u.UginEyeOfTheStorms.class)); + cards.add(new SetCardInfo("Unburied Earthcarver", 95, Rarity.COMMON, mage.cards.u.UnburiedEarthcarver.class)); cards.add(new SetCardInfo("Underfoot Underdogs", 129, Rarity.COMMON, mage.cards.u.UnderfootUnderdogs.class)); cards.add(new SetCardInfo("Undergrowth Leopard", 165, Rarity.COMMON, mage.cards.u.UndergrowthLeopard.class)); cards.add(new SetCardInfo("Unending Whisper", 62, Rarity.COMMON, mage.cards.u.UnendingWhisper.class)); From 229956f1bcfa1a8d2866bc83c03ab709f87c381c Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 18:22:22 -0400 Subject: [PATCH 42/49] [TDM] Implement Ainok Wayfarer --- Mage.Sets/src/mage/cards/a/AinokWayfarer.java | 44 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 45 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/AinokWayfarer.java diff --git a/Mage.Sets/src/mage/cards/a/AinokWayfarer.java b/Mage.Sets/src/mage/cards/a/AinokWayfarer.java new file mode 100644 index 00000000000..77f093dc213 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AinokWayfarer.java @@ -0,0 +1,44 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.MillThenPutInHandEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AinokWayfarer extends CardImpl { + + public AinokWayfarer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.DOG); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When this creature enters, mill three cards. You may put a land card from among them into your hand. If you don't, put a +1/+1 counter on this creature. + this.addAbility(new EntersBattlefieldTriggeredAbility(new MillThenPutInHandEffect( + 1, StaticFilters.FILTER_CARD_LAND_A, + new AddCountersSourceEffect(CounterType.P1P1.createInstance(), true) + ))); + } + + private AinokWayfarer(final AinokWayfarer card) { + super(card); + } + + @Override + public AinokWayfarer copy() { + return new AinokWayfarer(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 00ac70147a2..0681ecaef8d 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -29,6 +29,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Adorned Crocodile", 69, Rarity.COMMON, mage.cards.a.AdornedCrocodile.class)); cards.add(new SetCardInfo("Aegis Sculptor", 35, Rarity.UNCOMMON, mage.cards.a.AegisSculptor.class)); cards.add(new SetCardInfo("Agent of Kotis", 36, Rarity.COMMON, mage.cards.a.AgentOfKotis.class)); + cards.add(new SetCardInfo("Ainok Wayfarer", 134, Rarity.COMMON, mage.cards.a.AinokWayfarer.class)); cards.add(new SetCardInfo("Alchemist's Assistant", 71, Rarity.UNCOMMON, mage.cards.a.AlchemistsAssistant.class)); cards.add(new SetCardInfo("Alesha's Legacy", 72, Rarity.COMMON, mage.cards.a.AleshasLegacy.class)); cards.add(new SetCardInfo("Ambling Stormshell", 37, Rarity.RARE, mage.cards.a.AmblingStormshell.class)); From 46d582e0e63f5d6401c5a462f8d4e073085738c7 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 18:27:06 -0400 Subject: [PATCH 43/49] [TDM] Implement Constrictor Sage --- .../src/mage/cards/c/ConstrictorSage.java | 59 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 60 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/ConstrictorSage.java diff --git a/Mage.Sets/src/mage/cards/c/ConstrictorSage.java b/Mage.Sets/src/mage/cards/c/ConstrictorSage.java new file mode 100644 index 00000000000..57429482fc1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ConstrictorSage.java @@ -0,0 +1,59 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.ExileSourceFromGraveCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ConstrictorSage extends CardImpl { + + public ConstrictorSage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.SNAKE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When this creature enters, tap target creature an opponent controls and put a stun counter on it. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); + ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()) + .setText("and put a stun counter on it")); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + + // Renew -- {2}{U}, Exile this card from your graveyard: Tap target creature an opponent controls and put a stun counter on it. Activate only as a sorcery. + ability = new ActivateAsSorceryActivatedAbility(Zone.GRAVEYARD, new TapTargetEffect(), new ManaCostsImpl<>("{2}{U}")); + ability.addCost(new ExileSourceFromGraveCost()); + ability.addEffect(new AddCountersTargetEffect(CounterType.STUN.createInstance()) + .setText("and put a stun counter on it")); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability.setAbilityWord(AbilityWord.RENEW)); + } + + private ConstrictorSage(final ConstrictorSage card) { + super(card); + } + + @Override + public ConstrictorSage copy() { + return new ConstrictorSage(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 0681ecaef8d..9f782e26d6d 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -52,6 +52,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Caustic Exhale", 74, Rarity.COMMON, mage.cards.c.CausticExhale.class)); cards.add(new SetCardInfo("Champion of Dusan", 137, Rarity.COMMON, mage.cards.c.ChampionOfDusan.class)); cards.add(new SetCardInfo("Channeled Dragonfire", 102, Rarity.UNCOMMON, mage.cards.c.ChanneledDragonfire.class)); + cards.add(new SetCardInfo("Constrictor Sage", 39, Rarity.UNCOMMON, mage.cards.c.ConstrictorSage.class)); cards.add(new SetCardInfo("Coordinated Maneuver", 6, Rarity.COMMON, mage.cards.c.CoordinatedManeuver.class)); cards.add(new SetCardInfo("Cori Mountain Monastery", 252, Rarity.RARE, mage.cards.c.CoriMountainMonastery.class)); cards.add(new SetCardInfo("Cori Mountain Stalwart", 175, Rarity.UNCOMMON, mage.cards.c.CoriMountainStalwart.class)); From 21c5dabb489fab40ede79c5e0424cd9f49bf844f Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 18:39:52 -0400 Subject: [PATCH 44/49] [TDM] Implement Revival of the Ancestors --- .../mage/cards/r/RevivalOfTheAncestors.java | 70 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 71 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/RevivalOfTheAncestors.java diff --git a/Mage.Sets/src/mage/cards/r/RevivalOfTheAncestors.java b/Mage.Sets/src/mage/cards/r/RevivalOfTheAncestors.java new file mode 100644 index 00000000000..9f73504a426 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RevivalOfTheAncestors.java @@ -0,0 +1,70 @@ +package mage.cards.r; + +import mage.abilities.common.SagaAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.DistributeCountersEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SagaChapter; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.NoFlyingSpiritWhiteToken; +import mage.target.common.TargetCreaturePermanentAmount; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RevivalOfTheAncestors extends CardImpl { + + public RevivalOfTheAncestors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{B}{G}"); + + this.subtype.add(SubType.SAGA); + + // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) + SagaAbility sagaAbility = new SagaAbility(this); + + // I -- Create three 1/1 white Spirit creature tokens. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_I, + new CreateTokenEffect(new NoFlyingSpiritWhiteToken(), 3) + ); + + // II -- Distribute three +1/+1 counters among one, two, or three target creatures you control. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_II, + new DistributeCountersEffect(CounterType.P1P1), + new TargetCreaturePermanentAmount(3) + ); + + // III -- Creatures you control gain trample and lifelink until end of turn. + sagaAbility.addChapterEffect( + this, SagaChapter.CHAPTER_III, + new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("creatures you control gain trample"), + new GainAbilityControlledEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("and lifelink until end of turn")); + this.addAbility(sagaAbility); + } + + private RevivalOfTheAncestors(final RevivalOfTheAncestors card) { + super(card); + } + + @Override + public RevivalOfTheAncestors copy() { + return new RevivalOfTheAncestors(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 9f782e26d6d..1370212d0e8 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -141,6 +141,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Reigning Victor", 216, Rarity.COMMON, mage.cards.r.ReigningVictor.class)); cards.add(new SetCardInfo("Reputable Merchant", 217, Rarity.COMMON, mage.cards.r.ReputableMerchant.class)); cards.add(new SetCardInfo("Rescue Leopard", 116, Rarity.COMMON, mage.cards.r.RescueLeopard.class)); + cards.add(new SetCardInfo("Revival of the Ancestors", 218, Rarity.RARE, mage.cards.r.RevivalOfTheAncestors.class)); cards.add(new SetCardInfo("Ringing Strike Mastery", 53, Rarity.COMMON, mage.cards.r.RingingStrikeMastery.class)); cards.add(new SetCardInfo("Roamer's Routine", 154, Rarity.COMMON, mage.cards.r.RoamersRoutine.class)); cards.add(new SetCardInfo("Roar of Endless Song", 220, Rarity.RARE, mage.cards.r.RoarOfEndlessSong.class)); From a641f5d05b26909def5edd7865e4b165f328435d Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 18:46:51 -0400 Subject: [PATCH 45/49] [TDM] Implement Sage of the Fang --- Mage.Sets/src/mage/cards/s/SageOfTheFang.java | 51 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 52 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SageOfTheFang.java diff --git a/Mage.Sets/src/mage/cards/s/SageOfTheFang.java b/Mage.Sets/src/mage/cards/s/SageOfTheFang.java new file mode 100644 index 00000000000..12a152c90d9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SageOfTheFang.java @@ -0,0 +1,51 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.RenewAbility; +import mage.abilities.effects.common.DoubleCountersTargetEffect; +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.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SageOfTheFang extends CardImpl { + + public SageOfTheFang(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When this creature enters, put a +1/+1 counter on target creature. + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // Renew -- {3}{G}, Exile this card from your graveyard: Put a +1/+1 counter on target creature, then double the number of +1/+1 counters on that creature. + ability = new RenewAbility("{3}{G}", CounterType.P1P1.createInstance()); + ability.addEffect(new DoubleCountersTargetEffect(CounterType.P1P1) + .setText(", then double the number of +1/+1 counters on that creature")); + this.addAbility(ability); + } + + private SageOfTheFang(final SageOfTheFang card) { + super(card); + } + + @Override + public SageOfTheFang copy() { + return new SageOfTheFang(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 1370212d0e8..64a3197a6b0 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -147,6 +147,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Roar of Endless Song", 220, Rarity.RARE, mage.cards.r.RoarOfEndlessSong.class)); cards.add(new SetCardInfo("Roiling Dragonstorm", 55, Rarity.UNCOMMON, mage.cards.r.RoilingDragonstorm.class)); cards.add(new SetCardInfo("Rugged Highlands", 265, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); + cards.add(new SetCardInfo("Sage of the Fang", 155, Rarity.UNCOMMON, mage.cards.s.SageOfTheFang.class)); cards.add(new SetCardInfo("Sagu Pummeler", 156, Rarity.COMMON, mage.cards.s.SaguPummeler.class)); cards.add(new SetCardInfo("Salt Road Packbeast", 23, Rarity.COMMON, mage.cards.s.SaltRoadPackbeast.class)); cards.add(new SetCardInfo("Sandskitter Outrider", 89, Rarity.COMMON, mage.cards.s.SandskitterOutrider.class)); From f07c8239afaba464e735068c17c843ea051dffb1 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 18:49:26 -0400 Subject: [PATCH 46/49] [TDM] Implement Riverwalk Technique --- .../src/mage/cards/r/RiverwalkTechnique.java | 41 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 42 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/RiverwalkTechnique.java diff --git a/Mage.Sets/src/mage/cards/r/RiverwalkTechnique.java b/Mage.Sets/src/mage/cards/r/RiverwalkTechnique.java new file mode 100644 index 00000000000..a8547b88b2d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiverwalkTechnique.java @@ -0,0 +1,41 @@ +package mage.cards.r; + +import mage.abilities.Mode; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetSpell; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RiverwalkTechnique extends CardImpl { + + public RiverwalkTechnique(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); + + // Choose one -- + // * The owner of target nonland permanent puts it on their choice of the top or bottom of their library. + this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect(true)); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + + // * Counter target noncreature spell. + this.getSpellAbility().addMode(new Mode(new CounterTargetEffect()) + .addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_NON_CREATURE))); + } + + private RiverwalkTechnique(final RiverwalkTechnique card) { + super(card); + } + + @Override + public RiverwalkTechnique copy() { + return new RiverwalkTechnique(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 64a3197a6b0..4b59d4b311b 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -143,6 +143,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Rescue Leopard", 116, Rarity.COMMON, mage.cards.r.RescueLeopard.class)); cards.add(new SetCardInfo("Revival of the Ancestors", 218, Rarity.RARE, mage.cards.r.RevivalOfTheAncestors.class)); cards.add(new SetCardInfo("Ringing Strike Mastery", 53, Rarity.COMMON, mage.cards.r.RingingStrikeMastery.class)); + cards.add(new SetCardInfo("Riverwalk Technique", 54, Rarity.COMMON, mage.cards.r.RiverwalkTechnique.class)); cards.add(new SetCardInfo("Roamer's Routine", 154, Rarity.COMMON, mage.cards.r.RoamersRoutine.class)); cards.add(new SetCardInfo("Roar of Endless Song", 220, Rarity.RARE, mage.cards.r.RoarOfEndlessSong.class)); cards.add(new SetCardInfo("Roiling Dragonstorm", 55, Rarity.UNCOMMON, mage.cards.r.RoilingDragonstorm.class)); From a293b77f142709dc6ca1bf402af8b9f2a9018804 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 18:58:31 -0400 Subject: [PATCH 47/49] [TDM] Implement Wayspeaker Bodyguard --- .../src/mage/cards/w/WayspeakerBodyguard.java | 62 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 63 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WayspeakerBodyguard.java diff --git a/Mage.Sets/src/mage/cards/w/WayspeakerBodyguard.java b/Mage.Sets/src/mage/cards/w/WayspeakerBodyguard.java new file mode 100644 index 00000000000..b7f5291cddf --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WayspeakerBodyguard.java @@ -0,0 +1,62 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.FlurryAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.common.FilterNonlandCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.filter.predicate.mageobject.PermanentPredicate; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WayspeakerBodyguard extends CardImpl { + + private static final FilterCard filter = new FilterNonlandCard("nonland permanent card with mana value 2 or less"); + + static { + filter.add(PermanentPredicate.instance); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3)); + } + + public WayspeakerBodyguard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.ORC); + this.subtype.add(SubType.MONK); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When this creature enters, return target nonland permanent card with mana value 2 or less from your graveyard to your hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + + // Flurry -- Whenever you cast your second spell each turn, tap target creature an opponent controls. + ability = new FlurryAbility(new TapTargetEffect()); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private WayspeakerBodyguard(final WayspeakerBodyguard card) { + super(card); + } + + @Override + public WayspeakerBodyguard copy() { + return new WayspeakerBodyguard(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 4b59d4b311b..6e8fdd58aa4 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -193,6 +193,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Venerated Stormsinger", 97, Rarity.UNCOMMON, mage.cards.v.VeneratedStormsinger.class)); cards.add(new SetCardInfo("Voice of Victory", 33, Rarity.RARE, mage.cards.v.VoiceOfVictory.class)); cards.add(new SetCardInfo("Watcher of the Wayside", 249, Rarity.COMMON, mage.cards.w.WatcherOfTheWayside.class)); + cards.add(new SetCardInfo("Wayspeaker Bodyguard", 34, Rarity.UNCOMMON, mage.cards.w.WayspeakerBodyguard.class)); cards.add(new SetCardInfo("Wild Ride", 132, Rarity.COMMON, mage.cards.w.WildRide.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 271, Rarity.COMMON, mage.cards.w.WindScarredCrag.class)); cards.add(new SetCardInfo("Wingblade Disciple", 65, Rarity.UNCOMMON, mage.cards.w.WingbladeDisciple.class)); From a850ce7339ba802f0d3e366afb16d2792ea3282e Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 29 Mar 2025 19:04:36 -0400 Subject: [PATCH 48/49] [TDM] Implement Snowmelt Stag --- Mage.Sets/src/mage/cards/s/SnowmeltStag.java | 56 +++++++++++++++++++ .../src/mage/sets/TarkirDragonstorm.java | 1 + 2 files changed, 57 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SnowmeltStag.java diff --git a/Mage.Sets/src/mage/cards/s/SnowmeltStag.java b/Mage.Sets/src/mage/cards/s/SnowmeltStag.java new file mode 100644 index 00000000000..a72e8ad66f0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SnowmeltStag.java @@ -0,0 +1,56 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SnowmeltStag extends CardImpl { + + public SnowmeltStag(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.ELEMENTAL); + this.subtype.add(SubType.ELK); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // During your turn, this creature has base power and toughness 5/2. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new SetBasePowerToughnessSourceEffect(5, 2, Duration.WhileOnBattlefield), + MyTurnCondition.instance, "during your turn, this creature has base power and toughness 5/2" + ))); + + // {5}{U}{U}: This creature can't be blocked this turn. + this.addAbility(new SimpleActivatedAbility( + new CantBeBlockedSourceEffect(Duration.EndOfTurn), new ManaCostsImpl<>("{5}{U}{U}") + )); + } + + private SnowmeltStag(final SnowmeltStag card) { + super(card); + } + + @Override + public SnowmeltStag copy() { + return new SnowmeltStag(this); + } +} diff --git a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java index 6e8fdd58aa4..71bf4073c12 100644 --- a/Mage.Sets/src/mage/sets/TarkirDragonstorm.java +++ b/Mage.Sets/src/mage/sets/TarkirDragonstorm.java @@ -164,6 +164,7 @@ public final class TarkirDragonstorm extends ExpansionSet { cards.add(new SetCardInfo("Skirmish Rhino", 224, Rarity.UNCOMMON, mage.cards.s.SkirmishRhino.class)); cards.add(new SetCardInfo("Smile at Death", 24, Rarity.MYTHIC, mage.cards.s.SmileAtDeath.class)); cards.add(new SetCardInfo("Snakeskin Veil", 159, Rarity.COMMON, mage.cards.s.SnakeskinVeil.class)); + cards.add(new SetCardInfo("Snowmelt Stag", 57, Rarity.COMMON, mage.cards.s.SnowmeltStag.class)); cards.add(new SetCardInfo("Spectral Denial", 58, Rarity.UNCOMMON, mage.cards.s.SpectralDenial.class)); cards.add(new SetCardInfo("Stormplain Detainment", 28, Rarity.COMMON, mage.cards.s.StormplainDetainment.class)); cards.add(new SetCardInfo("Stormscale Scion", 123, Rarity.MYTHIC, mage.cards.s.StormscaleScion.class)); From 5ac01f259d27e82096373a5064d59732aa6d3f62 Mon Sep 17 00:00:00 2001 From: xenohedron <12538125+xenohedron@users.noreply.github.com> Date: Sun, 30 Mar 2025 00:52:30 -0400 Subject: [PATCH 49/49] fix Veiled Apparition (was missing flying) --- .../src/mage/cards/v/VeiledApparition.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/Mage.Sets/src/mage/cards/v/VeiledApparition.java b/Mage.Sets/src/mage/cards/v/VeiledApparition.java index 6d23247eca8..ddb202c6119 100644 --- a/Mage.Sets/src/mage/cards/v/VeiledApparition.java +++ b/Mage.Sets/src/mage/cards/v/VeiledApparition.java @@ -1,17 +1,15 @@ package mage.cards.v; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.TriggeredAbility; -import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; import mage.abilities.condition.common.SourceMatchesFilterCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.common.DoUnlessControllerPaysEffect; -import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -21,6 +19,8 @@ import mage.filter.FilterSpell; import mage.filter.StaticFilters; import mage.game.permanent.token.TokenImpl; +import java.util.UUID; + /** * * @author jeffwadsworth @@ -33,7 +33,7 @@ public final class VeiledApparition extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); // When an opponent casts a spell, if Veiled Apparition is an enchantment, Veiled Apparition becomes a 3/3 Illusion creature with flying and "At the beginning of your upkeep, sacrifice Veiled Apparition unless you pay {1}{U}." - TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new VeilApparitionToken(), null, Duration.WhileOnBattlefield), + TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new VeiledApparitionToken(), null, Duration.WhileOnBattlefield), filter, false); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_ENCHANTMENT), "When an opponent casts a spell, if {this} is an enchantment, {this} becomes a 3/3 Illusion creature with flying and \"At the beginning of your upkeep, sacrifice Veiled Apparition unless you pay {1}{U}.\"")); @@ -50,23 +50,25 @@ public final class VeiledApparition extends CardImpl { } } -class VeilApparitionToken extends TokenImpl { +class VeiledApparitionToken extends TokenImpl { - public VeilApparitionToken() { + VeiledApparitionToken() { super("Illusion", "3/3 Illusion creature with flying and \"At the beginning of your upkeep, sacrifice Veiled Apparition unless you pay {1}{U}."); cardType.add(CardType.CREATURE); subtype.add(SubType.ILLUSION); power = new MageInt(3); toughness = new MageInt(3); - Ability ability = new BeginningOfUpkeepTriggeredAbility(new DoUnlessControllerPaysEffect(new SacrificeSourceEffect(), new ManaCostsImpl<>("{1}{U}"))); - this.addAbility(ability); + this.addAbility(FlyingAbility.getInstance()); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl<>("{1}{U}")) + )); } - private VeilApparitionToken(final VeilApparitionToken token) { + private VeiledApparitionToken(final VeiledApparitionToken token) { super(token); } - public VeilApparitionToken copy() { - return new VeilApparitionToken(this); + public VeiledApparitionToken copy() { + return new VeiledApparitionToken(this); } }