From 24adedfbc5c1d9b5cb4a0fb6f9bec74ed3fb3c13 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 12:05:32 -0400 Subject: [PATCH 01/71] updated C18 spoiler --- Mage.Sets/src/mage/sets/Commander2018.java | 4 ++++ Utils/mtg-cards-data.txt | 13 ++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index a7684a575a0..08e0ce8b583 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -20,11 +20,15 @@ public final class Commander2018 extends ExpansionSet { super("Commander 2018 Edition", "C18", ExpansionSet.buildDate(2018, 8, 10), SetType.SUPPLEMENTAL); this.blockName = "Command Zone"; + cards.add(new SetCardInfo("Avenger of Zendikar", 129, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class)); + cards.add(new SetCardInfo("Budoka Gardener", 134, Rarity.RARE, mage.cards.b.BudokaGardener.class)); + cards.add(new SetCardInfo("Chain Reaction", 121, Rarity.RARE, mage.cards.c.ChainReaction.class)); cards.add(new SetCardInfo("Chaos Warp", 122, Rarity.RARE, mage.cards.c.ChaosWarp.class)); cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); + cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); cards.add(new SetCardInfo("Saheeli's Directive", 26, Rarity.RARE, mage.cards.s.SaheelisDirective.class)); cards.add(new SetCardInfo("Tawnos, Urza's Apprentice", 45, Rarity.MYTHIC, mage.cards.t.TawnosUrzasApprentice.class)); cards.add(new SetCardInfo("Thopter Spy Network", 107, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index cf70702e450..a7229b949b7 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33928,17 +33928,28 @@ Forest|Global Series: Jiang Yanggu & Mu Yanling|40|C||Basic Land - Forest|||({T} Echo Storm|Commander 2018|7|R|{3}{U}{U}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.$Create a token that's a copy of target artifact.| Loyal Drake|Commander 2018|10|U|{2}{U}|Creature - Drake|2|2|Flying$Lieutenant — At the beginning of combat on your turn, if you control your commander, draw a card.| Vedalken Humiliator|Commander 2018|13|R|{3}{U}|Creature - Vedalken Wizard|3|4|Metalcraft — Whenever Vedalken Humiliator attacks, if you control three or more artifacts, creatures your opponents control lose all abilities and have base power and toughness 1/1 until end of turn.| +Emissary of Grudges|Commander 2018|20|R|{5}{R}|Creature - Efreet|6|4|Flying, haste$As Emissary of Grudges enters the battlefield, secretly choose an opponent.$Reveal the player you chose: Choose new targets for target spell or ability if it's controlled by the chosen player and if it targets you or a permanent you control. Activate this ability only once.| Enchanter's Bane|Commander 2018|21|R|{1}{R}|Enchantment|||At the beginning of your end step, target enchantment deals damage equal to its converted mana cost to its controller unless that player sacrifices it.| +Fury Storm|Commander 2018|22|R|{2}{R}{R}|Instant|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.$Copy target instant or sorcery spell. You may choose new targets for the copy.| Saheeli's Directive|Commander 2018|26|R|{X}{R}{R}{R}|Sorcery|||Improvise$Reveal the top X cards of your library. You may put any number of artifact cards with converted mana cost X or less from among them onto the battlefield. Then put all cards revealed this way that weren't put onto the battlefield into your graveyard.| Treasure Nabber|Commander 2018|27|R|{2}{R}|Creature - Goblin Rogue|3|2|Whenever an opponent taps an artifact for mana, gain control of that artifact until the end of your next turn.| Varchild, Betrayer of Kjeldor|Commander 2018|28|R|{2}{R}|Legendary Creature - Human Knight|3|3|Whenever Varchild, Betrayer of Kjeldor deals combat damage to a player, that player creates that many 1/1 red Survivor creature tokens.$Survivors your opponents control can't block, and they can't attack you or a planeswalker you control.$When Varchild leaves the battlefield, gain control of all Survivors.| Brudiclad, Telchor Engineer|Commander 2018|39|M|{4}{U}{R}|Legendary Artifact Creature - Artificer|4|4|Creature tokens you control have haste.$At the beginning of combat on your turn, create a 2/1 blue Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token.| +Lord Windgrace|Commander 2018|43|M|{2}{B}{R}{G}|Legendary Planeswalker - Windgrace|5|+2: Discard a card, then draw a card. If a land card is discarded this way, draw an additional card.$-3: Return up to two target land cards from your graveyard to the battlefield.$-11: Destroy up to six target nonland permanents, then create six 2/2 green Cat Warrior creature tokens with forestwalk.$Lord Windgrace can be your commander.| Saheeli, the Gifted|Commander 2018|44|M|{2}{U}{R}|Legendary Planeswalker - Saheeli|4|+1: Create a 1/1 colorless Servo artifact creature token.$+1: The next spell you cast this turn costs {1} less to cast for each artifact you control as you cast it.$-7: For each artifact you control, create a token that's a copy of it. Those tokens gain haste. Exile those tokens at the beginning of the next end step.$Saheeli, the Gifted can be your commander.| Tawnos, Urza's Apprentice|Commander 2018|45|M|{U}{R}|Legendary Creature - Human Artificer|1|3|Haste${U}{R}, {T}: Copy target activated or triggered ability you control from an artifact source. You may choose new targets for the copy.| -Ancient Stone Idol|Commander 2018|53|R|{10}|Artifact Creature - Golem|12|12|Flash$This spell costs {1} less to cast for each attacking creature.$Trample$When Ancient Stone Idol dies, create a colorless 6/12 Construct artifact creature token with trample.| +Thantis the Warweaver|Commander 2018|46|M|{3}{B}{R}{G}|Legendary Creature - Spider|5|5|Vigilance, reach$All creatures attack each combat if able.$Whenever a creature attacks you or a planeswalker you control, put a +1/+1 counter on Thantis the Warweaver.| +Windgrace's Judgment|Commander 2018|49|R|{3}{B}{G}|Instant|||For any number of opponents, destroy target nonland permanent that player controls.| +Xantcha, Sleeper Agent|Commander 2018|50|R|{1}{B}{R}|Legendary Creature - Minion|5|5|As Xantcha, Sleeper Agent enters the battlefield, an opponent of your choice gains control of it.$Xantcha attacks each combat if able and can't attack its owner or planeswalkers its owner controls.${3}: Xantcha's controller loses 2 life and you draw a card. Any player may activate this ability.| +Ancient Stone Idol|Commander 2018|53|R|{10}|Artifact Creature - Golem|12|12|Flash$This spell costs {1} less to cast for each attacking creature.$Trample$When Ancient Stone Idol dies, create a 6/12 colorless Construct artifact creature token with trample.| Coveted Jewel|Commander 2018|54|R|{6}|Artifact|||When Coveted Jewel enters the battlefield, draw three cards.${T}: Add three mana of any one color.$Whenever one or more creatures an opponent controls attack you and aren't blocked, that player draws three cards and gains control of Coveted Jewel. Untap it.| +Endless Atlas|Commander 2018|55|R|{2}|Artifact|||{2}, {T}: Draw a card. Activate this ability only if you control three or more lands with the same name.| Geode Golem|Commander 2018|56|U|{5}|Artifact Creature - Golem|5|3|Trample$Whenever Geode Golem deals combat damage to a player, you may cast your commander from the command zone without paying its mana cost.| Retrofitter Foundry|Commander 2018|57|R|{1}|Artifact|||{3}: Untap Retrofitter Foundry.${2}, {T}: Create a 1/1 colorless Servo artifact creature token.${1}, {T}, Sacrifice a Servo: Create a 1/1 colorless Thopter artifact creature token with flying.${T}, Sacrifice a Thopter: Create a 4/4 colorless Construct artifact creature token.| Forge of Heroes|Commander 2018|58|C||Land|||{T}: Add {C}.${T}: Choose target commander that entered the battlefield this turn. Put a +1/+1 counter on it if it's a creature and a loyalty counter on it if it's a planeswalker.| Thopter Spy Network|Commander 2018|107|R|{2}{U}{U}|Enchantment|||At the beginning of your upkeep, if you control an artifact, create a 1/1 colorless Thopter artifact creature token with flying.$Whenever one or more artifact creatures you control deal combat damage to a player, draw a card.| +Ruinous Path|Commander 2018|117|R|{1}{B}{B}|Sorcery|||Destroy target creature or planeswalker.$Awaken 4—{5}{B}{B}| +Chain Reaction|Commander 2018|121|R|{2}{R}{R}|Sorcery|||Chain Reaction deals X damage to each creature, where X is the number of creatures on the battlefield.| Chaos Warp|Commander 2018|122|R|{2}{R}|Instant|||The owner of target permanent shuffles it into their library, then reveals the top card of their library. If it's a permanent card, they put it onto the battlefield.| +Avenger of Zendikar|Commander 2018|129|M|{5}{G}{G}|Creature - Elemental|5|5|When Avenger of Zendikar enters the battlefield, create a 0/1 green Plant creature token for each land you control.$Landfall — Whenever a land enters the battlefield under your control, you may put a +1/+1 counter on each Plant creature you control.| +Budoka Gardener|Commander 2018|134|R|{1}{G}|Creature - Human Monk|2|1|{T}: You may put a land card from your hand onto the battlefield. If you control ten or more lands, flip Budoka Gardener.| \ No newline at end of file From add593547570b9b9337c8662097066114bf36861 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 12:21:03 -0400 Subject: [PATCH 02/71] Implemented Ancient Stone Idol --- .../src/mage/cards/a/AncientStoneIdol.java | 99 +++++++++++++++++++ Mage.Sets/src/mage/cards/s/StoneIdolTrap.java | 3 +- Mage.Sets/src/mage/sets/Commander2018.java | 1 + 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/a/AncientStoneIdol.java diff --git a/Mage.Sets/src/mage/cards/a/AncientStoneIdol.java b/Mage.Sets/src/mage/cards/a/AncientStoneIdol.java new file mode 100644 index 00000000000..c9935eb2c3c --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AncientStoneIdol.java @@ -0,0 +1,99 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.constants.SubType; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.CostModificationType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.game.Game; +import mage.game.permanent.token.StoneTrapIdolToken; +import mage.util.CardUtil; + +/** + * + * @author TheElk801 + */ +public final class AncientStoneIdol extends CardImpl { + + public AncientStoneIdol(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{10}"); + + this.subtype.add(SubType.GOLEM); + this.power = new MageInt(12); + this.toughness = new MageInt(12); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // This spell costs {1} less to cast for each attacking creature. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new AncientStoneIdolCostReductionEffect())); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Ancient Stone Idol dies, create a 6/12 colorless Construct artifact creature token with trample. + this.addAbility(new DiesTriggeredAbility(new CreateTokenEffect(new StoneTrapIdolToken()))); + } + + public AncientStoneIdol(final AncientStoneIdol card) { + super(card); + } + + @Override + public AncientStoneIdol copy() { + return new AncientStoneIdol(this); + } +} + +class AncientStoneIdolCostReductionEffect extends CostModificationEffectImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(new AttackingPredicate()); + } + + public AncientStoneIdolCostReductionEffect() { + super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "This spell costs {1} less to cast for each attacking creature"; + } + + protected AncientStoneIdolCostReductionEffect(AncientStoneIdolCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + int reductionAmount = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + CardUtil.reduceCost(abilityToModify, reductionAmount); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if ((abilityToModify instanceof SpellAbility) && abilityToModify.getSourceId().equals(source.getSourceId())) { + return game.getCard(abilityToModify.getSourceId()) != null; + } + return false; + } + + @Override + public AncientStoneIdolCostReductionEffect copy() { + return new AncientStoneIdolCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StoneIdolTrap.java b/Mage.Sets/src/mage/cards/s/StoneIdolTrap.java index 3d4421c55d0..ec704870134 100644 --- a/Mage.Sets/src/mage/cards/s/StoneIdolTrap.java +++ b/Mage.Sets/src/mage/cards/s/StoneIdolTrap.java @@ -1,4 +1,3 @@ - package mage.cards.s; import mage.abilities.Ability; @@ -57,7 +56,7 @@ class StoneIdolTrapCostReductionEffect extends CostModificationEffectImpl { public StoneIdolTrapCostReductionEffect() { super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); - staticText = "{this} costs {1} less to cast for each attacking creature"; + staticText = "This spell costs {1} less to cast for each attacking creature"; } protected StoneIdolTrapCostReductionEffect(StoneIdolTrapCostReductionEffect effect) { diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 08e0ce8b583..91f1c2cfac7 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -20,6 +20,7 @@ public final class Commander2018 extends ExpansionSet { super("Commander 2018 Edition", "C18", ExpansionSet.buildDate(2018, 8, 10), SetType.SUPPLEMENTAL); this.blockName = "Command Zone"; + cards.add(new SetCardInfo("Ancient Stone Idol", 53, Rarity.RARE, mage.cards.a.AncientStoneIdol.class)); cards.add(new SetCardInfo("Avenger of Zendikar", 129, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class)); cards.add(new SetCardInfo("Budoka Gardener", 134, Rarity.RARE, mage.cards.b.BudokaGardener.class)); cards.add(new SetCardInfo("Chain Reaction", 121, Rarity.RARE, mage.cards.c.ChainReaction.class)); From e2ebe344d1b4a16394fc771fe89b34d8dda76275 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 12:23:33 -0400 Subject: [PATCH 03/71] updated C18 spoiler --- Mage.Sets/src/mage/sets/Commander2018.java | 1 + Utils/mtg-cards-data.txt | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 91f1c2cfac7..0d49ca83b47 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -25,6 +25,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Budoka Gardener", 134, Rarity.RARE, mage.cards.b.BudokaGardener.class)); cards.add(new SetCardInfo("Chain Reaction", 121, Rarity.RARE, mage.cards.c.ChainReaction.class)); cards.add(new SetCardInfo("Chaos Warp", 122, Rarity.RARE, mage.cards.c.ChaosWarp.class)); + cards.add(new SetCardInfo("Eidolon of Blossoms", 140, Rarity.RARE, mage.cards.e.EidolonOfBlossoms.class)); cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index a7229b949b7..cbad2df3503 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33928,9 +33928,11 @@ Forest|Global Series: Jiang Yanggu & Mu Yanling|40|C||Basic Land - Forest|||({T} Echo Storm|Commander 2018|7|R|{3}{U}{U}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.$Create a token that's a copy of target artifact.| Loyal Drake|Commander 2018|10|U|{2}{U}|Creature - Drake|2|2|Flying$Lieutenant — At the beginning of combat on your turn, if you control your commander, draw a card.| Vedalken Humiliator|Commander 2018|13|R|{3}{U}|Creature - Vedalken Wizard|3|4|Metalcraft — Whenever Vedalken Humiliator attacks, if you control three or more artifacts, creatures your opponents control lose all abilities and have base power and toughness 1/1 until end of turn.| +Loyal Subordinate|Commander 2018|16|U|{2}{B}|Creature - Zombie|3|1|Menace$Lieutenant — At the beginning of combat on your turn, if you control your commander, each opponent loses 3 life.| Emissary of Grudges|Commander 2018|20|R|{5}{R}|Creature - Efreet|6|4|Flying, haste$As Emissary of Grudges enters the battlefield, secretly choose an opponent.$Reveal the player you chose: Choose new targets for target spell or ability if it's controlled by the chosen player and if it targets you or a permanent you control. Activate this ability only once.| Enchanter's Bane|Commander 2018|21|R|{1}{R}|Enchantment|||At the beginning of your end step, target enchantment deals damage equal to its converted mana cost to its controller unless that player sacrifices it.| Fury Storm|Commander 2018|22|R|{2}{R}{R}|Instant|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.$Copy target instant or sorcery spell. You may choose new targets for the copy.| +Nesting Dragon|Commander 2018|24|R|{3}{R}{R}|Creature - Dragon|5|4|Flying$Landfall — Whenever a land enters the battlefield under your control, create a 0/2 red Dragon Egg creature token with defender and "When this creature dies, create a 2/2 red Dragon creature token with flying and '{R}: This creature gets +1/+0 until end of turn.'"| Saheeli's Directive|Commander 2018|26|R|{X}{R}{R}{R}|Sorcery|||Improvise$Reveal the top X cards of your library. You may put any number of artifact cards with converted mana cost X or less from among them onto the battlefield. Then put all cards revealed this way that weren't put onto the battlefield into your graveyard.| Treasure Nabber|Commander 2018|27|R|{2}{R}|Creature - Goblin Rogue|3|2|Whenever an opponent taps an artifact for mana, gain control of that artifact until the end of your next turn.| Varchild, Betrayer of Kjeldor|Commander 2018|28|R|{2}{R}|Legendary Creature - Human Knight|3|3|Whenever Varchild, Betrayer of Kjeldor deals combat damage to a player, that player creates that many 1/1 red Survivor creature tokens.$Survivors your opponents control can't block, and they can't attack you or a planeswalker you control.$When Varchild leaves the battlefield, gain control of all Survivors.| @@ -33952,4 +33954,5 @@ Ruinous Path|Commander 2018|117|R|{1}{B}{B}|Sorcery|||Destroy target creature or Chain Reaction|Commander 2018|121|R|{2}{R}{R}|Sorcery|||Chain Reaction deals X damage to each creature, where X is the number of creatures on the battlefield.| Chaos Warp|Commander 2018|122|R|{2}{R}|Instant|||The owner of target permanent shuffles it into their library, then reveals the top card of their library. If it's a permanent card, they put it onto the battlefield.| Avenger of Zendikar|Commander 2018|129|M|{5}{G}{G}|Creature - Elemental|5|5|When Avenger of Zendikar enters the battlefield, create a 0/1 green Plant creature token for each land you control.$Landfall — Whenever a land enters the battlefield under your control, you may put a +1/+1 counter on each Plant creature you control.| -Budoka Gardener|Commander 2018|134|R|{1}{G}|Creature - Human Monk|2|1|{T}: You may put a land card from your hand onto the battlefield. If you control ten or more lands, flip Budoka Gardener.| \ No newline at end of file +Budoka Gardener|Commander 2018|134|R|{1}{G}|Creature - Human Monk|2|1|{T}: You may put a land card from your hand onto the battlefield. If you control ten or more lands, flip Budoka Gardener.| +Eidolon of Blossoms|Commander 2018|140|R|{2}{G}{G}|Enchantment Creature - Spirit|2|2|Constellation — Whenever Eidolon of Blossoms or another enchantment enters the battlefield under your control, draw a card.| \ No newline at end of file From 85ad68a7a696abca6c95a43d1902541d0ad00c89 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 12:27:14 -0400 Subject: [PATCH 04/71] Implemented Loyal Subordinate --- .../src/mage/cards/l/LoyalSubordinate.java | 52 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 53 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/l/LoyalSubordinate.java diff --git a/Mage.Sets/src/mage/cards/l/LoyalSubordinate.java b/Mage.Sets/src/mage/cards/l/LoyalSubordinate.java new file mode 100644 index 00000000000..fe87346014a --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LoyalSubordinate.java @@ -0,0 +1,52 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.condition.common.CommanderInPlayCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.constants.SubType; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; + +/** + * + * @author TheElk801 + */ +public final class LoyalSubordinate extends CardImpl { + + public LoyalSubordinate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Menace + this.addAbility(new MenaceAbility()); + + // Lieutenant — At the beginning of combat on your turn, if you control your commander, each opponent loses 3 life. + this.addAbility(new ConditionalTriggeredAbility( + new BeginningOfCombatTriggeredAbility( + new LoseLifeOpponentsEffect(3), + TargetController.YOU, false + ), CommanderInPlayCondition.instance, + "Lieutenant — At the beginning of combat " + + "on your turn, if you control your commander, " + + "each opponent loses 3 life." + )); + } + + public LoyalSubordinate(final LoyalSubordinate card) { + super(card); + } + + @Override + public LoyalSubordinate copy() { + return new LoyalSubordinate(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 0d49ca83b47..4579f9b11b3 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -29,6 +29,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); + cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); cards.add(new SetCardInfo("Saheeli's Directive", 26, Rarity.RARE, mage.cards.s.SaheelisDirective.class)); From 82883f300fd0b634958ba695f34660c26c504e57 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 13:35:51 -0400 Subject: [PATCH 05/71] Implemented Thantis the Warweaver --- .../src/mage/cards/t/ThantisTheWarweaver.java | 65 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 66 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/ThantisTheWarweaver.java diff --git a/Mage.Sets/src/mage/cards/t/ThantisTheWarweaver.java b/Mage.Sets/src/mage/cards/t/ThantisTheWarweaver.java new file mode 100644 index 00000000000..75fc2ef69b9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThantisTheWarweaver.java @@ -0,0 +1,65 @@ +package mage.cards.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.AttacksAllTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.AttacksIfAbleAllEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +/** + * + * @author TheElk801 + */ +public final class ThantisTheWarweaver extends CardImpl { + + public ThantisTheWarweaver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SPIDER); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // All creatures attack each combat if able. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new AttacksIfAbleAllEffect( + StaticFilters.FILTER_PERMANENT_CREATURES, + Duration.WhileOnBattlefield, true + ).setText("All creatures attack each combat if able") + )); + + // Whenever a creature attacks you or a planeswalker you control, put a +1/+1 counter on Thantis the Warweaver. + this.addAbility(new AttacksAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + false, true + )); + } + + public ThantisTheWarweaver(final ThantisTheWarweaver card) { + super(card); + } + + @Override + public ThantisTheWarweaver copy() { + return new ThantisTheWarweaver(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 4579f9b11b3..b5950030cd3 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -34,6 +34,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); cards.add(new SetCardInfo("Saheeli's Directive", 26, Rarity.RARE, mage.cards.s.SaheelisDirective.class)); cards.add(new SetCardInfo("Tawnos, Urza's Apprentice", 45, Rarity.MYTHIC, mage.cards.t.TawnosUrzasApprentice.class)); + cards.add(new SetCardInfo("Thantis the Warweaver", 46, Rarity.MYTHIC, mage.cards.t.ThantisTheWarweaver.class)); cards.add(new SetCardInfo("Thopter Spy Network", 107, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class)); } } From 0dfe6983d28818369206238c61c67af39911f873 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 13:37:13 -0400 Subject: [PATCH 06/71] updated C18 spoiler --- Utils/mtg-cards-data.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index cbad2df3503..8bc0f867d7e 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33928,14 +33928,17 @@ Forest|Global Series: Jiang Yanggu & Mu Yanling|40|C||Basic Land - Forest|||({T} Echo Storm|Commander 2018|7|R|{3}{U}{U}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.$Create a token that's a copy of target artifact.| Loyal Drake|Commander 2018|10|U|{2}{U}|Creature - Drake|2|2|Flying$Lieutenant — At the beginning of combat on your turn, if you control your commander, draw a card.| Vedalken Humiliator|Commander 2018|13|R|{3}{U}|Creature - Vedalken Wizard|3|4|Metalcraft — Whenever Vedalken Humiliator attacks, if you control three or more artifacts, creatures your opponents control lose all abilities and have base power and toughness 1/1 until end of turn.| +Bloodtracker|Commander 2018|14|R|{3}{B}|Creature - Vampire Wizard|2|2|Flying${B}, Pay 2 life: Put a +1/+1 counter on Bloodtracker.$When Bloodtracker leaves the battlefield, draw a card for each +1/+1 counter on it.| Loyal Subordinate|Commander 2018|16|U|{2}{B}|Creature - Zombie|3|1|Menace$Lieutenant — At the beginning of combat on your turn, if you control your commander, each opponent loses 3 life.| Emissary of Grudges|Commander 2018|20|R|{5}{R}|Creature - Efreet|6|4|Flying, haste$As Emissary of Grudges enters the battlefield, secretly choose an opponent.$Reveal the player you chose: Choose new targets for target spell or ability if it's controlled by the chosen player and if it targets you or a permanent you control. Activate this ability only once.| Enchanter's Bane|Commander 2018|21|R|{1}{R}|Enchantment|||At the beginning of your end step, target enchantment deals damage equal to its converted mana cost to its controller unless that player sacrifices it.| Fury Storm|Commander 2018|22|R|{2}{R}{R}|Instant|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.$Copy target instant or sorcery spell. You may choose new targets for the copy.| Nesting Dragon|Commander 2018|24|R|{3}{R}{R}|Creature - Dragon|5|4|Flying$Landfall — Whenever a land enters the battlefield under your control, create a 0/2 red Dragon Egg creature token with defender and "When this creature dies, create a 2/2 red Dragon creature token with flying and '{R}: This creature gets +1/+0 until end of turn.'"| +Reality Scramble|Commander 2018|25|R|{2}{R}{R}|Sorcery|||Put target permanent you own on the bottom of your library. Reveal cards from the top of your library until you reveal a card that shares a card type with that permanent. Put that card onto the battlefield and the rest on the bottom of your library in a random order.$Retrace| Saheeli's Directive|Commander 2018|26|R|{X}{R}{R}{R}|Sorcery|||Improvise$Reveal the top X cards of your library. You may put any number of artifact cards with converted mana cost X or less from among them onto the battlefield. Then put all cards revealed this way that weren't put onto the battlefield into your graveyard.| Treasure Nabber|Commander 2018|27|R|{2}{R}|Creature - Goblin Rogue|3|2|Whenever an opponent taps an artifact for mana, gain control of that artifact until the end of your next turn.| Varchild, Betrayer of Kjeldor|Commander 2018|28|R|{2}{R}|Legendary Creature - Human Knight|3|3|Whenever Varchild, Betrayer of Kjeldor deals combat damage to a player, that player creates that many 1/1 red Survivor creature tokens.$Survivors your opponents control can't block, and they can't attack you or a planeswalker you control.$When Varchild leaves the battlefield, gain control of all Survivors.| +Loyal Guardian|Commander 2018|31|U|{4}{G}|Creature - Rhino|4|4|Trample$Lieutenant — At the beginning of combat on your turn, if you control your commander, put a +1/+1 counter on each creature you control.| Brudiclad, Telchor Engineer|Commander 2018|39|M|{4}{U}{R}|Legendary Artifact Creature - Artificer|4|4|Creature tokens you control have haste.$At the beginning of combat on your turn, create a 2/1 blue Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token.| Lord Windgrace|Commander 2018|43|M|{2}{B}{R}{G}|Legendary Planeswalker - Windgrace|5|+2: Discard a card, then draw a card. If a land card is discarded this way, draw an additional card.$-3: Return up to two target land cards from your graveyard to the battlefield.$-11: Destroy up to six target nonland permanents, then create six 2/2 green Cat Warrior creature tokens with forestwalk.$Lord Windgrace can be your commander.| Saheeli, the Gifted|Commander 2018|44|M|{2}{U}{R}|Legendary Planeswalker - Saheeli|4|+1: Create a 1/1 colorless Servo artifact creature token.$+1: The next spell you cast this turn costs {1} less to cast for each artifact you control as you cast it.$-7: For each artifact you control, create a token that's a copy of it. Those tokens gain haste. Exile those tokens at the beginning of the next end step.$Saheeli, the Gifted can be your commander.| From b4da7e1c3717f0c1eb7b91548e2c285e8fef9b92 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 13:43:09 -0400 Subject: [PATCH 07/71] Implemented Loyal Guardian --- Mage.Sets/src/mage/cards/l/LoyalGuardian.java | 56 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 57 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/l/LoyalGuardian.java diff --git a/Mage.Sets/src/mage/cards/l/LoyalGuardian.java b/Mage.Sets/src/mage/cards/l/LoyalGuardian.java new file mode 100644 index 00000000000..9b368b0bac7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LoyalGuardian.java @@ -0,0 +1,56 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.condition.common.CommanderInPlayCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.constants.SubType; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +/** + * + * @author TheElk801 + */ +public final class LoyalGuardian extends CardImpl { + + public LoyalGuardian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.RHINO); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Lieutenant — At the beginning of combat on your turn, if you control your commander, put a +1/+1 counter on each creature you control. + this.addAbility(new ConditionalTriggeredAbility( + new BeginningOfCombatTriggeredAbility( + new AddCountersAllEffect( + CounterType.P1P1.createInstance(), + StaticFilters.FILTER_CONTROLLED_CREATURE + ), TargetController.YOU, false + ), CommanderInPlayCondition.instance, + "Lieutenant — At the beginning of combat " + + "on your turn, if you control your commander, " + + "put a +1/+1 counter on each creature you control." + )); + } + + public LoyalGuardian(final LoyalGuardian card) { + super(card); + } + + @Override + public LoyalGuardian copy() { + return new LoyalGuardian(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index b5950030cd3..2079031f4d1 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -29,6 +29,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); + cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); From 11cb8bac08af36eed8aad69926e3fbf9cfbbb2fd Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 13:51:33 -0400 Subject: [PATCH 08/71] Implemented Bloodtracker --- Mage.Sets/src/mage/cards/b/Bloodtracker.java | 57 ++++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 58 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/Bloodtracker.java diff --git a/Mage.Sets/src/mage/cards/b/Bloodtracker.java b/Mage.Sets/src/mage/cards/b/Bloodtracker.java new file mode 100644 index 00000000000..bd4895f996e --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/Bloodtracker.java @@ -0,0 +1,57 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; + +/** + * + * @author TheElk801 + */ +public final class Bloodtracker extends CardImpl { + + public Bloodtracker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {B}, Pay 2 life: Put a +1/+1 counter on Bloodtracker. + Ability ability = new SimpleActivatedAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl("{B}")); + ability.addCost(new PayLifeCost(2)); + this.addAbility(ability); + + // When Bloodtracker leaves the battlefield, draw a card for each +1/+1 counter on it. + this.addAbility(new LeavesBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(new CountersSourceCount(CounterType.P1P1)) + .setText("draw a card for each +1/+1 counter on it"), false + )); + } + + public Bloodtracker(final Bloodtracker card) { + super(card); + } + + @Override + public Bloodtracker copy() { + return new Bloodtracker(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 2079031f4d1..9aea59ed9d1 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -22,6 +22,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Ancient Stone Idol", 53, Rarity.RARE, mage.cards.a.AncientStoneIdol.class)); cards.add(new SetCardInfo("Avenger of Zendikar", 129, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class)); + cards.add(new SetCardInfo("Bloodtracker", 14, Rarity.RARE, mage.cards.b.Bloodtracker.class)); cards.add(new SetCardInfo("Budoka Gardener", 134, Rarity.RARE, mage.cards.b.BudokaGardener.class)); cards.add(new SetCardInfo("Chain Reaction", 121, Rarity.RARE, mage.cards.c.ChainReaction.class)); cards.add(new SetCardInfo("Chaos Warp", 122, Rarity.RARE, mage.cards.c.ChaosWarp.class)); From b248a3cd6896d05cde79b2e048387e16cfbce0e4 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 14:49:47 -0400 Subject: [PATCH 09/71] updated C18 spoiler --- Mage.Sets/src/mage/sets/Commander2018.java | 4 ++++ Utils/mtg-cards-data.txt | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 9aea59ed9d1..9df3b67e07a 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -24,17 +24,21 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Avenger of Zendikar", 129, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class)); cards.add(new SetCardInfo("Bloodtracker", 14, Rarity.RARE, mage.cards.b.Bloodtracker.class)); cards.add(new SetCardInfo("Budoka Gardener", 134, Rarity.RARE, mage.cards.b.BudokaGardener.class)); + cards.add(new SetCardInfo("Centaur Vinecrasher", 135, Rarity.RARE, mage.cards.c.CentaurVinecrasher.class)); cards.add(new SetCardInfo("Chain Reaction", 121, Rarity.RARE, mage.cards.c.ChainReaction.class)); cards.add(new SetCardInfo("Chaos Warp", 122, Rarity.RARE, mage.cards.c.ChaosWarp.class)); cards.add(new SetCardInfo("Eidolon of Blossoms", 140, Rarity.RARE, mage.cards.e.EidolonOfBlossoms.class)); cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); + cards.add(new SetCardInfo("Explosive Vegetation", 144, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); + cards.add(new SetCardInfo("Rampaging Baloths", 158, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); cards.add(new SetCardInfo("Saheeli's Directive", 26, Rarity.RARE, mage.cards.s.SaheelisDirective.class)); + cards.add(new SetCardInfo("Scute Mob", 161, Rarity.RARE, mage.cards.s.ScuteMob.class)); cards.add(new SetCardInfo("Tawnos, Urza's Apprentice", 45, Rarity.MYTHIC, mage.cards.t.TawnosUrzasApprentice.class)); cards.add(new SetCardInfo("Thantis the Warweaver", 46, Rarity.MYTHIC, mage.cards.t.ThantisTheWarweaver.class)); cards.add(new SetCardInfo("Thopter Spy Network", 107, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 8bc0f867d7e..a19bbd7e377 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33939,7 +33939,9 @@ Saheeli's Directive|Commander 2018|26|R|{X}{R}{R}{R}|Sorcery|||Improvise$Reveal Treasure Nabber|Commander 2018|27|R|{2}{R}|Creature - Goblin Rogue|3|2|Whenever an opponent taps an artifact for mana, gain control of that artifact until the end of your next turn.| Varchild, Betrayer of Kjeldor|Commander 2018|28|R|{2}{R}|Legendary Creature - Human Knight|3|3|Whenever Varchild, Betrayer of Kjeldor deals combat damage to a player, that player creates that many 1/1 red Survivor creature tokens.$Survivors your opponents control can't block, and they can't attack you or a planeswalker you control.$When Varchild leaves the battlefield, gain control of all Survivors.| Loyal Guardian|Commander 2018|31|U|{4}{G}|Creature - Rhino|4|4|Trample$Lieutenant — At the beginning of combat on your turn, if you control your commander, put a +1/+1 counter on each creature you control.| +Whiptongue Hydra|Commander 2018|36|R|{5}{G}|Creature - Lizard Hydra|4|4|Reach$When Whiptongue Hydra enters the battlefield, destroy all creatures with flying. Put a +1/+1 counter on Whiptongue Hydra for each creature destroyed this way.| Brudiclad, Telchor Engineer|Commander 2018|39|M|{4}{U}{R}|Legendary Artifact Creature - Artificer|4|4|Creature tokens you control have haste.$At the beginning of combat on your turn, create a 2/1 blue Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token.| +Gyrus, Walker of Corpses|Commander 2018|41|M|{X}{B}{R}{G}|Legendary Creature - Hydra|0|0|Gyrus, Walker of Corpses enters the battlefield with a number of +1/+1 counters on it equal to the amount of mana spent to cast it.$Whenever Gyrus attacks, you may exile target creature card with lesser power from your graveyard. If you do, create a token that's a copy of that card and that's tapped and attacking. Exile the token at the end of combat.| Lord Windgrace|Commander 2018|43|M|{2}{B}{R}{G}|Legendary Planeswalker - Windgrace|5|+2: Discard a card, then draw a card. If a land card is discarded this way, draw an additional card.$-3: Return up to two target land cards from your graveyard to the battlefield.$-11: Destroy up to six target nonland permanents, then create six 2/2 green Cat Warrior creature tokens with forestwalk.$Lord Windgrace can be your commander.| Saheeli, the Gifted|Commander 2018|44|M|{2}{U}{R}|Legendary Planeswalker - Saheeli|4|+1: Create a 1/1 colorless Servo artifact creature token.$+1: The next spell you cast this turn costs {1} less to cast for each artifact you control as you cast it.$-7: For each artifact you control, create a token that's a copy of it. Those tokens gain haste. Exile those tokens at the beginning of the next end step.$Saheeli, the Gifted can be your commander.| Tawnos, Urza's Apprentice|Commander 2018|45|M|{U}{R}|Legendary Creature - Human Artificer|1|3|Haste${U}{R}, {T}: Copy target activated or triggered ability you control from an artifact source. You may choose new targets for the copy.| @@ -33958,4 +33960,8 @@ Chain Reaction|Commander 2018|121|R|{2}{R}{R}|Sorcery|||Chain Reaction deals X d Chaos Warp|Commander 2018|122|R|{2}{R}|Instant|||The owner of target permanent shuffles it into their library, then reveals the top card of their library. If it's a permanent card, they put it onto the battlefield.| Avenger of Zendikar|Commander 2018|129|M|{5}{G}{G}|Creature - Elemental|5|5|When Avenger of Zendikar enters the battlefield, create a 0/1 green Plant creature token for each land you control.$Landfall — Whenever a land enters the battlefield under your control, you may put a +1/+1 counter on each Plant creature you control.| Budoka Gardener|Commander 2018|134|R|{1}{G}|Creature - Human Monk|2|1|{T}: You may put a land card from your hand onto the battlefield. If you control ten or more lands, flip Budoka Gardener.| -Eidolon of Blossoms|Commander 2018|140|R|{2}{G}{G}|Enchantment Creature - Spirit|2|2|Constellation — Whenever Eidolon of Blossoms or another enchantment enters the battlefield under your control, draw a card.| \ No newline at end of file +Centaur Vinecrasher|Commander 2018|135|R|{3}{G}|Creature - Plant Centaur|1|1|Trample$Centaur Vinecrasher enters the battlefield with a number of +1/+1 counters on it equal to the number of land cards in all graveyards.$Whenever a land card is put into a graveyard from anywhere, you may pay {G}{G}. If you do, return Centaur Vinecrasher from your graveyard to your hand.| +Eidolon of Blossoms|Commander 2018|140|R|{2}{G}{G}|Enchantment Creature - Spirit|2|2|Constellation — Whenever Eidolon of Blossoms or another enchantment enters the battlefield under your control, draw a card.| +Explosive Vegetation|Commander 2018|144|U|{3}{G}|Sorcery|||Search your library for up to two basic land cards and put them onto the battlefield tapped. Then shuffle your library.| +Rampaging Baloths|Commander 2018|158|R|{4}{G}{G}|Creature - Beast|6|6|Trample$Landfall — Whenever a land enters the battlefield under your control, you may create a 4/4 green Beast creature token.| +Scute Mob|Commander 2018|161|R|{G}|Creature - Insect|1|1|At the beginning of your upkeep, if you control five or more lands, put four +1/+1 counters on Scute Mob.| \ No newline at end of file From 29c5936075dc83e62eedb9fc6733eec0c916f938 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 15:23:48 -0400 Subject: [PATCH 10/71] Implemented Whiptongue Hydra --- .../src/mage/cards/w/WhiptongueHydra.java | 91 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 92 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WhiptongueHydra.java diff --git a/Mage.Sets/src/mage/cards/w/WhiptongueHydra.java b/Mage.Sets/src/mage/cards/w/WhiptongueHydra.java new file mode 100644 index 00000000000..fae1fde2f16 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WhiptongueHydra.java @@ -0,0 +1,91 @@ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.constants.SubType; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author TheElk801 + */ +public final class WhiptongueHydra extends CardImpl { + + public WhiptongueHydra(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}"); + + this.subtype.add(SubType.LIZARD); + this.subtype.add(SubType.HYDRA); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // When Whiptongue Hydra enters the battlefield, destroy all creatures with flying. Put a +1/+1 counter on Whiptongue Hydra for each creature destroyed this way. + this.addAbility(new EntersBattlefieldTriggeredAbility(new WhiptongueHydraEffect(), false)); + } + + public WhiptongueHydra(final WhiptongueHydra card) { + super(card); + } + + @Override + public WhiptongueHydra copy() { + return new WhiptongueHydra(this); + } +} + +class WhiptongueHydraEffect extends OneShotEffect { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public WhiptongueHydraEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "destroy all creatures with flying. " + + "Put a +1/+1 counter on {this} for each permanent destroyed this way"; + } + + public WhiptongueHydraEffect(final WhiptongueHydraEffect effect) { + super(effect); + } + + @Override + public WhiptongueHydraEffect copy() { + return new WhiptongueHydraEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int destroyedPermanents = 0; + destroyedPermanents = game.getBattlefield().getActivePermanents( + filter, source.getControllerId(), source.getSourceId(), game + ).stream().filter( + (permanent) -> (permanent.destroy(source.getSourceId(), game, false)) + ).map((_item) -> 1).reduce(destroyedPermanents, Integer::sum); + if (destroyedPermanents > 0) { + return new AddCountersSourceEffect( + CounterType.P1P1.createInstance(destroyedPermanents), true + ).apply(game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 9df3b67e07a..a7562f0fb73 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -42,5 +42,6 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Tawnos, Urza's Apprentice", 45, Rarity.MYTHIC, mage.cards.t.TawnosUrzasApprentice.class)); cards.add(new SetCardInfo("Thantis the Warweaver", 46, Rarity.MYTHIC, mage.cards.t.ThantisTheWarweaver.class)); cards.add(new SetCardInfo("Thopter Spy Network", 107, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class)); + cards.add(new SetCardInfo("Whiptongue Hydra", 36, Rarity.RARE, mage.cards.w.WhiptongueHydra.class)); } } From 2d23d5c84e91212db90555abac002dd814518e6b Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 17:10:13 -0400 Subject: [PATCH 11/71] Implemented Echo Storm --- Mage.Sets/src/mage/cards/e/EchoStorm.java | 36 ++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + .../keyword/CommanderStormAbility.java | 107 ++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EchoStorm.java create mode 100644 Mage/src/main/java/mage/abilities/keyword/CommanderStormAbility.java diff --git a/Mage.Sets/src/mage/cards/e/EchoStorm.java b/Mage.Sets/src/mage/cards/e/EchoStorm.java new file mode 100644 index 00000000000..3a7277c482d --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EchoStorm.java @@ -0,0 +1,36 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.keyword.CommanderStormAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetArtifactPermanent; + +/** + * + * @author TheElk801 + */ +public final class EchoStorm extends CardImpl { + + public EchoStorm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}{U}"); + + // When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies. + this.addAbility(new CommanderStormAbility()); + + // Create a token that's a copy of target artifact. + this.getSpellAbility().addEffect(new CreateTokenCopyTargetEffect()); + this.getSpellAbility().addTarget(new TargetArtifactPermanent()); + } + + public EchoStorm(final EchoStorm card) { + super(card); + } + + @Override + public EchoStorm copy() { + return new EchoStorm(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index a7562f0fb73..e5a90cd11f5 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -27,6 +27,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Centaur Vinecrasher", 135, Rarity.RARE, mage.cards.c.CentaurVinecrasher.class)); cards.add(new SetCardInfo("Chain Reaction", 121, Rarity.RARE, mage.cards.c.ChainReaction.class)); cards.add(new SetCardInfo("Chaos Warp", 122, Rarity.RARE, mage.cards.c.ChaosWarp.class)); + cards.add(new SetCardInfo("Echo Storm", 7, Rarity.RARE, mage.cards.e.EchoStorm.class)); cards.add(new SetCardInfo("Eidolon of Blossoms", 140, Rarity.RARE, mage.cards.e.EidolonOfBlossoms.class)); cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); cards.add(new SetCardInfo("Explosive Vegetation", 144, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); diff --git a/Mage/src/main/java/mage/abilities/keyword/CommanderStormAbility.java b/Mage/src/main/java/mage/abilities/keyword/CommanderStormAbility.java new file mode 100644 index 00000000000..a40d3de2f53 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/CommanderStormAbility.java @@ -0,0 +1,107 @@ +package mage.abilities.keyword; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; +import mage.players.Player; + +/** + * + * @author Plopman + */ +public class CommanderStormAbility extends TriggeredAbilityImpl { + + public CommanderStormAbility() { + super(Zone.STACK, new CommanderStormEffect()); + this.ruleAtTheTop = true; + } + + private CommanderStormAbility(final CommanderStormAbility ability) { + super(ability); + } + + @Override + public CommanderStormAbility copy() { + return new CommanderStormAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getSourceId().equals(getSourceId())) { + StackObject spell = game.getStack().getStackObject(getSourceId()); + if (spell instanceof Spell) { + for (Effect effect : this.getEffects()) { + effect.setValue("StormSpell", spell); + effect.setValue("StormSpellRef", new MageObjectReference(spell.getId(), game)); + } + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "When you cast this spell, copy it for each time you've " + + "cast your commander from the command zone this game. " + + "You may choose new targets for the copies."; + } +} + +class CommanderStormEffect extends OneShotEffect { + + public CommanderStormEffect() { + super(Outcome.Copy); + } + + public CommanderStormEffect(final CommanderStormEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + MageObjectReference spellRef = (MageObjectReference) this.getValue("StormSpellRef"); + if (spellRef == null) { + return false; + } + int stormCount = 0; + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + stormCount = player.getCommandersIds().stream().map( + (commanderId) -> (Integer) game.getState().getValue(commanderId + "_castCount") + ).map((castCount) -> castCount).reduce(stormCount, Integer::sum); + if (stormCount == 0) { + return true; + } + Spell spell = (Spell) this.getValue("StormSpell"); + if (spell == null) { + return false; + } + game.informPlayers(spell.getLogName() + " will be copied " + stormCount + " time" + (stormCount > 1 ? "s" : "")); + for (int i = 0; i < stormCount; i++) { + spell.createCopyOnStack(game, source, source.getControllerId(), true); + } + return true; + } + + @Override + public CommanderStormEffect copy() { + return new CommanderStormEffect(this); + } +} From d6702ea1deb00fb12e7fb348e28cc92f42c8195a Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 17:11:30 -0400 Subject: [PATCH 12/71] Implemented Fury Storm --- Mage.Sets/src/mage/cards/f/FuryStorm.java | 37 ++++++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 38 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/f/FuryStorm.java diff --git a/Mage.Sets/src/mage/cards/f/FuryStorm.java b/Mage.Sets/src/mage/cards/f/FuryStorm.java new file mode 100644 index 00000000000..ce1ad8bd1ef --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FuryStorm.java @@ -0,0 +1,37 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.abilities.effects.common.CopyTargetSpellEffect; +import mage.abilities.keyword.CommanderStormAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetSpell; + +/** + * + * @author TheElk801 + */ +public final class FuryStorm extends CardImpl { + + public FuryStorm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}{R}"); + + // When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies. + this.addAbility(new CommanderStormAbility()); + + // Copy target instant or sorcery spell. You may choose new targets for the copy. + this.getSpellAbility().addEffect(new CopyTargetSpellEffect()); + this.getSpellAbility().addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY)); + } + + public FuryStorm(final FuryStorm card) { + super(card); + } + + @Override + public FuryStorm copy() { + return new FuryStorm(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index e5a90cd11f5..fc393222ece 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -32,6 +32,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); cards.add(new SetCardInfo("Explosive Vegetation", 144, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); + cards.add(new SetCardInfo("Fury Storm", 22, Rarity.RARE, mage.cards.f.FuryStorm.class)); cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); From 79120e7484210ae2aefe006300f3f1873867528b Mon Sep 17 00:00:00 2001 From: Quercitron Date: Wed, 25 Jul 2018 02:46:31 +0300 Subject: [PATCH 13/71] Make color distribution in booster more uniform --- Mage.Sets/src/mage/sets/Dominaria.java | 2 +- .../mage/test/sets/BoosterGenerationTest.java | 15 +++- .../main/java/mage/cards/ExpansionSet.java | 87 +++++++++++++++++-- Mage/src/main/java/mage/util/RandomUtil.java | 4 + 4 files changed, 95 insertions(+), 13 deletions(-) diff --git a/Mage.Sets/src/mage/sets/Dominaria.java b/Mage.Sets/src/mage/sets/Dominaria.java index 6e48f762fed..98d533f1954 100644 --- a/Mage.Sets/src/mage/sets/Dominaria.java +++ b/Mage.Sets/src/mage/sets/Dominaria.java @@ -26,7 +26,7 @@ public final class Dominaria extends ExpansionSet { this.numBoosterUncommon = 3; this.numBoosterRare = 1; this.ratioBoosterMythic = 8; - this.needsLegends = true; + this.needsLegendCreature = true; this.maxCardNumberInBooster = 269; cards.add(new SetCardInfo("Academy Drake", 40, Rarity.COMMON, mage.cards.a.AcademyDrake.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java index b6da9a2d9e5..85f8da3236c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java @@ -9,10 +9,8 @@ import mage.cards.repository.CardInfo; import mage.cards.repository.CardScanner; import mage.constants.CardType; import mage.constants.Rarity; -import mage.sets.CoreSet2019; -import mage.sets.FateReforged; -import mage.sets.MastersEditionII; -import mage.sets.MastersEditionIV; +import mage.sets.*; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -115,6 +113,15 @@ public class BoosterGenerationTest extends MageTestBase { assertTrue(allCards.stream().anyMatch(card -> card.getCardType().contains(CardType.LAND) && card.getRarity().equals(Rarity.COMMON))); } + @Test + public void testDominaria_EveryBoosterContainsLegendaryCreature() { + for (int i = 0; i < 10; i++) { + List booster = Dominaria.getInstance().createBooster(); + // check that booster contains legendary creature + assertTrue(booster.stream().anyMatch(card -> card.isCreature() && card.isLegendary())); + } + } + private static String str(List cards) { StringBuilder sb = new StringBuilder("["); Iterator iterator = cards.iterator(); diff --git a/Mage/src/main/java/mage/cards/ExpansionSet.java b/Mage/src/main/java/mage/cards/ExpansionSet.java index 2e0750d00e1..f58e7c41c98 100644 --- a/Mage/src/main/java/mage/cards/ExpansionSet.java +++ b/Mage/src/main/java/mage/cards/ExpansionSet.java @@ -1,6 +1,7 @@ package mage.cards; +import mage.ObjectColor; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; @@ -96,7 +97,11 @@ public abstract class ExpansionSet implements Serializable { protected int numBoosterRare; protected int numBoosterDoubleFaced; // -1 = include normally 0 = exclude 1-n = include explicit protected int ratioBoosterMythic; - protected boolean needsLegends = false; + + protected boolean needsLegendCreature = false; + protected boolean validateBoosterColors = true; + protected double rejectMissingColorProbability = 0.8; + protected double rejectSameColorUncommonsProbability = 0.8; protected int maxCardNumberInBooster; // used to omit cards with collector numbers beyond the regular cards in a set for boosters @@ -186,17 +191,83 @@ public abstract class ExpansionSet implements Serializable { } public List createBooster() { - if (needsLegends) { - for (int i = 0; i < 100000; i++) {//don't want to somehow loop forever - List booster = tryBooster(); - for (Card card : booster) { - if (card.isLegendary() && card.isCreature()) {// Dominaria packs must contain at least one legendary creature. - return booster; + for (int i = 0; i < 100; i++) {//don't want to somehow loop forever + List booster = tryBooster(); + if (boosterIsValid(booster)) { + return booster; + } + } + return tryBooster(); + } + + protected boolean boosterIsValid(List booster) { + if (validateBoosterColors) { + if (!validateColors(booster)) { + return false; + } + } + + if (needsLegendCreature) { + if (booster.stream().noneMatch(card -> card.isLegendary() && card.isCreature())) { + return false; + } + } + + return true; + } + + protected boolean validateColors(List booster) { + List magicColors = + Arrays.asList(ObjectColor.WHITE, ObjectColor.BLUE, ObjectColor.BLACK, ObjectColor.RED, ObjectColor.GREEN); + + // all cards colors + Map colorWeight = new HashMap<>(); + // uncommon/rare/mythic cards colors + Map uncommonWeight = new HashMap<>(); + + for (ObjectColor color : magicColors) { + colorWeight.put(color, 0); + uncommonWeight.put(color, 0); + } + + // count colors in the booster + for (Card card : booster) { + ObjectColor cardColor = card.getColor(null); + if (cardColor != null) { + List colors = cardColor.getColors(); + // todo: do we need gold color? + colors.remove(ObjectColor.GOLD); + if (!colors.isEmpty()) { + // 60 - full card weight + // multicolored cards add part of the weight to each color + int cardColorWeight = 60 / colors.size(); + for (ObjectColor color : colors) { + colorWeight.put(color, colorWeight.get(color) + cardColorWeight); + if (card.getRarity() != Rarity.COMMON) { + uncommonWeight.put(color, uncommonWeight.get(color) + cardColorWeight); + } } } } } - return tryBooster(); + + // check that all colors are present + if (magicColors.stream().anyMatch(color -> colorWeight.get(color) < 60)) { + // reject only part of the boosters + if (RandomUtil.nextDouble() < rejectMissingColorProbability) { + return false; + } + } + + // check that we don't have 3 or more uncommons/rares of the same color + if (magicColors.stream().anyMatch(color -> uncommonWeight.get(color) >= 180)) { + // reject only part of the boosters + if (RandomUtil.nextDouble() < rejectSameColorUncommonsProbability) { + return false; + } + } + + return true; } public List tryBooster() { diff --git a/Mage/src/main/java/mage/util/RandomUtil.java b/Mage/src/main/java/mage/util/RandomUtil.java index aa08d609386..29307983419 100644 --- a/Mage/src/main/java/mage/util/RandomUtil.java +++ b/Mage/src/main/java/mage/util/RandomUtil.java @@ -26,4 +26,8 @@ public final class RandomUtil { public static boolean nextBoolean() { return ThreadLocalRandom.current().nextBoolean(); } + + public static double nextDouble() { + return ThreadLocalRandom.current().nextDouble(); + } } From 8bf4d13aeb2caffa8175ba39dac58ab4ce3d37ab Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 20:15:32 -0400 Subject: [PATCH 14/71] updated C18 spoiler --- Utils/mtg-cards-data.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index a19bbd7e377..d6e2279a4ac 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33930,18 +33930,20 @@ Loyal Drake|Commander 2018|10|U|{2}{U}|Creature - Drake|2|2|Flying$Lieutenant Vedalken Humiliator|Commander 2018|13|R|{3}{U}|Creature - Vedalken Wizard|3|4|Metalcraft — Whenever Vedalken Humiliator attacks, if you control three or more artifacts, creatures your opponents control lose all abilities and have base power and toughness 1/1 until end of turn.| Bloodtracker|Commander 2018|14|R|{3}{B}|Creature - Vampire Wizard|2|2|Flying${B}, Pay 2 life: Put a +1/+1 counter on Bloodtracker.$When Bloodtracker leaves the battlefield, draw a card for each +1/+1 counter on it.| Loyal Subordinate|Commander 2018|16|U|{2}{B}|Creature - Zombie|3|1|Menace$Lieutenant — At the beginning of combat on your turn, if you control your commander, each opponent loses 3 life.| -Emissary of Grudges|Commander 2018|20|R|{5}{R}|Creature - Efreet|6|4|Flying, haste$As Emissary of Grudges enters the battlefield, secretly choose an opponent.$Reveal the player you chose: Choose new targets for target spell or ability if it's controlled by the chosen player and if it targets you or a permanent you control. Activate this ability only once.| +Emissary of Grudges|Commander 2018|20|R|{5}{R}|Creature - Efreet|6|5|Flying, haste$As Emissary of Grudges enters the battlefield, secretly choose an opponent.$Reveal the player you chose: Choose new targets for target spell or ability if it's controlled by the chosen player and if it targets you or a permanent you control. Activate this ability only once.| Enchanter's Bane|Commander 2018|21|R|{1}{R}|Enchantment|||At the beginning of your end step, target enchantment deals damage equal to its converted mana cost to its controller unless that player sacrifices it.| Fury Storm|Commander 2018|22|R|{2}{R}{R}|Instant|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.$Copy target instant or sorcery spell. You may choose new targets for the copy.| +Loyal Apprentice|Commander 2018|23|U|{1}{R}|Creature - Human Artificer|2|1|Haste$Lieutenant — At the beginning of combat on your turn, if you control your commander, create a 1/1 colorless Thopter artifact creature token with flying. That token gains haste until end of turn.| Nesting Dragon|Commander 2018|24|R|{3}{R}{R}|Creature - Dragon|5|4|Flying$Landfall — Whenever a land enters the battlefield under your control, create a 0/2 red Dragon Egg creature token with defender and "When this creature dies, create a 2/2 red Dragon creature token with flying and '{R}: This creature gets +1/+0 until end of turn.'"| Reality Scramble|Commander 2018|25|R|{2}{R}{R}|Sorcery|||Put target permanent you own on the bottom of your library. Reveal cards from the top of your library until you reveal a card that shares a card type with that permanent. Put that card onto the battlefield and the rest on the bottom of your library in a random order.$Retrace| Saheeli's Directive|Commander 2018|26|R|{X}{R}{R}{R}|Sorcery|||Improvise$Reveal the top X cards of your library. You may put any number of artifact cards with converted mana cost X or less from among them onto the battlefield. Then put all cards revealed this way that weren't put onto the battlefield into your graveyard.| Treasure Nabber|Commander 2018|27|R|{2}{R}|Creature - Goblin Rogue|3|2|Whenever an opponent taps an artifact for mana, gain control of that artifact until the end of your next turn.| Varchild, Betrayer of Kjeldor|Commander 2018|28|R|{2}{R}|Legendary Creature - Human Knight|3|3|Whenever Varchild, Betrayer of Kjeldor deals combat damage to a player, that player creates that many 1/1 red Survivor creature tokens.$Survivors your opponents control can't block, and they can't attack you or a planeswalker you control.$When Varchild leaves the battlefield, gain control of all Survivors.| +Crash of Rhino Beetles|Commander 2018|29|R|{4}{G}|Creature - Insect|5|5|Trample$Crash of Rhino Beetles gets +10/+10 as long as you control ten or more lands.| Loyal Guardian|Commander 2018|31|U|{4}{G}|Creature - Rhino|4|4|Trample$Lieutenant — At the beginning of combat on your turn, if you control your commander, put a +1/+1 counter on each creature you control.| Whiptongue Hydra|Commander 2018|36|R|{5}{G}|Creature - Lizard Hydra|4|4|Reach$When Whiptongue Hydra enters the battlefield, destroy all creatures with flying. Put a +1/+1 counter on Whiptongue Hydra for each creature destroyed this way.| Brudiclad, Telchor Engineer|Commander 2018|39|M|{4}{U}{R}|Legendary Artifact Creature - Artificer|4|4|Creature tokens you control have haste.$At the beginning of combat on your turn, create a 2/1 blue Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token.| -Gyrus, Walker of Corpses|Commander 2018|41|M|{X}{B}{R}{G}|Legendary Creature - Hydra|0|0|Gyrus, Walker of Corpses enters the battlefield with a number of +1/+1 counters on it equal to the amount of mana spent to cast it.$Whenever Gyrus attacks, you may exile target creature card with lesser power from your graveyard. If you do, create a token that's a copy of that card and that's tapped and attacking. Exile the token at the end of combat.| +Gyrus, Waker of Corpses|Commander 2018|41|M|{X}{B}{R}{G}|Legendary Creature - Hydra|0|0|Gyrus, Walker of Corpses enters the battlefield with a number of +1/+1 counters on it equal to the amount of mana spent to cast it.$Whenever Gyrus attacks, you may exile target creature card with lesser power from your graveyard. If you do, create a token that's a copy of that card and that's tapped and attacking. Exile the token at the end of combat.| Lord Windgrace|Commander 2018|43|M|{2}{B}{R}{G}|Legendary Planeswalker - Windgrace|5|+2: Discard a card, then draw a card. If a land card is discarded this way, draw an additional card.$-3: Return up to two target land cards from your graveyard to the battlefield.$-11: Destroy up to six target nonland permanents, then create six 2/2 green Cat Warrior creature tokens with forestwalk.$Lord Windgrace can be your commander.| Saheeli, the Gifted|Commander 2018|44|M|{2}{U}{R}|Legendary Planeswalker - Saheeli|4|+1: Create a 1/1 colorless Servo artifact creature token.$+1: The next spell you cast this turn costs {1} less to cast for each artifact you control as you cast it.$-7: For each artifact you control, create a token that's a copy of it. Those tokens gain haste. Exile those tokens at the beginning of the next end step.$Saheeli, the Gifted can be your commander.| Tawnos, Urza's Apprentice|Commander 2018|45|M|{U}{R}|Legendary Creature - Human Artificer|1|3|Haste${U}{R}, {T}: Copy target activated or triggered ability you control from an artifact source. You may choose new targets for the copy.| From ee361da05f4058e92e061c5cbd99c3e8a0d34a4c Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 20:28:52 -0400 Subject: [PATCH 15/71] Implemented Crash of Rhino Beetles --- .../src/mage/cards/c/CrashOfRhinoBeetles.java | 59 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 60 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/CrashOfRhinoBeetles.java diff --git a/Mage.Sets/src/mage/cards/c/CrashOfRhinoBeetles.java b/Mage.Sets/src/mage/cards/c/CrashOfRhinoBeetles.java new file mode 100644 index 00000000000..720d7490e2e --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrashOfRhinoBeetles.java @@ -0,0 +1,59 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.StaticFilters; + +/** + * + * @author TheElk801 + */ +public final class CrashOfRhinoBeetles extends CardImpl { + + public CrashOfRhinoBeetles(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.INSECT); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Crash of Rhino Beetles gets +10/+10 as long as you control ten or more lands. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new BoostSourceEffect( + 10, 10, Duration.WhileOnBattlefield + ), + new PermanentsOnTheBattlefieldCondition( + StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, + ComparisonType.MORE_THAN, 9 + ), + "{this} gets +10/+10 as long as you control ten or more lands" + ) + )); + } + + public CrashOfRhinoBeetles(final CrashOfRhinoBeetles card) { + super(card); + } + + @Override + public CrashOfRhinoBeetles copy() { + return new CrashOfRhinoBeetles(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index fc393222ece..e75d4836aab 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -27,6 +27,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Centaur Vinecrasher", 135, Rarity.RARE, mage.cards.c.CentaurVinecrasher.class)); cards.add(new SetCardInfo("Chain Reaction", 121, Rarity.RARE, mage.cards.c.ChainReaction.class)); cards.add(new SetCardInfo("Chaos Warp", 122, Rarity.RARE, mage.cards.c.ChaosWarp.class)); + cards.add(new SetCardInfo("Crash of Rhino Beetles", 29, Rarity.RARE, mage.cards.c.CrashOfRhinoBeetles.class)); cards.add(new SetCardInfo("Echo Storm", 7, Rarity.RARE, mage.cards.e.EchoStorm.class)); cards.add(new SetCardInfo("Eidolon of Blossoms", 140, Rarity.RARE, mage.cards.e.EidolonOfBlossoms.class)); cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); From 41fce60eee324ba49fe0dca3a0907ea319cf758f Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 20:45:45 -0400 Subject: [PATCH 16/71] Implemented Nesting Dragon --- Mage.Sets/src/mage/cards/n/NestingDragon.java | 44 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + .../permanent/token/NestingDragonToken.java | 45 +++++++++++++++++++ 3 files changed, 90 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/n/NestingDragon.java create mode 100644 Mage/src/main/java/mage/game/permanent/token/NestingDragonToken.java diff --git a/Mage.Sets/src/mage/cards/n/NestingDragon.java b/Mage.Sets/src/mage/cards/n/NestingDragon.java new file mode 100644 index 00000000000..9f50c82d243 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NestingDragon.java @@ -0,0 +1,44 @@ +package mage.cards.n; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.LandfallAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.NestingDragonToken; + +/** + * + * @author TheElk801 + */ +public final class NestingDragon extends CardImpl { + + public NestingDragon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Landfall — Whenever a land enters the battlefield under your control, create a 0/2 red Dragon Egg creature token with defender and "When this creature dies, create a 2/2 red Dragon creature token with flying and '{R}: This creature gets +1/+0 until end of turn.'" + this.addAbility(new LandfallAbility( + new CreateTokenEffect(new NestingDragonToken()), false + )); + } + + public NestingDragon(final NestingDragon card) { + super(card); + } + + @Override + public NestingDragon copy() { + return new NestingDragon(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index e75d4836aab..1828b27b149 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -37,6 +37,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); + cards.add(new SetCardInfo("Nesting Dragon", 24, Rarity.RARE, mage.cards.n.NestingDragon.class)); cards.add(new SetCardInfo("Rampaging Baloths", 158, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); diff --git a/Mage/src/main/java/mage/game/permanent/token/NestingDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/NestingDragonToken.java new file mode 100644 index 00000000000..e33ce893297 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/NestingDragonToken.java @@ -0,0 +1,45 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * + * @author spjspj + */ +public final class NestingDragonToken extends TokenImpl { + + public NestingDragonToken() { + super( + "Dragon Egg", + "0/2 red Dragon Egg creature token with defender and " + + "\"" + + "When this creature dies, " + + "create a 2/2 red Dragon creature token with flying and " + + "'{R}: This creature gets +1/+0 until end of turn.'" + + "\"" + ); + cardType.add(CardType.CREATURE); + color.setRed(true); + subtype.add(SubType.DRAGON); + subtype.add(SubType.EGG); + power = new MageInt(0); + toughness = new MageInt(2); + addAbility(DefenderAbility.getInstance()); + this.addAbility(new DiesTriggeredAbility( + new CreateTokenEffect(new DragonEggDragonToken()), false + )); + } + + public NestingDragonToken(final NestingDragonToken token) { + super(token); + } + + public NestingDragonToken copy() { + return new NestingDragonToken(this); + } +} From 489ca675993942784014f1511aaf84bc68034c6f Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 21:45:35 -0400 Subject: [PATCH 17/71] Implemented Varchild, Betrayer of Kjeldor --- .../cards/v/VarchildBetrayerOfKjeldor.java | 117 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 118 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/v/VarchildBetrayerOfKjeldor.java diff --git a/Mage.Sets/src/mage/cards/v/VarchildBetrayerOfKjeldor.java b/Mage.Sets/src/mage/cards/v/VarchildBetrayerOfKjeldor.java new file mode 100644 index 00000000000..bbff89dbf7c --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VarchildBetrayerOfKjeldor.java @@ -0,0 +1,117 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenTargetEffect; +import mage.abilities.effects.common.combat.CantAttackYouOrPlaneswalkerAllEffect; +import mage.abilities.effects.common.combat.CantBlockAllEffect; +import mage.abilities.effects.common.continuous.GainControlAllEffect; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.token.SurvivorToken; + +/** + * + * @author TheElk801 + */ +public final class VarchildBetrayerOfKjeldor extends CardImpl { + + private static final FilterCreaturePermanent filter1 + = new FilterCreaturePermanent( + SubType.SURVIVOR, + "Survivors your opponents control" + ); + private static final FilterCreaturePermanent filter2 + = new FilterCreaturePermanent( + SubType.SURVIVOR, "all Survivors" + ); + + static { + filter1.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public VarchildBetrayerOfKjeldor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever Varchild, Betrayer of Kjeldor deals combat damage to a player, that player creates that many 1/1 red Survivor creature tokens. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new VarchildBetrayerOfKjeldorEffect(), false, true + )); + + // Survivors your opponents control can't block, and they can't attack you or a planeswalker you control. + Ability ability = new SimpleStaticAbility( + Zone.BATTLEFIELD, + new CantBlockAllEffect( + filter1, Duration.WhileOnBattlefield + ) + ); + ability.addEffect(new CantAttackYouOrPlaneswalkerAllEffect( + Duration.WhileOnBattlefield, filter1 + ).setText("and can't attack you or a planeswalker you control")); + this.addAbility(ability); + + // When Varchild leaves the battlefield, gain control of all Survivors. + this.addAbility(new LeavesBattlefieldTriggeredAbility( + new GainControlAllEffect(Duration.Custom, filter2), false + )); + } + + public VarchildBetrayerOfKjeldor(final VarchildBetrayerOfKjeldor card) { + super(card); + } + + @Override + public VarchildBetrayerOfKjeldor copy() { + return new VarchildBetrayerOfKjeldor(this); + } +} + +class VarchildBetrayerOfKjeldorEffect extends OneShotEffect { + + public VarchildBetrayerOfKjeldorEffect() { + super(Outcome.Benefit); + this.staticText = "that player creates " + + "that many 1/1 red Survivor creature tokens"; + } + + public VarchildBetrayerOfKjeldorEffect(final VarchildBetrayerOfKjeldorEffect effect) { + super(effect); + } + + @Override + public VarchildBetrayerOfKjeldorEffect copy() { + return new VarchildBetrayerOfKjeldorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int damage = (int) this.getValue("damage"); + if (damage > 0) { + return new CreateTokenTargetEffect( + new SurvivorToken(), damage + ).apply(game, source); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 1828b27b149..9a1d6808eeb 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -46,6 +46,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Tawnos, Urza's Apprentice", 45, Rarity.MYTHIC, mage.cards.t.TawnosUrzasApprentice.class)); cards.add(new SetCardInfo("Thantis the Warweaver", 46, Rarity.MYTHIC, mage.cards.t.ThantisTheWarweaver.class)); cards.add(new SetCardInfo("Thopter Spy Network", 107, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class)); + cards.add(new SetCardInfo("Varchild, Betrayer of Kjeldor", 28, Rarity.RARE, mage.cards.v.VarchildBetrayerOfKjeldor.class)); cards.add(new SetCardInfo("Whiptongue Hydra", 36, Rarity.RARE, mage.cards.w.WhiptongueHydra.class)); } } From dd4b6f7996e300417224a86145b4496d81ad83dc Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Tue, 24 Jul 2018 22:22:13 -0400 Subject: [PATCH 18/71] Implemented Loyal Apprentice --- .../src/mage/cards/l/LoyalApprentice.java | 95 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 96 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/l/LoyalApprentice.java diff --git a/Mage.Sets/src/mage/cards/l/LoyalApprentice.java b/Mage.Sets/src/mage/cards/l/LoyalApprentice.java new file mode 100644 index 00000000000..048afacdf9e --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LoyalApprentice.java @@ -0,0 +1,95 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.condition.common.CommanderInPlayCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.constants.SubType; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.game.Game; +import mage.game.permanent.token.ThopterColorlessToken; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public final class LoyalApprentice extends CardImpl { + + public LoyalApprentice(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ARTIFICER); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Lieutenant — At the beginning of combat on your turn, if you control your commander, create a 1/1 colorless Thopter artifact creature token with flying. That token gains haste until end of turn. + this.addAbility(new ConditionalTriggeredAbility( + new BeginningOfCombatTriggeredAbility( + new LoyalApprenticeEffect(), + TargetController.YOU, false + ), CommanderInPlayCondition.instance, + "Lieutenant — At the beginning of combat " + + "on your turn, create a 1/1 colorless Thopter " + + "artifact creature token with flying. " + + "That token gains haste until end of turn" + )); + } + + public LoyalApprentice(final LoyalApprentice card) { + super(card); + } + + @Override + public LoyalApprentice copy() { + return new LoyalApprentice(this); + } +} + +class LoyalApprenticeEffect extends OneShotEffect { + + public LoyalApprenticeEffect() { + super(Outcome.Benefit); + } + + public LoyalApprenticeEffect(final LoyalApprenticeEffect effect) { + super(effect); + } + + @Override + public LoyalApprenticeEffect copy() { + return new LoyalApprenticeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + CreateTokenEffect effect = new CreateTokenEffect(new ThopterColorlessToken()); + effect.apply(game, source); + effect.getLastAddedTokenIds().stream().map((tokenId) -> { + ContinuousEffect continuousEffect = new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ); + continuousEffect.setTargetPointer(new FixedTarget(tokenId, game)); + return continuousEffect; + }).forEachOrdered((continuousEffect) -> { + game.addEffect(continuousEffect, source); + }); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 9a1d6808eeb..47faa9f978e 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -34,6 +34,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Explosive Vegetation", 144, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); cards.add(new SetCardInfo("Fury Storm", 22, Rarity.RARE, mage.cards.f.FuryStorm.class)); + cards.add(new SetCardInfo("Loyal Apprentice", 23, Rarity.UNCOMMON, mage.cards.l.LoyalApprentice.class)); cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); From fe74ea97a15fc48ca12c9f39137f163a64541e0c Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 25 Jul 2018 12:09:44 -0400 Subject: [PATCH 19/71] updated C18 spoilers --- Mage.Sets/src/mage/sets/Commander2018.java | 8 ++++++++ Utils/mtg-cards-data.txt | 19 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 47faa9f978e..2657b5ec4a8 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -22,18 +22,25 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Ancient Stone Idol", 53, Rarity.RARE, mage.cards.a.AncientStoneIdol.class)); cards.add(new SetCardInfo("Avenger of Zendikar", 129, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class)); + cards.add(new SetCardInfo("Bear Umbra", 131, Rarity.RARE, mage.cards.b.BearUmbra.class)); cards.add(new SetCardInfo("Bloodtracker", 14, Rarity.RARE, mage.cards.b.Bloodtracker.class)); + cards.add(new SetCardInfo("Bruna, Light of Alabaster", 170, Rarity.MYTHIC, mage.cards.b.BrunaLightOfAlabaster.class)); cards.add(new SetCardInfo("Budoka Gardener", 134, Rarity.RARE, mage.cards.b.BudokaGardener.class)); cards.add(new SetCardInfo("Centaur Vinecrasher", 135, Rarity.RARE, mage.cards.c.CentaurVinecrasher.class)); cards.add(new SetCardInfo("Chain Reaction", 121, Rarity.RARE, mage.cards.c.ChainReaction.class)); cards.add(new SetCardInfo("Chaos Warp", 122, Rarity.RARE, mage.cards.c.ChaosWarp.class)); cards.add(new SetCardInfo("Crash of Rhino Beetles", 29, Rarity.RARE, mage.cards.c.CrashOfRhinoBeetles.class)); + cards.add(new SetCardInfo("Dictate of Kruphix", 86, Rarity.RARE, mage.cards.d.DictateOfKruphix.class)); cards.add(new SetCardInfo("Echo Storm", 7, Rarity.RARE, mage.cards.e.EchoStorm.class)); + cards.add(new SetCardInfo("Eel Umbra", 89, Rarity.COMMON, mage.cards.e.EelUmbra.class)); cards.add(new SetCardInfo("Eidolon of Blossoms", 140, Rarity.RARE, mage.cards.e.EidolonOfBlossoms.class)); cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); + cards.add(new SetCardInfo("Enchantress's Presence", 141, Rarity.RARE, mage.cards.e.EnchantresssPresence.class)); cards.add(new SetCardInfo("Explosive Vegetation", 144, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); + cards.add(new SetCardInfo("Finest Hour", 180, Rarity.RARE, mage.cards.f.FinestHour.class)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); cards.add(new SetCardInfo("Fury Storm", 22, Rarity.RARE, mage.cards.f.FuryStorm.class)); + cards.add(new SetCardInfo("Hydra Omnivore", 153, Rarity.MYTHIC, mage.cards.h.HydraOmnivore.class)); cards.add(new SetCardInfo("Loyal Apprentice", 23, Rarity.UNCOMMON, mage.cards.l.LoyalApprentice.class)); cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); @@ -44,6 +51,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); cards.add(new SetCardInfo("Saheeli's Directive", 26, Rarity.RARE, mage.cards.s.SaheelisDirective.class)); cards.add(new SetCardInfo("Scute Mob", 161, Rarity.RARE, mage.cards.s.ScuteMob.class)); + cards.add(new SetCardInfo("Spawning Grounds", 163, Rarity.RARE, mage.cards.s.SpawningGrounds.class)); cards.add(new SetCardInfo("Tawnos, Urza's Apprentice", 45, Rarity.MYTHIC, mage.cards.t.TawnosUrzasApprentice.class)); cards.add(new SetCardInfo("Thantis the Warweaver", 46, Rarity.MYTHIC, mage.cards.t.ThantisTheWarweaver.class)); cards.add(new SetCardInfo("Thopter Spy Network", 107, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index d6e2279a4ac..9cdb0a32e5f 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33925,8 +33925,12 @@ Cleansing Screech|Global Series: Jiang Yanggu & Mu Yanling|37|C|{4}{R}|Sorcery|| Timber Gorge|Global Series: Jiang Yanggu & Mu Yanling|38|C||Land|||Timber Gorge enters the battlefield tapped.${T}: Add {R} or {G}.| Mountain|Global Series: Jiang Yanggu & Mu Yanling|39|C||Basic Land - Mountain|||({T}: Add {R}.)| Forest|Global Series: Jiang Yanggu & Mu Yanling|40|C||Basic Land - Forest|||({T}: Add {G}.)| +Empyrial Storm|Commander 2018|2|R|{4}{W}{W}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game.$Create a 4/4 white Angel creature token with flying.| +Heavenly Blademaster|Commander 2018|3|R|{5}{W}|Creature - Angel|3|6|Flying, double strike$When Heavenly Blademaster enters the battlefield, you may attach any number of Auras and Equipment you control to it.$Other creatures you control get +1/+1 for each Aura and Equipment attached to Heavenly Blademaster.| Echo Storm|Commander 2018|7|R|{3}{U}{U}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.$Create a token that's a copy of target artifact.| +Estrid's Invocation|Commander 2018|8|R|{2}{U}|Enchantment|||You may have Estrid's Invocation enter the battlefield as a copy of any enchantment you control, except it gains "At the beginning of your upkeep, you may exile this enchantment. If you do, return it to the battlefield under its owner's control."| Loyal Drake|Commander 2018|10|U|{2}{U}|Creature - Drake|2|2|Flying$Lieutenant — At the beginning of combat on your turn, if you control your commander, draw a card.| +Octopus Umbra|Commander 2018|11|R|{3}{U}{U}|Enchantment - Aura|||Enchant creature$Enchanted creature has base power and toughness 8/8 and has "Whenever this creature attacks, you may tap target creature with power 8 or less."$Totem armor| Vedalken Humiliator|Commander 2018|13|R|{3}{U}|Creature - Vedalken Wizard|3|4|Metalcraft — Whenever Vedalken Humiliator attacks, if you control three or more artifacts, creatures your opponents control lose all abilities and have base power and toughness 1/1 until end of turn.| Bloodtracker|Commander 2018|14|R|{3}{B}|Creature - Vampire Wizard|2|2|Flying${B}, Pay 2 life: Put a +1/+1 counter on Bloodtracker.$When Bloodtracker leaves the battlefield, draw a card for each +1/+1 counter on it.| Loyal Subordinate|Commander 2018|16|U|{2}{B}|Creature - Zombie|3|1|Menace$Lieutenant — At the beginning of combat on your turn, if you control your commander, each opponent loses 3 life.| @@ -33941,13 +33945,18 @@ Treasure Nabber|Commander 2018|27|R|{2}{R}|Creature - Goblin Rogue|3|2|Whenever Varchild, Betrayer of Kjeldor|Commander 2018|28|R|{2}{R}|Legendary Creature - Human Knight|3|3|Whenever Varchild, Betrayer of Kjeldor deals combat damage to a player, that player creates that many 1/1 red Survivor creature tokens.$Survivors your opponents control can't block, and they can't attack you or a planeswalker you control.$When Varchild leaves the battlefield, gain control of all Survivors.| Crash of Rhino Beetles|Commander 2018|29|R|{4}{G}|Creature - Insect|5|5|Trample$Crash of Rhino Beetles gets +10/+10 as long as you control ten or more lands.| Loyal Guardian|Commander 2018|31|U|{4}{G}|Creature - Rhino|4|4|Trample$Lieutenant — At the beginning of combat on your turn, if you control your commander, put a +1/+1 counter on each creature you control.| +Turntimber Sower|Commander 2018|35|R|{2}{G}|Creature - Elf Druid|3|3|Whenever one or more land cards are put into your graveyard from anywhere, create a 0/1 green Plant creature token.${G}, Sacrifice three creatures: Return target land card from your graveyard to your hand.| Whiptongue Hydra|Commander 2018|36|R|{5}{G}|Creature - Lizard Hydra|4|4|Reach$When Whiptongue Hydra enters the battlefield, destroy all creatures with flying. Put a +1/+1 counter on Whiptongue Hydra for each creature destroyed this way.| +Arixmethes, Slumbering Isle|Commander 2018|38|R|{2}{U}{G}|Legendary Creature - Kraken|12|12|Arixmethes, Slumbering Isle enters the battlefield tapped with five slumber counters on it.$As long as Arixmethes has a slumber counter on it, it's a land.$Whenever you cast a spell, you may remove a slumber counter from Arixmethes.${T}: Add {G}{U}.| Brudiclad, Telchor Engineer|Commander 2018|39|M|{4}{U}{R}|Legendary Artifact Creature - Artificer|4|4|Creature tokens you control have haste.$At the beginning of combat on your turn, create a 2/1 blue Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token.| +Estrid, the Masked|Commander 2018|40|M|{1}{W}{U}{G}|Legendary Planeswalker - Estrid|3|+2: Untap each enchanted permanent you control.$-1: Create a white Aura enchantment token named Mask attached to another target permanent. The token has enchantment permanent and totem armor.$-7: Put the top seven cards of your library into your graveyard. Return all non-Aura enchantment cards from your graveyard to the battlefield, then do the same for Aura cards.$Estrid, the Masked can be your commander.| Gyrus, Waker of Corpses|Commander 2018|41|M|{X}{B}{R}{G}|Legendary Creature - Hydra|0|0|Gyrus, Walker of Corpses enters the battlefield with a number of +1/+1 counters on it equal to the amount of mana spent to cast it.$Whenever Gyrus attacks, you may exile target creature card with lesser power from your graveyard. If you do, create a token that's a copy of that card and that's tapped and attacking. Exile the token at the end of combat.| +Kestia, the Cultivator|Commander 2018|42|M|{1}{W}{U}{G}|Legendary Enchantment Creature - Nymph|4|4|Bestow {3}{G}{W}{U}$Enchanted creature gets +4/+4.$Whenever an enchanted creature or enchantment creature you control attacks, draw a card.| Lord Windgrace|Commander 2018|43|M|{2}{B}{R}{G}|Legendary Planeswalker - Windgrace|5|+2: Discard a card, then draw a card. If a land card is discarded this way, draw an additional card.$-3: Return up to two target land cards from your graveyard to the battlefield.$-11: Destroy up to six target nonland permanents, then create six 2/2 green Cat Warrior creature tokens with forestwalk.$Lord Windgrace can be your commander.| Saheeli, the Gifted|Commander 2018|44|M|{2}{U}{R}|Legendary Planeswalker - Saheeli|4|+1: Create a 1/1 colorless Servo artifact creature token.$+1: The next spell you cast this turn costs {1} less to cast for each artifact you control as you cast it.$-7: For each artifact you control, create a token that's a copy of it. Those tokens gain haste. Exile those tokens at the beginning of the next end step.$Saheeli, the Gifted can be your commander.| Tawnos, Urza's Apprentice|Commander 2018|45|M|{U}{R}|Legendary Creature - Human Artificer|1|3|Haste${U}{R}, {T}: Copy target activated or triggered ability you control from an artifact source. You may choose new targets for the copy.| Thantis the Warweaver|Commander 2018|46|M|{3}{B}{R}{G}|Legendary Creature - Spider|5|5|Vigilance, reach$All creatures attack each combat if able.$Whenever a creature attacks you or a planeswalker you control, put a +1/+1 counter on Thantis the Warweaver.| +Tuvasa the Sunlit|Commander 2018|47|M|{W}{U}{G}|Legendary Creature - Merfolk Shaman|1|1|Tuvasa the Sunlit gets +1/+1 for each enchantment you control.$Whenever you case your first enchantment spell each turn, draw a card.| Windgrace's Judgment|Commander 2018|49|R|{3}{B}{G}|Instant|||For any number of opponents, destroy target nonland permanent that player controls.| Xantcha, Sleeper Agent|Commander 2018|50|R|{1}{B}{R}|Legendary Creature - Minion|5|5|As Xantcha, Sleeper Agent enters the battlefield, an opponent of your choice gains control of it.$Xantcha attacks each combat if able and can't attack its owner or planeswalkers its owner controls.${3}: Xantcha's controller loses 2 life and you draw a card. Any player may activate this ability.| Ancient Stone Idol|Commander 2018|53|R|{10}|Artifact Creature - Golem|12|12|Flash$This spell costs {1} less to cast for each attacking creature.$Trample$When Ancient Stone Idol dies, create a 6/12 colorless Construct artifact creature token with trample.| @@ -33956,14 +33965,22 @@ Endless Atlas|Commander 2018|55|R|{2}|Artifact|||{2}, {T}: Draw a card. Activate Geode Golem|Commander 2018|56|U|{5}|Artifact Creature - Golem|5|3|Trample$Whenever Geode Golem deals combat damage to a player, you may cast your commander from the command zone without paying its mana cost.| Retrofitter Foundry|Commander 2018|57|R|{1}|Artifact|||{3}: Untap Retrofitter Foundry.${2}, {T}: Create a 1/1 colorless Servo artifact creature token.${1}, {T}, Sacrifice a Servo: Create a 1/1 colorless Thopter artifact creature token with flying.${T}, Sacrifice a Thopter: Create a 4/4 colorless Construct artifact creature token.| Forge of Heroes|Commander 2018|58|C||Land|||{T}: Add {C}.${T}: Choose target commander that entered the battlefield this turn. Put a +1/+1 counter on it if it's a creature and a loyalty counter on it if it's a planeswalker.| +Dictate of Kruphix|Commander 2018|86|R|{1}{U}{U}|Enchantment|||Flash$At the beginning of each player's draw step, that player draws an additional card.| +Eel Umbra|Commander 2018|89|C|{1}{U}|Enchantment - Aura|||Flash| Thopter Spy Network|Commander 2018|107|R|{2}{U}{U}|Enchantment|||At the beginning of your upkeep, if you control an artifact, create a 1/1 colorless Thopter artifact creature token with flying.$Whenever one or more artifact creatures you control deal combat damage to a player, draw a card.| Ruinous Path|Commander 2018|117|R|{1}{B}{B}|Sorcery|||Destroy target creature or planeswalker.$Awaken 4—{5}{B}{B}| Chain Reaction|Commander 2018|121|R|{2}{R}{R}|Sorcery|||Chain Reaction deals X damage to each creature, where X is the number of creatures on the battlefield.| Chaos Warp|Commander 2018|122|R|{2}{R}|Instant|||The owner of target permanent shuffles it into their library, then reveals the top card of their library. If it's a permanent card, they put it onto the battlefield.| Avenger of Zendikar|Commander 2018|129|M|{5}{G}{G}|Creature - Elemental|5|5|When Avenger of Zendikar enters the battlefield, create a 0/1 green Plant creature token for each land you control.$Landfall — Whenever a land enters the battlefield under your control, you may put a +1/+1 counter on each Plant creature you control.| +Bear Umbra|Commander 2018|131|R|{2}{G}{G}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +2/+2 and has "Whenever this creature attacks, untap all lands you control."$Totem armor| Budoka Gardener|Commander 2018|134|R|{1}{G}|Creature - Human Monk|2|1|{T}: You may put a land card from your hand onto the battlefield. If you control ten or more lands, flip Budoka Gardener.| Centaur Vinecrasher|Commander 2018|135|R|{3}{G}|Creature - Plant Centaur|1|1|Trample$Centaur Vinecrasher enters the battlefield with a number of +1/+1 counters on it equal to the number of land cards in all graveyards.$Whenever a land card is put into a graveyard from anywhere, you may pay {G}{G}. If you do, return Centaur Vinecrasher from your graveyard to your hand.| Eidolon of Blossoms|Commander 2018|140|R|{2}{G}{G}|Enchantment Creature - Spirit|2|2|Constellation — Whenever Eidolon of Blossoms or another enchantment enters the battlefield under your control, draw a card.| +Enchantress's Presence|Commander 2018|141|R|{2}{G}|Enchantment|||Whenever you cast an enchantment spell, draw a card.| Explosive Vegetation|Commander 2018|144|U|{3}{G}|Sorcery|||Search your library for up to two basic land cards and put them onto the battlefield tapped. Then shuffle your library.| +Hydra Omnivore|Commander 2018|153|M|{4}{G}{G}|Creature - Hydra|8|8|Whenever Hydra Omnivore deals combat damage to an opponent, it deals that much damage to each other opponent.| Rampaging Baloths|Commander 2018|158|R|{4}{G}{G}|Creature - Beast|6|6|Trample$Landfall — Whenever a land enters the battlefield under your control, you may create a 4/4 green Beast creature token.| -Scute Mob|Commander 2018|161|R|{G}|Creature - Insect|1|1|At the beginning of your upkeep, if you control five or more lands, put four +1/+1 counters on Scute Mob.| \ No newline at end of file +Scute Mob|Commander 2018|161|R|{G}|Creature - Insect|1|1|At the beginning of your upkeep, if you control five or more lands, put four +1/+1 counters on Scute Mob.| +Spawning Grounds|Commander 2018|163|R|{6}{G}{G}|Enchantment - Aura|||Enchant land$Enchanted land has "{T}: Create a 5/5 green Beast creature token with trample."| +Bruna, Light of Alabaster|Commander 2018|170|M|{3}{W}{W}{U}|Legendary Creature - Angel|5|5|Flying, vigilance$Whenever Bruna, Light of Alabaster attacks or blocks, you may attach to it any number of Auras on the battlefield and you may put onto the battlefield attached to it any number of Aura cards that could enchant it from your graveyard and/or hand.| +Finest Hour|Commander 2018|180|R|{2}{G}{W}{U}|Enchantment|||Exalted$Whenever a creature you control attacks alone, if it's the first combat phase of the turn, untap that creature. After this phase, there is an additional combat phase.| \ No newline at end of file From b3786358c7be04de354be22f6ba1034f2ec16be4 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 25 Jul 2018 12:18:37 -0400 Subject: [PATCH 20/71] Implemented Empyrial Storm --- Mage.Sets/src/mage/cards/e/EmpyrialStorm.java | 35 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 36 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EmpyrialStorm.java diff --git a/Mage.Sets/src/mage/cards/e/EmpyrialStorm.java b/Mage.Sets/src/mage/cards/e/EmpyrialStorm.java new file mode 100644 index 00000000000..1b96845f052 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EmpyrialStorm.java @@ -0,0 +1,35 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.CommanderStormAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.AngelToken; + +/** + * + * @author TheElk801 + */ +public final class EmpyrialStorm extends CardImpl { + + public EmpyrialStorm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}{W}"); + + // When you cast this spell, copy it for each time you've cast your commander from the command zone this game. + this.addAbility(new CommanderStormAbility()); + + // Create a 4/4 white Angel creature token with flying. + this.getSpellAbility().addEffect(new CreateTokenEffect(new AngelToken())); + } + + public EmpyrialStorm(final EmpyrialStorm card) { + super(card); + } + + @Override + public EmpyrialStorm copy() { + return new EmpyrialStorm(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 2657b5ec4a8..ff6c88e1d94 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -34,6 +34,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Echo Storm", 7, Rarity.RARE, mage.cards.e.EchoStorm.class)); cards.add(new SetCardInfo("Eel Umbra", 89, Rarity.COMMON, mage.cards.e.EelUmbra.class)); cards.add(new SetCardInfo("Eidolon of Blossoms", 140, Rarity.RARE, mage.cards.e.EidolonOfBlossoms.class)); + cards.add(new SetCardInfo("Empyrial Storm", 2, Rarity.RARE, mage.cards.e.EmpyrialStorm.class)); cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); cards.add(new SetCardInfo("Enchantress's Presence", 141, Rarity.RARE, mage.cards.e.EnchantresssPresence.class)); cards.add(new SetCardInfo("Explosive Vegetation", 144, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); From 7c6dfe3e566617e16388a396d9ca919f632f9146 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 25 Jul 2018 12:39:06 -0400 Subject: [PATCH 21/71] Implemented Octopus Umbra --- Mage.Sets/src/mage/cards/o/OctopusUmbra.java | 76 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + .../SetPowerToughnessEnchantedEffect.java | 18 ++++- 3 files changed, 91 insertions(+), 4 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/o/OctopusUmbra.java diff --git a/Mage.Sets/src/mage/cards/o/OctopusUmbra.java b/Mage.Sets/src/mage/cards/o/OctopusUmbra.java new file mode 100644 index 00000000000..148586f6fc1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OctopusUmbra.java @@ -0,0 +1,76 @@ +package mage.cards.o; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessEnchantedEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.TotemArmorAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; + +/** + * + * @author TheElk801 + */ +public final class OctopusUmbra extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power 8 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 9)); + } + + public OctopusUmbra(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature has base power and toughness 8/8 and has "Whenever this creature attacks, you may tap target creature with power 8 or less." + Ability abilityToAdd = new AttacksTriggeredAbility(new TapTargetEffect(), true); + abilityToAdd.addTarget(new TargetCreaturePermanent(filter)); + ability = new SimpleStaticAbility( + Zone.BATTLEFIELD, + new SetPowerToughnessEnchantedEffect(8, 8) + ); + ability.addEffect(new GainAbilityAttachedEffect( + abilityToAdd, AttachmentType.AURA + ).setText("and has \"Whenever this creature attacks, " + + "you may tap target creature with power 8 or less.\"")); + this.addAbility(ability); + + // Totem armor + this.addAbility(new TotemArmorAbility()); + + } + + public OctopusUmbra(final OctopusUmbra card) { + super(card); + } + + @Override + public OctopusUmbra copy() { + return new OctopusUmbra(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index ff6c88e1d94..a1aaea2765b 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -47,6 +47,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); cards.add(new SetCardInfo("Nesting Dragon", 24, Rarity.RARE, mage.cards.n.NestingDragon.class)); + cards.add(new SetCardInfo("Octopus Umbra", 11, Rarity.RARE, mage.cards.o.OctopusUmbra.class)); cards.add(new SetCardInfo("Rampaging Baloths", 158, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessEnchantedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessEnchantedEffect.java index e33d30a36da..a5f1cf72e30 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessEnchantedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetPowerToughnessEnchantedEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; @@ -16,13 +15,24 @@ import mage.game.permanent.Permanent; */ public class SetPowerToughnessEnchantedEffect extends ContinuousEffectImpl { + private final int power; + private final int toughness; + public SetPowerToughnessEnchantedEffect() { + this(0, 2); + } + + public SetPowerToughnessEnchantedEffect(int power, int toughness) { super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.SetPT_7b, Outcome.BoostCreature); - staticText = "Enchanted creature has base power and toughness 0/2"; + staticText = "Enchanted creature has base power and toughness " + power + "/" + toughness; + this.power = power; + this.toughness = toughness; } public SetPowerToughnessEnchantedEffect(final SetPowerToughnessEnchantedEffect effect) { super(effect); + this.power = effect.power; + this.toughness = effect.toughness; } @Override @@ -36,8 +46,8 @@ public class SetPowerToughnessEnchantedEffect extends ContinuousEffectImpl { if (enchantment != null && enchantment.getAttachedTo() != null) { Permanent enchanted = game.getPermanent(enchantment.getAttachedTo()); if (enchanted != null) { - enchanted.getPower().setValue(0); - enchanted.getToughness().setValue(2); + enchanted.getPower().setValue(power); + enchanted.getToughness().setValue(toughness); } return true; } From 91244c09dc5782d44cbcabdf5c6b44c876bcf2a1 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 25 Jul 2018 12:58:19 -0400 Subject: [PATCH 22/71] Implemented Kestia, the Cultivator --- .../src/mage/cards/k/KestiaTheCultivator.java | 74 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + .../common/AttacksAllTriggeredAbility.java | 6 +- 3 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/k/KestiaTheCultivator.java diff --git a/Mage.Sets/src/mage/cards/k/KestiaTheCultivator.java b/Mage.Sets/src/mage/cards/k/KestiaTheCultivator.java new file mode 100644 index 00000000000..18f4dfcdc3b --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KestiaTheCultivator.java @@ -0,0 +1,74 @@ +package mage.cards.k; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.AttacksAllTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.abilities.keyword.BestowAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SetTargetPointer; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.EnchantedPredicate; + +/** + * + * @author TheElk801 + */ +public final class KestiaTheCultivator extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("an enchanted creature or enchantment creature you control"); + + static { + filter.add(Predicates.or( + new EnchantedPredicate(), + new CardTypePredicate(CardType.ENCHANTMENT) + )); + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public KestiaTheCultivator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{1}{G}{W}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.NYMPH); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Bestow {3}{G}{W}{U} + this.addAbility(new BestowAbility(this, "{3}{G}{W}{U}")); + + // Enchanted creature gets +4/+4. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new BoostEnchantedEffect(4, 4, Duration.WhileOnBattlefield) + )); + + // Whenever an enchanted creature or enchantment creature you control attacks, draw a card. + this.addAbility(new AttacksAllTriggeredAbility( + new DrawCardSourceControllerEffect(1), + false, filter, SetTargetPointer.NONE, false + )); + } + + public KestiaTheCultivator(final KestiaTheCultivator card) { + super(card); + } + + @Override + public KestiaTheCultivator copy() { + return new KestiaTheCultivator(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index a1aaea2765b..269aaef7be6 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -42,6 +42,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); cards.add(new SetCardInfo("Fury Storm", 22, Rarity.RARE, mage.cards.f.FuryStorm.class)); cards.add(new SetCardInfo("Hydra Omnivore", 153, Rarity.MYTHIC, mage.cards.h.HydraOmnivore.class)); + cards.add(new SetCardInfo("Kestia, the Cultivator", 42, Rarity.MYTHIC, mage.cards.k.KestiaTheCultivator.class)); cards.add(new SetCardInfo("Loyal Apprentice", 23, Rarity.UNCOMMON, mage.cards.l.LoyalApprentice.class)); cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); diff --git a/Mage/src/main/java/mage/abilities/common/AttacksAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/AttacksAllTriggeredAbility.java index 3b47bc1c16f..c290a39cc2e 100644 --- a/Mage/src/main/java/mage/abilities/common/AttacksAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/AttacksAllTriggeredAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.common; import java.util.UUID; @@ -102,7 +101,10 @@ public class AttacksAllTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a " + filter.getMessage() + " attacks" + (attacksYouOrYourPlaneswalker ? " you or a planeswalker you control" : "") + ", " + super.getRule(); + return "Whenever " + (filter.getMessage().startsWith("an") ? "" : "a ") + + filter.getMessage() + " attacks" + + (attacksYouOrYourPlaneswalker ? " you or a planeswalker you control" : "") + + ", " + super.getRule(); } } From 2a6181b67a9ab42ab8a344977082b4ed2d061883 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 25 Jul 2018 15:45:56 -0400 Subject: [PATCH 23/71] Implemeted Lord Windgrace --- Mage.Sets/src/mage/cards/l/LordWindgrace.java | 112 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + .../src/main/java/mage/constants/SubType.java | 1 + 3 files changed, 114 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/l/LordWindgrace.java diff --git a/Mage.Sets/src/mage/cards/l/LordWindgrace.java b/Mage.Sets/src/mage/cards/l/LordWindgrace.java new file mode 100644 index 00000000000..3cbd21e70f2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LordWindgrace.java @@ -0,0 +1,112 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.CanBeYourCommanderAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.Card; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.common.FilterLandCard; +import mage.filter.predicate.other.OwnerPredicate; +import mage.game.Game; +import mage.game.permanent.token.CatWarriorToken; +import mage.players.Player; +import mage.target.common.TargetCardInASingleGraveyard; +import mage.target.common.TargetNonlandPermanent; + +/** + * + * @author TheElk801 + */ +public final class LordWindgrace extends CardImpl { + + private static final FilterLandCard filter = new FilterLandCard("land cards from your graveyard"); + + static { + filter.add(new OwnerPredicate(TargetController.YOU)); + } + + public LordWindgrace(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{B}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.WINDGRACE); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(5)); + + // +2: Discard a card, then draw a card. If a land card is discarded this way, draw an additional card. + this.addAbility(new LoyaltyAbility(new LordWindgraceEffect(), 2)); + + // -3: Return up to two target land cards from your graveyard to the battlefield. + Ability ability = new LoyaltyAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), -3 + ); + ability.addTarget(new TargetCardInASingleGraveyard(0, 2, filter)); + this.addAbility(ability); + + // -11: Destroy up to six target nonland permanents, then create six 2/2 green Cat Warrior creature tokens with forestwalk. + ability = new LoyaltyAbility(new DestroyTargetEffect(), -11); + ability.addEffect( + new CreateTokenEffect(new CatWarriorToken(), 6) + .setText(", then create six 2/2 green Cat Warrior " + + "creature tokens with forestwalk") + ); + ability.addTarget(new TargetNonlandPermanent(0, 6, false)); + this.addAbility(ability); + + // Lord Windgrace can be your commander. + this.addAbility(CanBeYourCommanderAbility.getInstance()); + } + + public LordWindgrace(final LordWindgrace card) { + super(card); + } + + @Override + public LordWindgrace copy() { + return new LordWindgrace(this); + } +} + +class LordWindgraceEffect extends OneShotEffect { + + public LordWindgraceEffect() { + super(Outcome.Benefit); + this.staticText = "discard a card, then draw a card. " + + "If a land card is discarded this way, draw an additional card"; + } + + public LordWindgraceEffect(final LordWindgraceEffect effect) { + super(effect); + } + + @Override + public LordWindgraceEffect copy() { + return new LordWindgraceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = player.discardOne(false, source, game); + if (card == null || !card.isLand()) { + player.drawCards(1, game); + } else { + player.drawCards(2, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 269aaef7be6..85ec95a3b0f 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -43,6 +43,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Fury Storm", 22, Rarity.RARE, mage.cards.f.FuryStorm.class)); cards.add(new SetCardInfo("Hydra Omnivore", 153, Rarity.MYTHIC, mage.cards.h.HydraOmnivore.class)); cards.add(new SetCardInfo("Kestia, the Cultivator", 42, Rarity.MYTHIC, mage.cards.k.KestiaTheCultivator.class)); + cards.add(new SetCardInfo("Lord Windgrace", 43, Rarity.MYTHIC, mage.cards.l.LordWindgrace.class)); cards.add(new SetCardInfo("Loyal Apprentice", 23, Rarity.UNCOMMON, mage.cards.l.LoyalApprentice.class)); cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); diff --git a/Mage/src/main/java/mage/constants/SubType.java b/Mage/src/main/java/mage/constants/SubType.java index cb533251485..49ca306dd6b 100644 --- a/Mage/src/main/java/mage/constants/SubType.java +++ b/Mage/src/main/java/mage/constants/SubType.java @@ -406,6 +406,7 @@ public enum SubType { VIVIEN("Vivien", SubTypeSet.PlaneswalkerType), VRASKA("Vraska", SubTypeSet.PlaneswalkerType), WILL("Will", SubTypeSet.PlaneswalkerType), + WINDGRACE("Windgrace", SubTypeSet.PlaneswalkerType), XENAGOS("Xenagos", SubTypeSet.PlaneswalkerType), YANGGU("Yanggu", SubTypeSet.PlaneswalkerType), YANLING("Yanling", SubTypeSet.PlaneswalkerType), From ea2842cd234531040079cd2cfba75739ec7da88c Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 25 Jul 2018 16:45:57 -0400 Subject: [PATCH 24/71] Implemented Tuvasa the Sunlit --- .../src/mage/cards/t/TuvasaTheSunlit.java | 153 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 154 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TuvasaTheSunlit.java diff --git a/Mage.Sets/src/mage/cards/t/TuvasaTheSunlit.java b/Mage.Sets/src/mage/cards/t/TuvasaTheSunlit.java new file mode 100644 index 00000000000..7cb517ce679 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TuvasaTheSunlit.java @@ -0,0 +1,153 @@ +package mage.cards.t; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.FilterSpell; +import mage.filter.common.FilterEnchantmentPermanent; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.watchers.Watcher; + +/** + * + * @author TheElk801 + */ +public final class TuvasaTheSunlit extends CardImpl { + + private static final FilterEnchantmentPermanent filter + = new FilterEnchantmentPermanent("enchantment you control"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public TuvasaTheSunlit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Tuvasa the Sunlit gets +1/+1 for each enchantment you control. + DynamicValue value + = new PermanentsOnBattlefieldCount(new FilterPermanent(filter)); + Ability ability = new SimpleStaticAbility( + Zone.BATTLEFIELD, + new BoostSourceEffect( + value, value, Duration.WhileOnBattlefield + ).setText("{this} gets +1/+1 for each enchantment you control") + ); + this.addAbility(ability); + + // Whenever you cast your first enchantment spell each turn, draw a card. + this.addAbility( + new TuvasaTheSunlitTriggeredAbility(), + new TuvasaTheSunlitWatcher() + ); + } + + public TuvasaTheSunlit(final TuvasaTheSunlit card) { + super(card); + } + + @Override + public TuvasaTheSunlit copy() { + return new TuvasaTheSunlit(this); + } +} + +class TuvasaTheSunlitTriggeredAbility extends SpellCastControllerTriggeredAbility { + + private static final FilterSpell filter + = new FilterSpell("an enchantment spell"); + + static { + filter.add(new CardTypePredicate(CardType.ENCHANTMENT)); + } + + public TuvasaTheSunlitTriggeredAbility() { + super(new DrawCardSourceControllerEffect(1), filter, false); + this.rule = "Whenever you cast your first enchantment spell each turn, draw a card."; + } + + public TuvasaTheSunlitTriggeredAbility(final TuvasaTheSunlitTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!super.checkTrigger(event, game)) { + return false; + } + TuvasaTheSunlitWatcher watcher = (TuvasaTheSunlitWatcher) game.getState().getWatchers().get(TuvasaTheSunlitWatcher.class.getSimpleName()); + MageObjectReference mor = watcher.getFirstEnchantmentThisTurn(this.getControllerId()); + return mor == null || mor.refersTo(event.getTargetId(), game); + } + +} + +class TuvasaTheSunlitWatcher extends Watcher { + + private final Map firstEnchantmentThisTurn = new HashMap(); + + public TuvasaTheSunlitWatcher() { + super(TuvasaTheSunlitWatcher.class.getSimpleName(), WatcherScope.GAME); + } + + public TuvasaTheSunlitWatcher(final TuvasaTheSunlitWatcher watcher) { + super(watcher); + this.firstEnchantmentThisTurn.putAll(watcher.firstEnchantmentThisTurn); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.SPELL_CAST) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && spell.isEnchantment()) { + firstEnchantmentThisTurn.putIfAbsent( + event.getPlayerId(), + new MageObjectReference(spell, game) + ); + } + } + } + + @Override + public void reset() { + firstEnchantmentThisTurn.clear(); + } + + public MageObjectReference getFirstEnchantmentThisTurn(UUID playerId) { + return firstEnchantmentThisTurn.get(playerId); + } + + @Override + public Watcher copy() { + return new TuvasaTheSunlitWatcher(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 85ec95a3b0f..1c20c9f0419 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -59,6 +59,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Tawnos, Urza's Apprentice", 45, Rarity.MYTHIC, mage.cards.t.TawnosUrzasApprentice.class)); cards.add(new SetCardInfo("Thantis the Warweaver", 46, Rarity.MYTHIC, mage.cards.t.ThantisTheWarweaver.class)); cards.add(new SetCardInfo("Thopter Spy Network", 107, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class)); + cards.add(new SetCardInfo("Tuvasa the Sunlit", 47, Rarity.MYTHIC, mage.cards.t.TuvasaTheSunlit.class)); cards.add(new SetCardInfo("Varchild, Betrayer of Kjeldor", 28, Rarity.RARE, mage.cards.v.VarchildBetrayerOfKjeldor.class)); cards.add(new SetCardInfo("Whiptongue Hydra", 36, Rarity.RARE, mage.cards.w.WhiptongueHydra.class)); } From dc5b6f09f83d64bedfaadb294dfef907ae724284 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 25 Jul 2018 16:53:42 -0400 Subject: [PATCH 25/71] updated C18 spoiler --- Mage.Sets/src/mage/sets/Commander2018.java | 1 + Utils/mtg-cards-data.txt | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 1c20c9f0419..87a7184acdb 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -62,5 +62,6 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Tuvasa the Sunlit", 47, Rarity.MYTHIC, mage.cards.t.TuvasaTheSunlit.class)); cards.add(new SetCardInfo("Varchild, Betrayer of Kjeldor", 28, Rarity.RARE, mage.cards.v.VarchildBetrayerOfKjeldor.class)); cards.add(new SetCardInfo("Whiptongue Hydra", 36, Rarity.RARE, mage.cards.w.WhiptongueHydra.class)); + cards.add(new SetCardInfo("Winds of Rath", 79, Rarity.RARE, mage.cards.w.WindsOfRath.class)); } } diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 9cdb0a32e5f..5457be5e4c2 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33945,18 +33945,19 @@ Treasure Nabber|Commander 2018|27|R|{2}{R}|Creature - Goblin Rogue|3|2|Whenever Varchild, Betrayer of Kjeldor|Commander 2018|28|R|{2}{R}|Legendary Creature - Human Knight|3|3|Whenever Varchild, Betrayer of Kjeldor deals combat damage to a player, that player creates that many 1/1 red Survivor creature tokens.$Survivors your opponents control can't block, and they can't attack you or a planeswalker you control.$When Varchild leaves the battlefield, gain control of all Survivors.| Crash of Rhino Beetles|Commander 2018|29|R|{4}{G}|Creature - Insect|5|5|Trample$Crash of Rhino Beetles gets +10/+10 as long as you control ten or more lands.| Loyal Guardian|Commander 2018|31|U|{4}{G}|Creature - Rhino|4|4|Trample$Lieutenant — At the beginning of combat on your turn, if you control your commander, put a +1/+1 counter on each creature you control.| +Myth Unbound|Commander 2018|32|R|{2}{G}|Enchantment|||Your commander costs {1} less to cast for each time it's been cast from the command zone this game.$Whenever your commander is put into the command zone from anywhere, draw a card.| Turntimber Sower|Commander 2018|35|R|{2}{G}|Creature - Elf Druid|3|3|Whenever one or more land cards are put into your graveyard from anywhere, create a 0/1 green Plant creature token.${G}, Sacrifice three creatures: Return target land card from your graveyard to your hand.| Whiptongue Hydra|Commander 2018|36|R|{5}{G}|Creature - Lizard Hydra|4|4|Reach$When Whiptongue Hydra enters the battlefield, destroy all creatures with flying. Put a +1/+1 counter on Whiptongue Hydra for each creature destroyed this way.| -Arixmethes, Slumbering Isle|Commander 2018|38|R|{2}{U}{G}|Legendary Creature - Kraken|12|12|Arixmethes, Slumbering Isle enters the battlefield tapped with five slumber counters on it.$As long as Arixmethes has a slumber counter on it, it's a land.$Whenever you cast a spell, you may remove a slumber counter from Arixmethes.${T}: Add {G}{U}.| +Arixmethes, Slumbering Isle|Commander 2018|38|R|{2}{G}{U}|Legendary Creature - Kraken|12|12|Arixmethes, Slumbering Isle enters the battlefield tapped with five slumber counters on it.$As long as Arixmethes has a slumber counter on it, it's a land.$Whenever you cast a spell, you may remove a slumber counter from Arixmethes.${T}: Add {G}{U}.| Brudiclad, Telchor Engineer|Commander 2018|39|M|{4}{U}{R}|Legendary Artifact Creature - Artificer|4|4|Creature tokens you control have haste.$At the beginning of combat on your turn, create a 2/1 blue Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token.| -Estrid, the Masked|Commander 2018|40|M|{1}{W}{U}{G}|Legendary Planeswalker - Estrid|3|+2: Untap each enchanted permanent you control.$-1: Create a white Aura enchantment token named Mask attached to another target permanent. The token has enchantment permanent and totem armor.$-7: Put the top seven cards of your library into your graveyard. Return all non-Aura enchantment cards from your graveyard to the battlefield, then do the same for Aura cards.$Estrid, the Masked can be your commander.| +Estrid, the Masked|Commander 2018|40|M|{1}{G}{W}{U}|Legendary Planeswalker - Estrid|3|+2: Untap each enchanted permanent you control.$-1: Create a white Aura enchantment token named Mask attached to another target permanent. The token has enchant permanent and totem armor.$-7: Put the top seven cards of your library into your graveyard. Return all non-Aura enchantment cards from your graveyard to the battlefield, then do the same for Aura cards.$Estrid, the Masked can be your commander.| Gyrus, Waker of Corpses|Commander 2018|41|M|{X}{B}{R}{G}|Legendary Creature - Hydra|0|0|Gyrus, Walker of Corpses enters the battlefield with a number of +1/+1 counters on it equal to the amount of mana spent to cast it.$Whenever Gyrus attacks, you may exile target creature card with lesser power from your graveyard. If you do, create a token that's a copy of that card and that's tapped and attacking. Exile the token at the end of combat.| -Kestia, the Cultivator|Commander 2018|42|M|{1}{W}{U}{G}|Legendary Enchantment Creature - Nymph|4|4|Bestow {3}{G}{W}{U}$Enchanted creature gets +4/+4.$Whenever an enchanted creature or enchantment creature you control attacks, draw a card.| +Kestia, the Cultivator|Commander 2018|42|M|{1}{G}{W}{U}|Legendary Enchantment Creature - Nymph|4|4|Bestow {3}{G}{W}{U}$Enchanted creature gets +4/+4.$Whenever an enchanted creature or enchantment creature you control attacks, draw a card.| Lord Windgrace|Commander 2018|43|M|{2}{B}{R}{G}|Legendary Planeswalker - Windgrace|5|+2: Discard a card, then draw a card. If a land card is discarded this way, draw an additional card.$-3: Return up to two target land cards from your graveyard to the battlefield.$-11: Destroy up to six target nonland permanents, then create six 2/2 green Cat Warrior creature tokens with forestwalk.$Lord Windgrace can be your commander.| Saheeli, the Gifted|Commander 2018|44|M|{2}{U}{R}|Legendary Planeswalker - Saheeli|4|+1: Create a 1/1 colorless Servo artifact creature token.$+1: The next spell you cast this turn costs {1} less to cast for each artifact you control as you cast it.$-7: For each artifact you control, create a token that's a copy of it. Those tokens gain haste. Exile those tokens at the beginning of the next end step.$Saheeli, the Gifted can be your commander.| Tawnos, Urza's Apprentice|Commander 2018|45|M|{U}{R}|Legendary Creature - Human Artificer|1|3|Haste${U}{R}, {T}: Copy target activated or triggered ability you control from an artifact source. You may choose new targets for the copy.| Thantis the Warweaver|Commander 2018|46|M|{3}{B}{R}{G}|Legendary Creature - Spider|5|5|Vigilance, reach$All creatures attack each combat if able.$Whenever a creature attacks you or a planeswalker you control, put a +1/+1 counter on Thantis the Warweaver.| -Tuvasa the Sunlit|Commander 2018|47|M|{W}{U}{G}|Legendary Creature - Merfolk Shaman|1|1|Tuvasa the Sunlit gets +1/+1 for each enchantment you control.$Whenever you case your first enchantment spell each turn, draw a card.| +Tuvasa the Sunlit|Commander 2018|47|M|{G}{W}{U}|Legendary Creature - Merfolk Shaman|1|1|Tuvasa the Sunlit gets +1/+1 for each enchantment you control.$Whenever you cast your first enchantment spell each turn, draw a card.| Windgrace's Judgment|Commander 2018|49|R|{3}{B}{G}|Instant|||For any number of opponents, destroy target nonland permanent that player controls.| Xantcha, Sleeper Agent|Commander 2018|50|R|{1}{B}{R}|Legendary Creature - Minion|5|5|As Xantcha, Sleeper Agent enters the battlefield, an opponent of your choice gains control of it.$Xantcha attacks each combat if able and can't attack its owner or planeswalkers its owner controls.${3}: Xantcha's controller loses 2 life and you draw a card. Any player may activate this ability.| Ancient Stone Idol|Commander 2018|53|R|{10}|Artifact Creature - Golem|12|12|Flash$This spell costs {1} less to cast for each attacking creature.$Trample$When Ancient Stone Idol dies, create a 6/12 colorless Construct artifact creature token with trample.| @@ -33965,6 +33966,7 @@ Endless Atlas|Commander 2018|55|R|{2}|Artifact|||{2}, {T}: Draw a card. Activate Geode Golem|Commander 2018|56|U|{5}|Artifact Creature - Golem|5|3|Trample$Whenever Geode Golem deals combat damage to a player, you may cast your commander from the command zone without paying its mana cost.| Retrofitter Foundry|Commander 2018|57|R|{1}|Artifact|||{3}: Untap Retrofitter Foundry.${2}, {T}: Create a 1/1 colorless Servo artifact creature token.${1}, {T}, Sacrifice a Servo: Create a 1/1 colorless Thopter artifact creature token with flying.${T}, Sacrifice a Thopter: Create a 4/4 colorless Construct artifact creature token.| Forge of Heroes|Commander 2018|58|C||Land|||{T}: Add {C}.${T}: Choose target commander that entered the battlefield this turn. Put a +1/+1 counter on it if it's a creature and a loyalty counter on it if it's a planeswalker.| +Winds of Rath|Commander 2018|79|R|{3}{W}{W}|Sorcery|||Destroy all creatures that aren't enchanted. They can't be regenerated.| Dictate of Kruphix|Commander 2018|86|R|{1}{U}{U}|Enchantment|||Flash$At the beginning of each player's draw step, that player draws an additional card.| Eel Umbra|Commander 2018|89|C|{1}{U}|Enchantment - Aura|||Flash| Thopter Spy Network|Commander 2018|107|R|{2}{U}{U}|Enchantment|||At the beginning of your upkeep, if you control an artifact, create a 1/1 colorless Thopter artifact creature token with flying.$Whenever one or more artifact creatures you control deal combat damage to a player, draw a card.| From b0598f5365c3a35190a76577d666ef68fdb0e93e Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 25 Jul 2018 17:20:15 -0400 Subject: [PATCH 26/71] updated C18 spoiler --- Mage.Sets/src/mage/sets/Commander2018.java | 2 ++ Utils/mtg-cards-data.txt | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 87a7184acdb..87154272151 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -41,6 +41,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Finest Hour", 180, Rarity.RARE, mage.cards.f.FinestHour.class)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); cards.add(new SetCardInfo("Fury Storm", 22, Rarity.RARE, mage.cards.f.FuryStorm.class)); + cards.add(new SetCardInfo("Herald of the Pantheon", 151, Rarity.RARE, mage.cards.h.HeraldOfThePantheon.class)); cards.add(new SetCardInfo("Hydra Omnivore", 153, Rarity.MYTHIC, mage.cards.h.HydraOmnivore.class)); cards.add(new SetCardInfo("Kestia, the Cultivator", 42, Rarity.MYTHIC, mage.cards.k.KestiaTheCultivator.class)); cards.add(new SetCardInfo("Lord Windgrace", 43, Rarity.MYTHIC, mage.cards.l.LordWindgrace.class)); @@ -55,6 +56,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); cards.add(new SetCardInfo("Saheeli's Directive", 26, Rarity.RARE, mage.cards.s.SaheelisDirective.class)); cards.add(new SetCardInfo("Scute Mob", 161, Rarity.RARE, mage.cards.s.ScuteMob.class)); + cards.add(new SetCardInfo("Sigil of the Empty Throne", 74, Rarity.RARE, mage.cards.s.SigilOfTheEmptyThrone.class)); cards.add(new SetCardInfo("Spawning Grounds", 163, Rarity.RARE, mage.cards.s.SpawningGrounds.class)); cards.add(new SetCardInfo("Tawnos, Urza's Apprentice", 45, Rarity.MYTHIC, mage.cards.t.TawnosUrzasApprentice.class)); cards.add(new SetCardInfo("Thantis the Warweaver", 46, Rarity.MYTHIC, mage.cards.t.ThantisTheWarweaver.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 5457be5e4c2..e83e2328ab9 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33946,6 +33946,8 @@ Varchild, Betrayer of Kjeldor|Commander 2018|28|R|{2}{R}|Legendary Creature - Hu Crash of Rhino Beetles|Commander 2018|29|R|{4}{G}|Creature - Insect|5|5|Trample$Crash of Rhino Beetles gets +10/+10 as long as you control ten or more lands.| Loyal Guardian|Commander 2018|31|U|{4}{G}|Creature - Rhino|4|4|Trample$Lieutenant — At the beginning of combat on your turn, if you control your commander, put a +1/+1 counter on each creature you control.| Myth Unbound|Commander 2018|32|R|{2}{G}|Enchantment|||Your commander costs {1} less to cast for each time it's been cast from the command zone this game.$Whenever your commander is put into the command zone from anywhere, draw a card.| +Nylea's Colossus|Commander 2018|33|C|{6}{G}|Enchantment Creature - Giant|6|6|Constellation — Whenever Nylea's Colossus or another enchantment enters the battlefield under your control, double target creature's power and toughness until end of turn.| +Ravenous Slime|Commander 2018|34|R|{2}{G}|Creature - Ooze|1|1|Ravenous Slime can't be blocked by creatures with power 2 or less.$If a creature an opponent controls would die, instead exile it and put a number of +1/+1 counters equal to that creature's power on Ravenous Slime.| Turntimber Sower|Commander 2018|35|R|{2}{G}|Creature - Elf Druid|3|3|Whenever one or more land cards are put into your graveyard from anywhere, create a 0/1 green Plant creature token.${G}, Sacrifice three creatures: Return target land card from your graveyard to your hand.| Whiptongue Hydra|Commander 2018|36|R|{5}{G}|Creature - Lizard Hydra|4|4|Reach$When Whiptongue Hydra enters the battlefield, destroy all creatures with flying. Put a +1/+1 counter on Whiptongue Hydra for each creature destroyed this way.| Arixmethes, Slumbering Isle|Commander 2018|38|R|{2}{G}{U}|Legendary Creature - Kraken|12|12|Arixmethes, Slumbering Isle enters the battlefield tapped with five slumber counters on it.$As long as Arixmethes has a slumber counter on it, it's a land.$Whenever you cast a spell, you may remove a slumber counter from Arixmethes.${T}: Add {G}{U}.| @@ -33966,6 +33968,7 @@ Endless Atlas|Commander 2018|55|R|{2}|Artifact|||{2}, {T}: Draw a card. Activate Geode Golem|Commander 2018|56|U|{5}|Artifact Creature - Golem|5|3|Trample$Whenever Geode Golem deals combat damage to a player, you may cast your commander from the command zone without paying its mana cost.| Retrofitter Foundry|Commander 2018|57|R|{1}|Artifact|||{3}: Untap Retrofitter Foundry.${2}, {T}: Create a 1/1 colorless Servo artifact creature token.${1}, {T}, Sacrifice a Servo: Create a 1/1 colorless Thopter artifact creature token with flying.${T}, Sacrifice a Thopter: Create a 4/4 colorless Construct artifact creature token.| Forge of Heroes|Commander 2018|58|C||Land|||{T}: Add {C}.${T}: Choose target commander that entered the battlefield this turn. Put a +1/+1 counter on it if it's a creature and a loyalty counter on it if it's a planeswalker.| +Sigil of the Empty Throne|Commander 2018|74|R|{3}{W}{W}|Enchantment|||Whenever you cast an enchantment spell, create a 4/4 white Angel creature token with flying.| Winds of Rath|Commander 2018|79|R|{3}{W}{W}|Sorcery|||Destroy all creatures that aren't enchanted. They can't be regenerated.| Dictate of Kruphix|Commander 2018|86|R|{1}{U}{U}|Enchantment|||Flash$At the beginning of each player's draw step, that player draws an additional card.| Eel Umbra|Commander 2018|89|C|{1}{U}|Enchantment - Aura|||Flash| @@ -33980,6 +33983,7 @@ Centaur Vinecrasher|Commander 2018|135|R|{3}{G}|Creature - Plant Centaur|1|1|Tra Eidolon of Blossoms|Commander 2018|140|R|{2}{G}{G}|Enchantment Creature - Spirit|2|2|Constellation — Whenever Eidolon of Blossoms or another enchantment enters the battlefield under your control, draw a card.| Enchantress's Presence|Commander 2018|141|R|{2}{G}|Enchantment|||Whenever you cast an enchantment spell, draw a card.| Explosive Vegetation|Commander 2018|144|U|{3}{G}|Sorcery|||Search your library for up to two basic land cards and put them onto the battlefield tapped. Then shuffle your library.| +Herald of the Pantheon|Commander 2018|151|R|{1}{G}|Creature - Centaur Shaman|2|2|Enchantment spells you cast cost {1} less to cast.$Whenever you cast an enchantment spell, you gain 1 life.| Hydra Omnivore|Commander 2018|153|M|{4}{G}{G}|Creature - Hydra|8|8|Whenever Hydra Omnivore deals combat damage to an opponent, it deals that much damage to each other opponent.| Rampaging Baloths|Commander 2018|158|R|{4}{G}{G}|Creature - Beast|6|6|Trample$Landfall — Whenever a land enters the battlefield under your control, you may create a 4/4 green Beast creature token.| Scute Mob|Commander 2018|161|R|{G}|Creature - Insect|1|1|At the beginning of your upkeep, if you control five or more lands, put four +1/+1 counters on Scute Mob.| From 5aa1c91831e9e70ce646c2e6bc5e911a68a61853 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 25 Jul 2018 23:12:02 -0400 Subject: [PATCH 27/71] Implemented Nylea's Colossus --- .../src/mage/cards/n/NyleasColossus.java | 75 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 76 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/n/NyleasColossus.java diff --git a/Mage.Sets/src/mage/cards/n/NyleasColossus.java b/Mage.Sets/src/mage/cards/n/NyleasColossus.java new file mode 100644 index 00000000000..4f0f7caf7ec --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NyleasColossus.java @@ -0,0 +1,75 @@ +package mage.cards.n; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.abilityword.ConstellationAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author TheElk801 + */ +public final class NyleasColossus extends CardImpl { + + public NyleasColossus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{6}{G}"); + + this.subtype.add(SubType.GIANT); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Constellation — Whenever Nylea's Colossus or another enchantment enters the battlefield under your control, double target creature's power and toughness until end of turn. + Ability ability = new ConstellationAbility(new NyleasColossusEffect(), false); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public NyleasColossus(final NyleasColossus card) { + super(card); + } + + @Override + public NyleasColossus copy() { + return new NyleasColossus(this); + } +} + +class NyleasColossusEffect extends OneShotEffect { + + public NyleasColossusEffect() { + super(Outcome.BoostCreature); + this.staticText = "double target creature's power and toughness until end of turn"; + } + + public NyleasColossusEffect(final NyleasColossusEffect effect) { + super(effect); + } + + @Override + public NyleasColossusEffect copy() { + return new NyleasColossusEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + int power = permanent.getPower().getValue(); + int toughness = permanent.getToughness().getValue(); + game.addEffect(new BoostTargetEffect(power, toughness, Duration.EndOfTurn), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 87154272151..60475043cdf 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -50,6 +50,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); cards.add(new SetCardInfo("Nesting Dragon", 24, Rarity.RARE, mage.cards.n.NestingDragon.class)); + cards.add(new SetCardInfo("Nylea's Colossus", 33, Rarity.COMMON, mage.cards.n.NyleasColossus.class)); cards.add(new SetCardInfo("Octopus Umbra", 11, Rarity.RARE, mage.cards.o.OctopusUmbra.class)); cards.add(new SetCardInfo("Rampaging Baloths", 158, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); From 9b7c0da3187d0d68923548b3e5f3f5d12ed70712 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 25 Jul 2018 23:37:24 -0400 Subject: [PATCH 28/71] Implemented Turntimber Sower --- .../src/mage/cards/t/TurntimberSower.java | 120 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 121 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TurntimberSower.java diff --git a/Mage.Sets/src/mage/cards/t/TurntimberSower.java b/Mage.Sets/src/mage/cards/t/TurntimberSower.java new file mode 100644 index 00000000000..2db016a36cd --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TurntimberSower.java @@ -0,0 +1,120 @@ +package mage.cards.t; + +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.Card; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeGroupEvent; +import mage.game.permanent.token.PlantToken; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author TheElk801 + */ +public final class TurntimberSower extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledCreaturePermanent("three creatures"); + + public TurntimberSower(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever one or more land cards are put into your graveyard from anywhere, create a 0/1 green Plant creature token. + this.addAbility(new TurntimberSowerTriggeredAbility()); + + // {G}, Sacrifice three creatures: Return target land card from your graveyard to your hand. + Ability ability = new SimpleActivatedAbility( + new ReturnToHandTargetEffect() + .setText("Return target land card " + + "from your graveyard to your hand"), + new ManaCostsImpl("{G}") + ); + ability.addCost(new SacrificeTargetCost( + new TargetControlledPermanent(3, 3, filter, true) + )); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_LAND)); + this.addAbility(ability); + } + + public TurntimberSower(final TurntimberSower card) { + super(card); + } + + @Override + public TurntimberSower copy() { + return new TurntimberSower(this); + } +} + +class TurntimberSowerTriggeredAbility extends TriggeredAbilityImpl { + + public TurntimberSowerTriggeredAbility() { + super(Zone.BATTLEFIELD, new CreateTokenEffect(new PlantToken()), false); + } + + public TurntimberSowerTriggeredAbility(final TurntimberSowerTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE_GROUP; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeGroupEvent zEvent = (ZoneChangeGroupEvent) event; + if (zEvent != null + && Zone.GRAVEYARD == zEvent.getToZone() + && zEvent.getCards() != null) { + for (Card card : zEvent.getCards()) { + if (card != null) { + UUID cardOwnerId = card.getOwnerId(); + Set cardType = card.getCardType(); + if (cardOwnerId != null + && card.isOwnedBy(getControllerId()) + && cardType != null + && card.isLand()) { + return true; + } + } + } + } + return false; + } + + @Override + public TurntimberSowerTriggeredAbility copy() { + return new TurntimberSowerTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever one or more land cards are put into your graveyard " + + "from anywhere, create a 0/1 green Plant creature token."; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 60475043cdf..d0c60c97e07 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -62,6 +62,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Tawnos, Urza's Apprentice", 45, Rarity.MYTHIC, mage.cards.t.TawnosUrzasApprentice.class)); cards.add(new SetCardInfo("Thantis the Warweaver", 46, Rarity.MYTHIC, mage.cards.t.ThantisTheWarweaver.class)); cards.add(new SetCardInfo("Thopter Spy Network", 107, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class)); + cards.add(new SetCardInfo("Turntimber Sower", 35, Rarity.RARE, mage.cards.t.TurntimberSower.class)); cards.add(new SetCardInfo("Tuvasa the Sunlit", 47, Rarity.MYTHIC, mage.cards.t.TuvasaTheSunlit.class)); cards.add(new SetCardInfo("Varchild, Betrayer of Kjeldor", 28, Rarity.RARE, mage.cards.v.VarchildBetrayerOfKjeldor.class)); cards.add(new SetCardInfo("Whiptongue Hydra", 36, Rarity.RARE, mage.cards.w.WhiptongueHydra.class)); From 8c556fc48f2fd1192d34a888fa07e9965b0101e7 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 08:26:32 -0400 Subject: [PATCH 29/71] updated C18 spoiler --- Mage.Sets/src/mage/sets/Commander2018.java | 2 +- Utils/mtg-cards-data.txt | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index d0c60c97e07..05a628cb56d 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -50,7 +50,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); cards.add(new SetCardInfo("Nesting Dragon", 24, Rarity.RARE, mage.cards.n.NestingDragon.class)); - cards.add(new SetCardInfo("Nylea's Colossus", 33, Rarity.COMMON, mage.cards.n.NyleasColossus.class)); + cards.add(new SetCardInfo("Nylea's Colossus", 33, Rarity.RARE, mage.cards.n.NyleasColossus.class)); cards.add(new SetCardInfo("Octopus Umbra", 11, Rarity.RARE, mage.cards.o.OctopusUmbra.class)); cards.add(new SetCardInfo("Rampaging Baloths", 158, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index e83e2328ab9..fed21a467f6 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33944,9 +33944,10 @@ Saheeli's Directive|Commander 2018|26|R|{X}{R}{R}{R}|Sorcery|||Improvise$Reveal Treasure Nabber|Commander 2018|27|R|{2}{R}|Creature - Goblin Rogue|3|2|Whenever an opponent taps an artifact for mana, gain control of that artifact until the end of your next turn.| Varchild, Betrayer of Kjeldor|Commander 2018|28|R|{2}{R}|Legendary Creature - Human Knight|3|3|Whenever Varchild, Betrayer of Kjeldor deals combat damage to a player, that player creates that many 1/1 red Survivor creature tokens.$Survivors your opponents control can't block, and they can't attack you or a planeswalker you control.$When Varchild leaves the battlefield, gain control of all Survivors.| Crash of Rhino Beetles|Commander 2018|29|R|{4}{G}|Creature - Insect|5|5|Trample$Crash of Rhino Beetles gets +10/+10 as long as you control ten or more lands.| +Genesis Storm|Commander 2018|30|R|{4}{G}{G}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game.$Reveal cards from the top of your library until you reveal a nonland permanent card. You may put that card onto the battlefield. Then put all cards revealed this way that weren't put onto the battlefield on the bottom of your library in a random order.| Loyal Guardian|Commander 2018|31|U|{4}{G}|Creature - Rhino|4|4|Trample$Lieutenant — At the beginning of combat on your turn, if you control your commander, put a +1/+1 counter on each creature you control.| Myth Unbound|Commander 2018|32|R|{2}{G}|Enchantment|||Your commander costs {1} less to cast for each time it's been cast from the command zone this game.$Whenever your commander is put into the command zone from anywhere, draw a card.| -Nylea's Colossus|Commander 2018|33|C|{6}{G}|Enchantment Creature - Giant|6|6|Constellation — Whenever Nylea's Colossus or another enchantment enters the battlefield under your control, double target creature's power and toughness until end of turn.| +Nylea's Colossus|Commander 2018|33|R|{6}{G}|Enchantment Creature - Giant|6|6|Constellation — Whenever Nylea's Colossus or another enchantment enters the battlefield under your control, double target creature's power and toughness until end of turn.| Ravenous Slime|Commander 2018|34|R|{2}{G}|Creature - Ooze|1|1|Ravenous Slime can't be blocked by creatures with power 2 or less.$If a creature an opponent controls would die, instead exile it and put a number of +1/+1 counters equal to that creature's power on Ravenous Slime.| Turntimber Sower|Commander 2018|35|R|{2}{G}|Creature - Elf Druid|3|3|Whenever one or more land cards are put into your graveyard from anywhere, create a 0/1 green Plant creature token.${G}, Sacrifice three creatures: Return target land card from your graveyard to your hand.| Whiptongue Hydra|Commander 2018|36|R|{5}{G}|Creature - Lizard Hydra|4|4|Reach$When Whiptongue Hydra enters the battlefield, destroy all creatures with flying. Put a +1/+1 counter on Whiptongue Hydra for each creature destroyed this way.| @@ -33968,6 +33969,7 @@ Endless Atlas|Commander 2018|55|R|{2}|Artifact|||{2}, {T}: Draw a card. Activate Geode Golem|Commander 2018|56|U|{5}|Artifact Creature - Golem|5|3|Trample$Whenever Geode Golem deals combat damage to a player, you may cast your commander from the command zone without paying its mana cost.| Retrofitter Foundry|Commander 2018|57|R|{1}|Artifact|||{3}: Untap Retrofitter Foundry.${2}, {T}: Create a 1/1 colorless Servo artifact creature token.${1}, {T}, Sacrifice a Servo: Create a 1/1 colorless Thopter artifact creature token with flying.${T}, Sacrifice a Thopter: Create a 4/4 colorless Construct artifact creature token.| Forge of Heroes|Commander 2018|58|C||Land|||{T}: Add {C}.${T}: Choose target commander that entered the battlefield this turn. Put a +1/+1 counter on it if it's a creature and a loyalty counter on it if it's a planeswalker.| +Isolated Watchtower|Commander 2018|59|R||Land|||{T}: Add {C}.${2}, {T}: Scry 1, then you may reveal the top card of your library. If a basic land card is revealed this way, put it onto the battlefield tapped. Activate this ability only if an opponent controls at least two more lands than you.| Sigil of the Empty Throne|Commander 2018|74|R|{3}{W}{W}|Enchantment|||Whenever you cast an enchantment spell, create a 4/4 white Angel creature token with flying.| Winds of Rath|Commander 2018|79|R|{3}{W}{W}|Sorcery|||Destroy all creatures that aren't enchanted. They can't be regenerated.| Dictate of Kruphix|Commander 2018|86|R|{1}{U}{U}|Enchantment|||Flash$At the beginning of each player's draw step, that player draws an additional card.| From b22c94193fa657be670347e90f6eca2e960de828 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 09:01:04 -0400 Subject: [PATCH 30/71] Implemented Ravenous Slime --- Mage.Sets/src/mage/cards/r/RavenousSlime.java | 141 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 142 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/RavenousSlime.java diff --git a/Mage.Sets/src/mage/cards/r/RavenousSlime.java b/Mage.Sets/src/mage/cards/r/RavenousSlime.java new file mode 100644 index 00000000000..f68af5571d9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RavenousSlime.java @@ -0,0 +1,141 @@ +package mage.cards.r; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleEvasionAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author TheElk801 + */ +public final class RavenousSlime extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creatures with power 2 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public RavenousSlime(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.OOZE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Ravenous Slime can't be blocked by creatures with power 2 or less. + this.addAbility(new SimpleEvasionAbility( + new CantBeBlockedByCreaturesSourceEffect( + filter, Duration.WhileOnBattlefield + ) + )); + + // If a creature an opponent controls would die, instead exile it and put a number of +1/+1 counters equal to that creature's power on Ravenous Slime. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new RavenousSlimeEffect() + )); + } + + public RavenousSlime(final RavenousSlime card) { + super(card); + } + + @Override + public RavenousSlime copy() { + return new RavenousSlime(this); + } +} + +class RavenousSlimeEffect extends ReplacementEffectImpl { + + public RavenousSlimeEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "If a creature an opponent controls would die, " + + "instead exile it and put a number of +1/+1 counters " + + "equal to that creature's power on {this}"; + } + + public RavenousSlimeEffect(final RavenousSlimeEffect effect) { + super(effect); + } + + @Override + public RavenousSlimeEffect copy() { + return new RavenousSlimeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourceCreature = game.getPermanent(source.getSourceId()); + if (controller == null || sourceCreature == null) { + return false; + } + if (((ZoneChangeEvent) event).getFromZone() != Zone.BATTLEFIELD) { + return false; + } + Permanent permanent = ((ZoneChangeEvent) event).getTarget(); + if (permanent == null) { + return false; + } + int power = permanent.getPower().getValue(); + controller.moveCards(permanent, Zone.EXILED, source, game); + return new AddCountersSourceEffect( + CounterType.P1P1.createInstance(power) + ).apply(game, source); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getToZone() != Zone.GRAVEYARD) { + return false; + } + Permanent permanent = ((ZoneChangeEvent) event).getTarget(); + if (permanent == null + || !game.getOpponents(source.getControllerId()).contains(permanent.getControllerId())) { + return false; + } + if (zEvent.getTarget() != null) { // if it comes from permanent, check if it was a creature on the battlefield + if (zEvent.getTarget().isCreature()) { + return true; + } + } else if (permanent.isCreature()) { + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 05a628cb56d..f149cec917a 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -53,6 +53,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Nylea's Colossus", 33, Rarity.RARE, mage.cards.n.NyleasColossus.class)); cards.add(new SetCardInfo("Octopus Umbra", 11, Rarity.RARE, mage.cards.o.OctopusUmbra.class)); cards.add(new SetCardInfo("Rampaging Baloths", 158, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); + cards.add(new SetCardInfo("Ravenous Slime", 34, Rarity.RARE, mage.cards.r.RavenousSlime.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); cards.add(new SetCardInfo("Saheeli's Directive", 26, Rarity.RARE, mage.cards.s.SaheelisDirective.class)); From 2086a4303614ae75c761735563f72612269364f6 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 11:11:42 -0400 Subject: [PATCH 31/71] Implemented Genesis Storm --- Mage.Sets/src/mage/cards/g/GenesisStorm.java | 90 ++++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 91 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/g/GenesisStorm.java diff --git a/Mage.Sets/src/mage/cards/g/GenesisStorm.java b/Mage.Sets/src/mage/cards/g/GenesisStorm.java new file mode 100644 index 00000000000..c26ff95762c --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GenesisStorm.java @@ -0,0 +1,90 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.CommanderStormAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author TheElk801 + */ +public final class GenesisStorm extends CardImpl { + + public GenesisStorm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}"); + + // When you cast this spell, copy it for each time you've cast your commander from the command zone this game. + this.addAbility(new CommanderStormAbility()); + + // Reveal cards from the top of your library until you reveal a nonland permanent card. You may put that card onto the battlefield. Then put all cards revealed this way that weren't put onto the battlefield on the bottom of your library in a random order. + this.getSpellAbility().addEffect(new GenesisStormEffect()); + } + + public GenesisStorm(final GenesisStorm card) { + super(card); + } + + @Override + public GenesisStorm copy() { + return new GenesisStorm(this); + } +} + +class GenesisStormEffect extends OneShotEffect { + + public GenesisStormEffect() { + super(Outcome.PlayForFree); + this.staticText = "reveal cards from the top of your library " + + "until you reveal a nonland permanent card. " + + "You may put that card onto the battlefield. " + + "Then put all cards revealed this way " + + "that weren't put onto the battlefield " + + "on the bottom of your library in a random order"; + } + + public GenesisStormEffect(GenesisStormEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + CardsImpl toReveal = new CardsImpl(); + Card nonLandCard = null; + for (Card card : controller.getLibrary().getCards(game)) { + toReveal.add(card); + if (card.isPermanent() && !card.isLand()) { + nonLandCard = card; + break; + } + } + controller.revealCards(source, toReveal, game); + if (nonLandCard != null && controller.chooseUse( + outcome, "Put " + nonLandCard.getLogName() + + " onto the battlefield?", source, game + )) { + controller.moveCards(nonLandCard, Zone.BATTLEFIELD, source, game); + toReveal.remove(nonLandCard); + } + controller.putCardsOnBottomOfLibrary(toReveal, game, source, false); + return true; + } + + @Override + public GenesisStormEffect copy() { + return new GenesisStormEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index f149cec917a..f87e5cf0fb9 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -41,6 +41,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Finest Hour", 180, Rarity.RARE, mage.cards.f.FinestHour.class)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); cards.add(new SetCardInfo("Fury Storm", 22, Rarity.RARE, mage.cards.f.FuryStorm.class)); + cards.add(new SetCardInfo("Genesis Storm", 30, Rarity.RARE, mage.cards.g.GenesisStorm.class)); cards.add(new SetCardInfo("Herald of the Pantheon", 151, Rarity.RARE, mage.cards.h.HeraldOfThePantheon.class)); cards.add(new SetCardInfo("Hydra Omnivore", 153, Rarity.MYTHIC, mage.cards.h.HydraOmnivore.class)); cards.add(new SetCardInfo("Kestia, the Cultivator", 42, Rarity.MYTHIC, mage.cards.k.KestiaTheCultivator.class)); From fc2ce0629b0ae1e9ae5b12f9d27b891286ce2fbb Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 12:16:50 -0400 Subject: [PATCH 32/71] Implemented Estrid's Invocation --- .../src/mage/cards/e/EstridsInvocation.java | 105 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 106 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EstridsInvocation.java diff --git a/Mage.Sets/src/mage/cards/e/EstridsInvocation.java b/Mage.Sets/src/mage/cards/e/EstridsInvocation.java new file mode 100644 index 00000000000..0f6094c73a0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EstridsInvocation.java @@ -0,0 +1,105 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CopyPermanentEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.functions.ApplyToPermanent; + +/** + * + * @author TheElk801 + */ +public final class EstridsInvocation extends CardImpl { + + public EstridsInvocation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + // You may have Estrid's Invocation enter the battlefield as a copy of any enchantment you control, except it gains "At the beginning of your upkeep, you may exile this enchantment. If you do, return it to the battlefield under its owner's control." + this.addAbility(new EntersBattlefieldAbility(new CopyPermanentEffect( + StaticFilters.FILTER_ENCHANTMENT_PERMANENT, + new EstridsInvocationApplier() + ).setText("as a copy of any enchantment you control, except it gains " + + "\"At the beginning of your upkeep, " + + "you may exile this enchantment. " + + "If you do, return it to the battlefield " + + "under its owner's control.\""), true + )); + } + + public EstridsInvocation(final EstridsInvocation card) { + super(card); + } + + @Override + public EstridsInvocation copy() { + return new EstridsInvocation(this); + } +} + +class EstridsInvocationApplier extends ApplyToPermanent { + + @Override + public boolean apply(Game game, Permanent permanent, Ability source, UUID copyToObjectId) { + // At the beginning of your upkeep, you may exile this enchantment. If you do, return it to the battlefield under its owner's control. + permanent.addAbility(new BeginningOfUpkeepTriggeredAbility( + new EstridsInvocationEffect(), TargetController.YOU, true + ), source.getSourceId(), game); + return true; + } + + @Override + public boolean apply(Game game, MageObject mageObject, Ability source, UUID copyToObjectId) { + // At the beginning of your upkeep, you may exile this enchantment. If you do, return it to the battlefield under its owner's control. + mageObject.getAbilities().add(new BeginningOfUpkeepTriggeredAbility( + new EstridsInvocationEffect(), TargetController.YOU, true + )); + return true; + } + +} + +class EstridsInvocationEffect extends OneShotEffect { + + public EstridsInvocationEffect() { + super(Outcome.Neutral); + this.staticText = "you may exile this enchantment. " + + "If you do, return it to the battlefield under its owner's control"; + } + + public EstridsInvocationEffect(final EstridsInvocationEffect effect) { + super(effect); + } + + @Override + public EstridsInvocationEffect copy() { + return new EstridsInvocationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + if (permanent.moveToExile(source.getSourceId(), "Estrid's Invocation", source.getSourceId(), game)) { + Card card = game.getExile().getCard(source.getSourceId(), game); + if (card != null) { + return card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index f87e5cf0fb9..99be857e752 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -37,6 +37,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Empyrial Storm", 2, Rarity.RARE, mage.cards.e.EmpyrialStorm.class)); cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); cards.add(new SetCardInfo("Enchantress's Presence", 141, Rarity.RARE, mage.cards.e.EnchantresssPresence.class)); + cards.add(new SetCardInfo("Estrid's Invocation", 8, Rarity.RARE, mage.cards.e.EstridsInvocation.class)); cards.add(new SetCardInfo("Explosive Vegetation", 144, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); cards.add(new SetCardInfo("Finest Hour", 180, Rarity.RARE, mage.cards.f.FinestHour.class)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); From 753f33dbc3eac1b0f5d8e4f6b65d70e0a484ba0e Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 13:43:20 -0400 Subject: [PATCH 33/71] Implemented Heavenly Blademaster --- .../src/mage/cards/h/HeavenlyBlademaster.java | 129 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 130 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/h/HeavenlyBlademaster.java diff --git a/Mage.Sets/src/mage/cards/h/HeavenlyBlademaster.java b/Mage.Sets/src/mage/cards/h/HeavenlyBlademaster.java new file mode 100644 index 00000000000..ee4ee6d4683 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HeavenlyBlademaster.java @@ -0,0 +1,129 @@ +package mage.cards.h; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.AdditiveDynamicValue; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.AuraAttachedCount; +import mage.abilities.dynamicvalue.common.EquipmentAttachedCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; + +/** + * + * @author TheElk801 + */ +public final class HeavenlyBlademaster extends CardImpl { + + public HeavenlyBlademaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}"); + + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(3); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Double strike + this.addAbility(DoubleStrikeAbility.getInstance()); + + // When Heavenly Blademaster enters the battlefield, you may attach any number of Auras and Equipment you control to it. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new HeavenlyBlademasterEffect(), true + )); + + // Other creatures you control get +1/+1 for each Aura and Equipment attached to Heavenly Blademaster. + DynamicValue totalAmount = new AdditiveDynamicValue( + new EquipmentAttachedCount(1), + new AuraAttachedCount(1) + ); + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new BoostControlledEffect( + totalAmount, totalAmount, Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURES, true + ) + )); + } + + public HeavenlyBlademaster(final HeavenlyBlademaster card) { + super(card); + } + + @Override + public HeavenlyBlademaster copy() { + return new HeavenlyBlademaster(this); + } +} + +class HeavenlyBlademasterEffect extends OneShotEffect { + + private static final FilterPermanent filter + = new FilterControlledPermanent("Aura or Equipment you control"); + + static { + filter.add(Predicates.or( + new SubtypePredicate(SubType.AURA), + new SubtypePredicate(SubType.EQUIPMENT) + )); + } + + public HeavenlyBlademasterEffect() { + super(Outcome.Benefit); + this.staticText = "you may attach any number " + + "of Auras and Equipment you control to it"; + } + + public HeavenlyBlademasterEffect(final HeavenlyBlademasterEffect effect) { + super(effect); + } + + @Override + public HeavenlyBlademasterEffect copy() { + return new HeavenlyBlademasterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + Player player = game.getPlayer(source.getControllerId()); + if (permanent == null || player == null) { + return false; + } + Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); + if (!player.choose(outcome, target, source.getSourceId(), game)) { + return false; + } + target.getTargets().stream().map( + attachmentId -> game.getPermanent(attachmentId) + ).filter( + attachment -> attachment != null + ).forEachOrdered((attachment) -> { + attachment.attachTo(permanent.getId(), game); + }); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 99be857e752..1d5eb0f1cfd 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -43,6 +43,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); cards.add(new SetCardInfo("Fury Storm", 22, Rarity.RARE, mage.cards.f.FuryStorm.class)); cards.add(new SetCardInfo("Genesis Storm", 30, Rarity.RARE, mage.cards.g.GenesisStorm.class)); + cards.add(new SetCardInfo("Heavenly Blademaster", 3, Rarity.RARE, mage.cards.h.HeavenlyBlademaster.class)); cards.add(new SetCardInfo("Herald of the Pantheon", 151, Rarity.RARE, mage.cards.h.HeraldOfThePantheon.class)); cards.add(new SetCardInfo("Hydra Omnivore", 153, Rarity.MYTHIC, mage.cards.h.HydraOmnivore.class)); cards.add(new SetCardInfo("Kestia, the Cultivator", 42, Rarity.MYTHIC, mage.cards.k.KestiaTheCultivator.class)); From 8bebca825779e09ab163d4b6c8fa67ac29b2aa63 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 15:47:09 -0400 Subject: [PATCH 34/71] Implemented Isolated Watchtower --- .../src/mage/cards/i/IsolatedWatchtower.java | 118 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 119 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/i/IsolatedWatchtower.java diff --git a/Mage.Sets/src/mage/cards/i/IsolatedWatchtower.java b/Mage.Sets/src/mage/cards/i/IsolatedWatchtower.java new file mode 100644 index 00000000000..f3307da13fb --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IsolatedWatchtower.java @@ -0,0 +1,118 @@ +package mage.cards.i; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author TheElk801 + */ +public final class IsolatedWatchtower extends CardImpl { + + public IsolatedWatchtower(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {2}, {T}: Scry 1, then you may reveal the top card of your library. If a basic land card is revealed this way, put it onto the battlefield tapped. Activate this ability only if an opponent controls at least two more lands than you. + Ability ability = new ConditionalActivatedAbility( + Zone.BATTLEFIELD, + new IsolatedWatchtowerEffect(), + new GenericManaCost(2), + new IsolatedWatchtowerCondition() + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public IsolatedWatchtower(final IsolatedWatchtower card) { + super(card); + } + + @Override + public IsolatedWatchtower copy() { + return new IsolatedWatchtower(this); + } +} + +class IsolatedWatchtowerEffect extends OneShotEffect { + + public IsolatedWatchtowerEffect() { + super(Outcome.Benefit); + this.staticText = "scry 1, then you may reveal the top card " + + "of your library. If a basic land card is revealed this way, " + + "put it onto the battlefield tapped"; + } + + public IsolatedWatchtowerEffect(final IsolatedWatchtowerEffect effect) { + super(effect); + } + + @Override + public IsolatedWatchtowerEffect copy() { + return new IsolatedWatchtowerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + player.scry(1, source, game); + if (!player.chooseUse( + outcome, "Reveal the top card of your library?", source, game + )) { + return true; + } + Card card = player.getLibrary().getFromTop(game); + player.revealCards(source, new CardsImpl(card), game); + if (card.isBasic() && card.isLand()) { + player.moveCards( + card, Zone.BATTLEFIELD, source, + game, true, false, true, null + ); + } + return true; + } +} + +class IsolatedWatchtowerCondition implements Condition { + + @Override + public boolean apply(Game game, Ability source) { + int numLands = game.getBattlefield().countAll( + StaticFilters.FILTER_LAND, source.getControllerId(), game + ); + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + if (numLands < 1 + game.getBattlefield().countAll( + StaticFilters.FILTER_LAND, opponentId, game + )) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return "an opponent controls at least two more lands than you"; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 1d5eb0f1cfd..eca1bdfeef7 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -46,6 +46,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Heavenly Blademaster", 3, Rarity.RARE, mage.cards.h.HeavenlyBlademaster.class)); cards.add(new SetCardInfo("Herald of the Pantheon", 151, Rarity.RARE, mage.cards.h.HeraldOfThePantheon.class)); cards.add(new SetCardInfo("Hydra Omnivore", 153, Rarity.MYTHIC, mage.cards.h.HydraOmnivore.class)); + cards.add(new SetCardInfo("Isolated Watchtower", 59, Rarity.RARE, mage.cards.i.IsolatedWatchtower.class)); cards.add(new SetCardInfo("Kestia, the Cultivator", 42, Rarity.MYTHIC, mage.cards.k.KestiaTheCultivator.class)); cards.add(new SetCardInfo("Lord Windgrace", 43, Rarity.MYTHIC, mage.cards.l.LordWindgrace.class)); cards.add(new SetCardInfo("Loyal Apprentice", 23, Rarity.UNCOMMON, mage.cards.l.LoyalApprentice.class)); From 9bf588fea08704ea0c75e473a4422d2242a5deb9 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 16:22:34 -0400 Subject: [PATCH 35/71] updated C18 spoiler --- Mage.Sets/src/mage/sets/Commander2018.java | 4 ++++ Utils/mtg-cards-data.txt | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index eca1bdfeef7..b1c376ff9a4 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -56,6 +56,9 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Nesting Dragon", 24, Rarity.RARE, mage.cards.n.NestingDragon.class)); cards.add(new SetCardInfo("Nylea's Colossus", 33, Rarity.RARE, mage.cards.n.NyleasColossus.class)); cards.add(new SetCardInfo("Octopus Umbra", 11, Rarity.RARE, mage.cards.o.OctopusUmbra.class)); + cards.add(new SetCardInfo("Phyrexian Delver", 115, Rarity.RARE, mage.cards.p.PhyrexianDelver.class)); + cards.add(new SetCardInfo("Portent", 97, Rarity.COMMON, mage.cards.p.Portent.class)); + cards.add(new SetCardInfo("Predict", 98, Rarity.UNCOMMON, mage.cards.p.Predict.class)); cards.add(new SetCardInfo("Rampaging Baloths", 158, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); cards.add(new SetCardInfo("Ravenous Slime", 34, Rarity.RARE, mage.cards.r.RavenousSlime.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); @@ -65,6 +68,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Sigil of the Empty Throne", 74, Rarity.RARE, mage.cards.s.SigilOfTheEmptyThrone.class)); cards.add(new SetCardInfo("Spawning Grounds", 163, Rarity.RARE, mage.cards.s.SpawningGrounds.class)); cards.add(new SetCardInfo("Tawnos, Urza's Apprentice", 45, Rarity.MYTHIC, mage.cards.t.TawnosUrzasApprentice.class)); + cards.add(new SetCardInfo("Terminus", 77, Rarity.RARE, mage.cards.t.Terminus.class)); cards.add(new SetCardInfo("Thantis the Warweaver", 46, Rarity.MYTHIC, mage.cards.t.ThantisTheWarweaver.class)); cards.add(new SetCardInfo("Thopter Spy Network", 107, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class)); cards.add(new SetCardInfo("Turntimber Sower", 35, Rarity.RARE, mage.cards.t.TurntimberSower.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index fed21a467f6..e4733613c55 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33927,13 +33927,20 @@ Mountain|Global Series: Jiang Yanggu & Mu Yanling|39|C||Basic Land - Mountain||| Forest|Global Series: Jiang Yanggu & Mu Yanling|40|C||Basic Land - Forest|||({T}: Add {G}.)| Empyrial Storm|Commander 2018|2|R|{4}{W}{W}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game.$Create a 4/4 white Angel creature token with flying.| Heavenly Blademaster|Commander 2018|3|R|{5}{W}|Creature - Angel|3|6|Flying, double strike$When Heavenly Blademaster enters the battlefield, you may attach any number of Auras and Equipment you control to it.$Other creatures you control get +1/+1 for each Aura and Equipment attached to Heavenly Blademaster.| +Loyal Unicorn|Commander 2018|4|U|{3}{W}|Creature - Unicorn|3|4|Vigilance$Lieutenant — At the beginning of combat on your turn, if you control your commander, prevent all combat damage that would be dealt to creatures you control this turn. Other creatures you control gain vigilance until end of turn.| +Magus of the Balance|Commander 2018|5|R|{1}{W}|Creature - Human Wizard|2|2|{4}{W}, {T}, Sacrifice Magus of the Balance: Each player chooses a number of lands they control equal to the number of lands controlled by the player who controls the fewest, then sacrifices the rest. Players discard cards and sacrifice creatures the same way.| +Aminatou's Augury|Commander 2018|6|R|{6}{U}{U}|Sorcery|||Exile the top eight cards of your library. You may put a land card from among them onto the battlefield. Until end of turn, for each nonland card type, you may cast a card of that type from among the exiled cards without paying its mana cost.| Echo Storm|Commander 2018|7|R|{3}{U}{U}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.$Create a token that's a copy of target artifact.| Estrid's Invocation|Commander 2018|8|R|{2}{U}|Enchantment|||You may have Estrid's Invocation enter the battlefield as a copy of any enchantment you control, except it gains "At the beginning of your upkeep, you may exile this enchantment. If you do, return it to the battlefield under its owner's control."| Loyal Drake|Commander 2018|10|U|{2}{U}|Creature - Drake|2|2|Flying$Lieutenant — At the beginning of combat on your turn, if you control your commander, draw a card.| Octopus Umbra|Commander 2018|11|R|{3}{U}{U}|Enchantment - Aura|||Enchant creature$Enchanted creature has base power and toughness 8/8 and has "Whenever this creature attacks, you may tap target creature with power 8 or less."$Totem armor| Vedalken Humiliator|Commander 2018|13|R|{3}{U}|Creature - Vedalken Wizard|3|4|Metalcraft — Whenever Vedalken Humiliator attacks, if you control three or more artifacts, creatures your opponents control lose all abilities and have base power and toughness 1/1 until end of turn.| Bloodtracker|Commander 2018|14|R|{3}{B}|Creature - Vampire Wizard|2|2|Flying${B}, Pay 2 life: Put a +1/+1 counter on Bloodtracker.$When Bloodtracker leaves the battlefield, draw a card for each +1/+1 counter on it.| +Entreat the Dead|Commander 2018|15|R|{X}{X}{B}{B}{B}|Sorcery|||Return X target creature cards from your graveyard to the battlefield.$Miracle {X}{B}{B}| Loyal Subordinate|Commander 2018|16|U|{2}{B}|Creature - Zombie|3|1|Menace$Lieutenant — At the beginning of combat on your turn, if you control your commander, each opponent loses 3 life.| +Night Incarnate|Commander 2018|17|R|{4}{B}|Creature - Elemental|3|4|Deathtouch$When Night Incarnate leaves the battlefield, all creatures get -3/-3 until end of turn.$Evoke {3}{B}| +Skull Storm|Commander 2018|18|C|{7}{B}{B}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game.$Each opponent sacrifices a creature. Each opponent who can't loses half their life, rounded up.| +Sower of Discord|Commander 2018|19|R|{4}{B}{B}|Creature - Demon|6|6|Flying$As Sower of Discord enters the battlefield, choose two players.$Whenever damage is dealt to one of the chosen players, the other chosen player also loses that much life.| Emissary of Grudges|Commander 2018|20|R|{5}{R}|Creature - Efreet|6|5|Flying, haste$As Emissary of Grudges enters the battlefield, secretly choose an opponent.$Reveal the player you chose: Choose new targets for target spell or ability if it's controlled by the chosen player and if it targets you or a permanent you control. Activate this ability only once.| Enchanter's Bane|Commander 2018|21|R|{1}{R}|Enchantment|||At the beginning of your end step, target enchantment deals damage equal to its converted mana cost to its controller unless that player sacrifices it.| Fury Storm|Commander 2018|22|R|{2}{R}{R}|Instant|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.$Copy target instant or sorcery spell. You may choose new targets for the copy.| @@ -33951,6 +33958,7 @@ Nylea's Colossus|Commander 2018|33|R|{6}{G}|Enchantment Creature - Giant|6|6|Con Ravenous Slime|Commander 2018|34|R|{2}{G}|Creature - Ooze|1|1|Ravenous Slime can't be blocked by creatures with power 2 or less.$If a creature an opponent controls would die, instead exile it and put a number of +1/+1 counters equal to that creature's power on Ravenous Slime.| Turntimber Sower|Commander 2018|35|R|{2}{G}|Creature - Elf Druid|3|3|Whenever one or more land cards are put into your graveyard from anywhere, create a 0/1 green Plant creature token.${G}, Sacrifice three creatures: Return target land card from your graveyard to your hand.| Whiptongue Hydra|Commander 2018|36|R|{5}{G}|Creature - Lizard Hydra|4|4|Reach$When Whiptongue Hydra enters the battlefield, destroy all creatures with flying. Put a +1/+1 counter on Whiptongue Hydra for each creature destroyed this way.| +Aminatou, the Fateshifter|Commander 2018|37|M|{W}{U}{B}|Legendary Planeswalker - Aminatou|3|+1: Draw a card, then put a card from your hand on top of your library.$-1: Exile another target permanent you own, then return it to the battlefield under your control.$-6: Choose left or right. Each player gains control of all nonland permanents other than Aminatou, the Fateshifter controlled by the next player in the chosen direction.$Aminatou, the Fateshifter can be your commander.| Arixmethes, Slumbering Isle|Commander 2018|38|R|{2}{G}{U}|Legendary Creature - Kraken|12|12|Arixmethes, Slumbering Isle enters the battlefield tapped with five slumber counters on it.$As long as Arixmethes has a slumber counter on it, it's a land.$Whenever you cast a spell, you may remove a slumber counter from Arixmethes.${T}: Add {G}{U}.| Brudiclad, Telchor Engineer|Commander 2018|39|M|{4}{U}{R}|Legendary Artifact Creature - Artificer|4|4|Creature tokens you control have haste.$At the beginning of combat on your turn, create a 2/1 blue Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token.| Estrid, the Masked|Commander 2018|40|M|{1}{G}{W}{U}|Legendary Planeswalker - Estrid|3|+2: Untap each enchanted permanent you control.$-1: Create a white Aura enchantment token named Mask attached to another target permanent. The token has enchant permanent and totem armor.$-7: Put the top seven cards of your library into your graveyard. Return all non-Aura enchantment cards from your graveyard to the battlefield, then do the same for Aura cards.$Estrid, the Masked can be your commander.| @@ -33963,6 +33971,8 @@ Thantis the Warweaver|Commander 2018|46|M|{3}{B}{R}{G}|Legendary Creature - Spid Tuvasa the Sunlit|Commander 2018|47|M|{G}{W}{U}|Legendary Creature - Merfolk Shaman|1|1|Tuvasa the Sunlit gets +1/+1 for each enchantment you control.$Whenever you cast your first enchantment spell each turn, draw a card.| Windgrace's Judgment|Commander 2018|49|R|{3}{B}{G}|Instant|||For any number of opponents, destroy target nonland permanent that player controls.| Xantcha, Sleeper Agent|Commander 2018|50|R|{1}{B}{R}|Legendary Creature - Minion|5|5|As Xantcha, Sleeper Agent enters the battlefield, an opponent of your choice gains control of it.$Xantcha attacks each combat if able and can't attack its owner or planeswalkers its owner controls.${3}: Xantcha's controller loses 2 life and you draw a card. Any player may activate this ability.| +Yennet, Crypt Sovereign|Commander 2018|51|M|{2}{W}{U}{B}|Legendary Creature - Sphinx|3|5|Flying, vigilance, menace$Whenever Yennet, Crypt Sovereign attacks, reveal the top card of your library. If that card's converted mana cost is odd, you may cast it without paying its mana cost. Otherwise, draw a card.| +Yuriko, the Tiger's Shadow|Commander 2018|52|R|{1}{U}{B}|Legendary Creature - Human Ninja|1|3|Commander ninjutsu {U}{B}$Whenever a Ninja you control deals combat damage to a player, reveal the top card of your library and put that card into your hand. Each opponent loses life equal to that card's converted mana cost.| Ancient Stone Idol|Commander 2018|53|R|{10}|Artifact Creature - Golem|12|12|Flash$This spell costs {1} less to cast for each attacking creature.$Trample$When Ancient Stone Idol dies, create a 6/12 colorless Construct artifact creature token with trample.| Coveted Jewel|Commander 2018|54|R|{6}|Artifact|||When Coveted Jewel enters the battlefield, draw three cards.${T}: Add three mana of any one color.$Whenever one or more creatures an opponent controls attack you and aren't blocked, that player draws three cards and gains control of Coveted Jewel. Untap it.| Endless Atlas|Commander 2018|55|R|{2}|Artifact|||{2}, {T}: Draw a card. Activate this ability only if you control three or more lands with the same name.| @@ -33971,10 +33981,14 @@ Retrofitter Foundry|Commander 2018|57|R|{1}|Artifact|||{3}: Untap Retrofitter Fo Forge of Heroes|Commander 2018|58|C||Land|||{T}: Add {C}.${T}: Choose target commander that entered the battlefield this turn. Put a +1/+1 counter on it if it's a creature and a loyalty counter on it if it's a planeswalker.| Isolated Watchtower|Commander 2018|59|R||Land|||{T}: Add {C}.${2}, {T}: Scry 1, then you may reveal the top card of your library. If a basic land card is revealed this way, put it onto the battlefield tapped. Activate this ability only if an opponent controls at least two more lands than you.| Sigil of the Empty Throne|Commander 2018|74|R|{3}{W}{W}|Enchantment|||Whenever you cast an enchantment spell, create a 4/4 white Angel creature token with flying.| +Terminus|Commander 2018|77|R|{4}{W}{W}|Sorcery|||Put all creatures on the bottom of their owners' libraries.$Miracle {W}| Winds of Rath|Commander 2018|79|R|{3}{W}{W}|Sorcery|||Destroy all creatures that aren't enchanted. They can't be regenerated.| Dictate of Kruphix|Commander 2018|86|R|{1}{U}{U}|Enchantment|||Flash$At the beginning of each player's draw step, that player draws an additional card.| Eel Umbra|Commander 2018|89|C|{1}{U}|Enchantment - Aura|||Flash| +Portent|Commander 2018|97|C|{U}|Sorcery|||Look at the top three cards of target player's library, then put them back in any order. You may have that player shuffle their library.$Draw a card at the beginning of the next turn's upkeep.| +Predict|Commander 2018|98|U|{1}{U}|Instant|||Choose a card name, then target player puts the top card of their library into their graveyard. If that card has the chosen name, you draw two cards. Otherwise, you draw a card.| Thopter Spy Network|Commander 2018|107|R|{2}{U}{U}|Enchantment|||At the beginning of your upkeep, if you control an artifact, create a 1/1 colorless Thopter artifact creature token with flying.$Whenever one or more artifact creatures you control deal combat damage to a player, draw a card.| +Phyrexian Delver|Commander 2018|115|R|{3}{B}{B}|Creature - Zombie|3|2|When Phyrexian Delver enters the battlefield, return target creature card from your graveyard to the battlefield. You lose life equal to that card's converted mana cost.| Ruinous Path|Commander 2018|117|R|{1}{B}{B}|Sorcery|||Destroy target creature or planeswalker.$Awaken 4—{5}{B}{B}| Chain Reaction|Commander 2018|121|R|{2}{R}{R}|Sorcery|||Chain Reaction deals X damage to each creature, where X is the number of creatures on the battlefield.| Chaos Warp|Commander 2018|122|R|{2}{R}|Instant|||The owner of target permanent shuffles it into their library, then reveals the top card of their library. If it's a permanent card, they put it onto the battlefield.| From e7a941716345c784b44aad228d1d988906209c6b Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 16:42:04 -0400 Subject: [PATCH 36/71] updated C18 spoiler --- Utils/mtg-cards-data.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index e4733613c55..aab2ff17a1b 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33925,6 +33925,7 @@ Cleansing Screech|Global Series: Jiang Yanggu & Mu Yanling|37|C|{4}{R}|Sorcery|| Timber Gorge|Global Series: Jiang Yanggu & Mu Yanling|38|C||Land|||Timber Gorge enters the battlefield tapped.${T}: Add {R} or {G}.| Mountain|Global Series: Jiang Yanggu & Mu Yanling|39|C||Basic Land - Mountain|||({T}: Add {R}.)| Forest|Global Series: Jiang Yanggu & Mu Yanling|40|C||Basic Land - Forest|||({T}: Add {G}.)| +Boreas Charger|Commander 2018|1|R|{2}{W}|Creature - Pegasus|2|1|Flying$When Boreas Charger leaves the battlefield, choose an opponent who controls more lands than you. Search your library for a number of Plains cards equal to the difference and reveal them. Put one of them onto the battlefield tapped and the rest into your hand. Then shuffle your library.| Empyrial Storm|Commander 2018|2|R|{4}{W}{W}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game.$Create a 4/4 white Angel creature token with flying.| Heavenly Blademaster|Commander 2018|3|R|{5}{W}|Creature - Angel|3|6|Flying, double strike$When Heavenly Blademaster enters the battlefield, you may attach any number of Auras and Equipment you control to it.$Other creatures you control get +1/+1 for each Aura and Equipment attached to Heavenly Blademaster.| Loyal Unicorn|Commander 2018|4|U|{3}{W}|Creature - Unicorn|3|4|Vigilance$Lieutenant — At the beginning of combat on your turn, if you control your commander, prevent all combat damage that would be dealt to creatures you control this turn. Other creatures you control gain vigilance until end of turn.| @@ -33934,6 +33935,7 @@ Echo Storm|Commander 2018|7|R|{3}{U}{U}|Sorcery|||When you cast this spell, copy Estrid's Invocation|Commander 2018|8|R|{2}{U}|Enchantment|||You may have Estrid's Invocation enter the battlefield as a copy of any enchantment you control, except it gains "At the beginning of your upkeep, you may exile this enchantment. If you do, return it to the battlefield under its owner's control."| Loyal Drake|Commander 2018|10|U|{2}{U}|Creature - Drake|2|2|Flying$Lieutenant — At the beginning of combat on your turn, if you control your commander, draw a card.| Octopus Umbra|Commander 2018|11|R|{3}{U}{U}|Enchantment - Aura|||Enchant creature$Enchanted creature has base power and toughness 8/8 and has "Whenever this creature attacks, you may tap target creature with power 8 or less."$Totem armor| +Primordial Mist|Commander 2018|12|R|{4}{U}|Enchantment|||At the beginning of your end step, you may manifest the top card of your library.| Vedalken Humiliator|Commander 2018|13|R|{3}{U}|Creature - Vedalken Wizard|3|4|Metalcraft — Whenever Vedalken Humiliator attacks, if you control three or more artifacts, creatures your opponents control lose all abilities and have base power and toughness 1/1 until end of turn.| Bloodtracker|Commander 2018|14|R|{3}{B}|Creature - Vampire Wizard|2|2|Flying${B}, Pay 2 life: Put a +1/+1 counter on Bloodtracker.$When Bloodtracker leaves the battlefield, draw a card for each +1/+1 counter on it.| Entreat the Dead|Commander 2018|15|R|{X}{X}{B}{B}{B}|Sorcery|||Return X target creature cards from your graveyard to the battlefield.$Miracle {X}{B}{B}| @@ -33969,6 +33971,7 @@ Saheeli, the Gifted|Commander 2018|44|M|{2}{U}{R}|Legendary Planeswalker - Sahee Tawnos, Urza's Apprentice|Commander 2018|45|M|{U}{R}|Legendary Creature - Human Artificer|1|3|Haste${U}{R}, {T}: Copy target activated or triggered ability you control from an artifact source. You may choose new targets for the copy.| Thantis the Warweaver|Commander 2018|46|M|{3}{B}{R}{G}|Legendary Creature - Spider|5|5|Vigilance, reach$All creatures attack each combat if able.$Whenever a creature attacks you or a planeswalker you control, put a +1/+1 counter on Thantis the Warweaver.| Tuvasa the Sunlit|Commander 2018|47|M|{G}{W}{U}|Legendary Creature - Merfolk Shaman|1|1|Tuvasa the Sunlit gets +1/+1 for each enchantment you control.$Whenever you cast your first enchantment spell each turn, draw a card.| +Varina, Lich Queen|Commander 2018|48|M|{1}{W}{U}{B}|Legendary Creature - Zombie Wizard|4|4|Whenever you attack with one or more Zombies, draw that many cards, then discard that many cards. You gain that much life.${2}, Exile two cards from your graveyard: Create a tapped 2/2 black Zombie creature token.| Windgrace's Judgment|Commander 2018|49|R|{3}{B}{G}|Instant|||For any number of opponents, destroy target nonland permanent that player controls.| Xantcha, Sleeper Agent|Commander 2018|50|R|{1}{B}{R}|Legendary Creature - Minion|5|5|As Xantcha, Sleeper Agent enters the battlefield, an opponent of your choice gains control of it.$Xantcha attacks each combat if able and can't attack its owner or planeswalkers its owner controls.${3}: Xantcha's controller loses 2 life and you draw a card. Any player may activate this ability.| Yennet, Crypt Sovereign|Commander 2018|51|M|{2}{W}{U}{B}|Legendary Creature - Sphinx|3|5|Flying, vigilance, menace$Whenever Yennet, Crypt Sovereign attacks, reveal the top card of your library. If that card's converted mana cost is odd, you may cast it without paying its mana cost. Otherwise, draw a card.| From bf6d46be9de0b1973fcac6712d95c8860d1b5ddc Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 16:50:29 -0400 Subject: [PATCH 37/71] Implemented Entreat the Dead --- .../src/mage/cards/e/EntreatTheDead.java | 59 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 60 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EntreatTheDead.java diff --git a/Mage.Sets/src/mage/cards/e/EntreatTheDead.java b/Mage.Sets/src/mage/cards/e/EntreatTheDead.java new file mode 100644 index 00000000000..86d76b7b4a5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EntreatTheDead.java @@ -0,0 +1,59 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.keyword.MiracleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.target.Target; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author TheElk801 + */ +public final class EntreatTheDead extends CardImpl { + + public EntreatTheDead(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{B}{B}{B}"); + + // Return X target creature cards from your graveyard to the battlefield. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(1, StaticFilters.FILTER_CARD_CREATURE)); + + // Miracle {X}{B}{B} + this.addAbility(new MiracleAbility(this, new ManaCostsImpl("{X}{B}{B}"))); + + } + + @Override + public void adjustTargets(Ability ability, Game game) { + if (ability instanceof SpellAbility) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + String filterName = xValue + + (xValue != 1 ? " creature cards" : "creature card") + + " from your graveyard"; + Target target = new TargetCardInYourGraveyard( + xValue, new FilterCreatureCard(filterName) + ); + ability.addTarget(target); + } + } + + public EntreatTheDead(final EntreatTheDead card) { + super(card); + } + + @Override + public EntreatTheDead copy() { + return new EntreatTheDead(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index b1c376ff9a4..7570126c058 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -37,6 +37,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Empyrial Storm", 2, Rarity.RARE, mage.cards.e.EmpyrialStorm.class)); cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); cards.add(new SetCardInfo("Enchantress's Presence", 141, Rarity.RARE, mage.cards.e.EnchantresssPresence.class)); + cards.add(new SetCardInfo("Entreat the Dead", 15, Rarity.RARE, mage.cards.e.EntreatTheDead.class)); cards.add(new SetCardInfo("Estrid's Invocation", 8, Rarity.RARE, mage.cards.e.EstridsInvocation.class)); cards.add(new SetCardInfo("Explosive Vegetation", 144, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); cards.add(new SetCardInfo("Finest Hour", 180, Rarity.RARE, mage.cards.f.FinestHour.class)); From fa9e500329f2de27f3bf0ece0d367030b4d91edd Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 16:54:55 -0400 Subject: [PATCH 38/71] Implemented Night Incarnate --- .../src/mage/cards/n/NightIncarnate.java | 49 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 50 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/n/NightIncarnate.java diff --git a/Mage.Sets/src/mage/cards/n/NightIncarnate.java b/Mage.Sets/src/mage/cards/n/NightIncarnate.java new file mode 100644 index 00000000000..e4cac134219 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NightIncarnate.java @@ -0,0 +1,49 @@ +package mage.cards.n; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.constants.SubType; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.EvokeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; + +/** + * + * @author TheElk801 + */ +public final class NightIncarnate extends CardImpl { + + public NightIncarnate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // When Night Incarnate leaves the battlefield, all creatures get -3/-3 until end of turn. + this.addAbility(new LeavesBattlefieldTriggeredAbility( + new BoostAllEffect(-3, -3, Duration.EndOfTurn), false + )); + + // Evoke {3}{B} + this.addAbility(new EvokeAbility(this, "{3}{B}")); + + } + + public NightIncarnate(final NightIncarnate card) { + super(card); + } + + @Override + public NightIncarnate copy() { + return new NightIncarnate(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 7570126c058..6d30b0daa0d 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -55,6 +55,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); cards.add(new SetCardInfo("Nesting Dragon", 24, Rarity.RARE, mage.cards.n.NestingDragon.class)); + cards.add(new SetCardInfo("Night Incarnate", 17, Rarity.RARE, mage.cards.n.NightIncarnate.class)); cards.add(new SetCardInfo("Nylea's Colossus", 33, Rarity.RARE, mage.cards.n.NyleasColossus.class)); cards.add(new SetCardInfo("Octopus Umbra", 11, Rarity.RARE, mage.cards.o.OctopusUmbra.class)); cards.add(new SetCardInfo("Phyrexian Delver", 115, Rarity.RARE, mage.cards.p.PhyrexianDelver.class)); From 4779b86da88bd172f5282dfe52d2ddff7049fc8c Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 17:02:13 -0400 Subject: [PATCH 39/71] Implemented Magus of the Balance --- Mage.Sets/src/mage/cards/b/Balance.java | 8 +- .../src/mage/cards/m/MagusOfTheBalance.java | 199 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 3 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/m/MagusOfTheBalance.java diff --git a/Mage.Sets/src/mage/cards/b/Balance.java b/Mage.Sets/src/mage/cards/b/Balance.java index f89d8499531..279a020a109 100644 --- a/Mage.Sets/src/mage/cards/b/Balance.java +++ b/Mage.Sets/src/mage/cards/b/Balance.java @@ -1,4 +1,3 @@ - package mage.cards.b; import mage.abilities.Ability; @@ -26,7 +25,7 @@ import java.util.UUID; public final class Balance extends CardImpl { public Balance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}"); // Each player chooses a number of lands he or she controls equal to the number of lands controlled by the player who controls the fewest, then sacrifices the rest. Players discard cards and sacrifice creatures the same way. this.getSpellAbility().addEffect(new BalanceEffect()); @@ -46,7 +45,10 @@ class BalanceEffect extends OneShotEffect { BalanceEffect() { super(Outcome.Sacrifice); - staticText = "Each player chooses a number of lands he or she controls equal to the number of lands controlled by the player who controls the fewest, then sacrifices the rest. Players sacrifice creatures and discard cards the same way"; + staticText = "each player chooses a number of lands they control " + + "equal to the number of lands controlled by the player " + + "who controls the fewest, then sacrifices the rest. " + + "Players discard cards and sacrifice creatures the same way"; } BalanceEffect(final BalanceEffect effect) { diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheBalance.java b/Mage.Sets/src/mage/cards/m/MagusOfTheBalance.java new file mode 100644 index 00000000000..49a0aba1f41 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheBalance.java @@ -0,0 +1,199 @@ +package mage.cards.m; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledLandPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author TheElk801 + */ +public final class MagusOfTheBalance extends CardImpl { + + public MagusOfTheBalance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {4}{W}, {T}, Sacrifice Magus of the Balance: Each player chooses a number of lands they control equal to the number of lands controlled by the player who controls the fewest, then sacrifices the rest. Players discard cards and sacrifice creatures the same way. + Ability ability = new SimpleActivatedAbility( + new MagusOfTheBalanceEffect(), + new ManaCostsImpl("{4}{W}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public MagusOfTheBalance(final MagusOfTheBalance card) { + super(card); + } + + @Override + public MagusOfTheBalance copy() { + return new MagusOfTheBalance(this); + } +} + +class MagusOfTheBalanceEffect extends OneShotEffect { + + MagusOfTheBalanceEffect() { + super(Outcome.Sacrifice); + staticText = "each player chooses a number of lands they control " + + "equal to the number of lands controlled by the player " + + "who controls the fewest, then sacrifices the rest. " + + "Players discard cards and sacrifice creatures the same way"; + } + + MagusOfTheBalanceEffect(final MagusOfTheBalanceEffect effect) { + super(effect); + } + + @Override + public MagusOfTheBalanceEffect copy() { + return new MagusOfTheBalanceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + //Lands + int minLand = Integer.MAX_VALUE; + Cards landsToSacrifice = new CardsImpl(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int count = game.getBattlefield().countAll(new FilterControlledLandPermanent(), player.getId(), game); + if (count < minLand) { + minLand = count; + } + } + } + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + TargetControlledPermanent target = new TargetControlledPermanent(minLand, minLand, new FilterControlledLandPermanent("lands to keep"), true); + if (target.choose(Outcome.Sacrifice, player.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledLandPermanent(), player.getId(), source.getSourceId(), game)) { + if (permanent != null && !target.getTargets().contains(permanent.getId())) { + landsToSacrifice.add(permanent); + } + } + } + } + } + + for (UUID cardId : landsToSacrifice) { + Permanent permanent = game.getPermanent(cardId); + if (permanent != null) { + permanent.sacrifice(source.getSourceId(), game); + } + } + + //Creatures + int minCreature = Integer.MAX_VALUE; + Cards creaturesToSacrifice = new CardsImpl(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int count = game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), player.getId(), game); + if (count < minCreature) { + minCreature = count; + } + } + } + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + TargetControlledPermanent target = new TargetControlledPermanent(minCreature, minCreature, new FilterControlledCreaturePermanent("creatures to keep"), true); + if (target.choose(Outcome.Sacrifice, player.getId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), player.getId(), source.getSourceId(), game)) { + if (permanent != null && !target.getTargets().contains(permanent.getId())) { + creaturesToSacrifice.add(permanent); + } + } + } + } + } + + for (UUID cardId : creaturesToSacrifice) { + Permanent permanent = game.getPermanent(cardId); + if (permanent != null) { + permanent.sacrifice(source.getSourceId(), game); + } + } + + //Cards in hand + int minCard = Integer.MAX_VALUE; + Map cardsToDiscard = new HashMap<>(2); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int count = player.getHand().size(); + if (count < minCard) { + minCard = count; + } + } + } + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + Cards cards = new CardsImpl(); + TargetCardInHand target = new TargetCardInHand(minCard, new FilterCard("cards to keep")); + if (target.choose(Outcome.Discard, player.getId(), source.getSourceId(), game)) { + for (Card card : player.getHand().getCards(game)) { + if (card != null && !target.getTargets().contains(card.getId())) { + cards.add(card); + } + } + cardsToDiscard.put(playerId, cards); + } + } + } + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null && cardsToDiscard.get(playerId) != null) { + for (UUID cardId : cardsToDiscard.get(playerId)) { + Card card = game.getCard(cardId); + if (card != null) { + player.discard(card, source, game); + } + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 6d30b0daa0d..c6bf42af141 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -54,6 +54,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); + cards.add(new SetCardInfo("Magus of the Balance", 5, Rarity.RARE, mage.cards.m.MagusOfTheBalance.class)); cards.add(new SetCardInfo("Nesting Dragon", 24, Rarity.RARE, mage.cards.n.NestingDragon.class)); cards.add(new SetCardInfo("Night Incarnate", 17, Rarity.RARE, mage.cards.n.NightIncarnate.class)); cards.add(new SetCardInfo("Nylea's Colossus", 33, Rarity.RARE, mage.cards.n.NyleasColossus.class)); From 660d9ec8c3fcd390cc9de10ad5600cc1290869af Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 17:14:05 -0400 Subject: [PATCH 40/71] Implemented Loyal Unicorn --- Mage.Sets/src/mage/cards/l/LoyalUnicorn.java | 66 ++++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 67 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/l/LoyalUnicorn.java diff --git a/Mage.Sets/src/mage/cards/l/LoyalUnicorn.java b/Mage.Sets/src/mage/cards/l/LoyalUnicorn.java new file mode 100644 index 00000000000..40b8aec51e1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LoyalUnicorn.java @@ -0,0 +1,66 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.condition.common.CommanderInPlayCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.PreventAllDamageToAllEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.constants.SubType; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.filter.StaticFilters; + +/** + * + * @author TheElk801 + */ +public final class LoyalUnicorn extends CardImpl { + + public LoyalUnicorn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.UNICORN); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Lieutenant — At the beginning of combat on your turn, if you control your commander, prevent all combat damage that would be dealt to creatures you control this turn. Other creatures you control gain vigilance until end of turn. + TriggeredAbility ability = new BeginningOfCombatTriggeredAbility( + new PreventAllDamageToAllEffect( + Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURES, + true + ), TargetController.YOU, false + ); + ability.addEffect(new GainAbilityAllEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_CONTROLLED_CREATURES, true + )); + this.addAbility(new ConditionalTriggeredAbility( + ability, CommanderInPlayCondition.instance, + "Lieutenant — At the beginning of combat " + + "on your turn, if you control your commander, " + + "prevent all combat damage that would be dealt " + + "to creatures you control this turn. " + + "Other creatures you control gain vigilance until end of turn." + )); + } + + public LoyalUnicorn(final LoyalUnicorn card) { + super(card); + } + + @Override + public LoyalUnicorn copy() { + return new LoyalUnicorn(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index c6bf42af141..fac7c03749c 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -54,6 +54,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); + cards.add(new SetCardInfo("Loyal Unicorn", 4, Rarity.UNCOMMON, mage.cards.l.LoyalUnicorn.class)); cards.add(new SetCardInfo("Magus of the Balance", 5, Rarity.RARE, mage.cards.m.MagusOfTheBalance.class)); cards.add(new SetCardInfo("Nesting Dragon", 24, Rarity.RARE, mage.cards.n.NestingDragon.class)); cards.add(new SetCardInfo("Night Incarnate", 17, Rarity.RARE, mage.cards.n.NightIncarnate.class)); From e39dbacc8b71f414a9ae063ff141d86b06ab04b4 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 20:57:04 -0400 Subject: [PATCH 41/71] updated C18 spoiler --- Mage.Sets/src/mage/sets/Commander2018.java | 9 +++++++++ Utils/mtg-cards-data.txt | 12 +++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index fac7c03749c..03b97a4a6b5 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -24,12 +24,16 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Avenger of Zendikar", 129, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class)); cards.add(new SetCardInfo("Bear Umbra", 131, Rarity.RARE, mage.cards.b.BearUmbra.class)); cards.add(new SetCardInfo("Bloodtracker", 14, Rarity.RARE, mage.cards.b.Bloodtracker.class)); + cards.add(new SetCardInfo("Brainstorm", 82, Rarity.UNCOMMON, mage.cards.b.Brainstorm.class)); cards.add(new SetCardInfo("Bruna, Light of Alabaster", 170, Rarity.MYTHIC, mage.cards.b.BrunaLightOfAlabaster.class)); cards.add(new SetCardInfo("Budoka Gardener", 134, Rarity.RARE, mage.cards.b.BudokaGardener.class)); cards.add(new SetCardInfo("Centaur Vinecrasher", 135, Rarity.RARE, mage.cards.c.CentaurVinecrasher.class)); cards.add(new SetCardInfo("Chain Reaction", 121, Rarity.RARE, mage.cards.c.ChainReaction.class)); cards.add(new SetCardInfo("Chaos Warp", 122, Rarity.RARE, mage.cards.c.ChaosWarp.class)); + cards.add(new SetCardInfo("Command Tower", 240, Rarity.COMMON, mage.cards.c.CommandTower.class)); + cards.add(new SetCardInfo("Commander's Sphere", 200, Rarity.COMMON, mage.cards.c.CommandersSphere.class)); cards.add(new SetCardInfo("Crash of Rhino Beetles", 29, Rarity.RARE, mage.cards.c.CrashOfRhinoBeetles.class)); + cards.add(new SetCardInfo("Crystal Ball", 201, Rarity.UNCOMMON, mage.cards.c.CrystalBall.class)); cards.add(new SetCardInfo("Dictate of Kruphix", 86, Rarity.RARE, mage.cards.d.DictateOfKruphix.class)); cards.add(new SetCardInfo("Echo Storm", 7, Rarity.RARE, mage.cards.e.EchoStorm.class)); cards.add(new SetCardInfo("Eel Umbra", 89, Rarity.COMMON, mage.cards.e.EelUmbra.class)); @@ -56,6 +60,8 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); cards.add(new SetCardInfo("Loyal Unicorn", 4, Rarity.UNCOMMON, mage.cards.l.LoyalUnicorn.class)); cards.add(new SetCardInfo("Magus of the Balance", 5, Rarity.RARE, mage.cards.m.MagusOfTheBalance.class)); + cards.add(new SetCardInfo("Mountain Valley", 268, Rarity.UNCOMMON, mage.cards.m.MountainValley.class)); + cards.add(new SetCardInfo("Myriad Landscape", 269, Rarity.UNCOMMON, mage.cards.m.MyriadLandscape.class)); cards.add(new SetCardInfo("Nesting Dragon", 24, Rarity.RARE, mage.cards.n.NestingDragon.class)); cards.add(new SetCardInfo("Night Incarnate", 17, Rarity.RARE, mage.cards.n.NightIncarnate.class)); cards.add(new SetCardInfo("Nylea's Colossus", 33, Rarity.RARE, mage.cards.n.NyleasColossus.class)); @@ -66,11 +72,14 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Rampaging Baloths", 158, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); cards.add(new SetCardInfo("Ravenous Slime", 34, Rarity.RARE, mage.cards.r.RavenousSlime.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); + cards.add(new SetCardInfo("Rocky Tar Pit", 274, Rarity.UNCOMMON, mage.cards.r.RockyTarPit.class)); cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); cards.add(new SetCardInfo("Saheeli's Directive", 26, Rarity.RARE, mage.cards.s.SaheelisDirective.class)); cards.add(new SetCardInfo("Scute Mob", 161, Rarity.RARE, mage.cards.s.ScuteMob.class)); cards.add(new SetCardInfo("Sigil of the Empty Throne", 74, Rarity.RARE, mage.cards.s.SigilOfTheEmptyThrone.class)); + cards.add(new SetCardInfo("Sol Ring", 222, Rarity.UNCOMMON, mage.cards.s.SolRing.class)); cards.add(new SetCardInfo("Spawning Grounds", 163, Rarity.RARE, mage.cards.s.SpawningGrounds.class)); + cards.add(new SetCardInfo("Swiftfoot Boots", 225, Rarity.UNCOMMON, mage.cards.s.SwiftfootBoots.class)); cards.add(new SetCardInfo("Tawnos, Urza's Apprentice", 45, Rarity.MYTHIC, mage.cards.t.TawnosUrzasApprentice.class)); cards.add(new SetCardInfo("Terminus", 77, Rarity.RARE, mage.cards.t.Terminus.class)); cards.add(new SetCardInfo("Thantis the Warweaver", 46, Rarity.MYTHIC, mage.cards.t.ThantisTheWarweaver.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index aab2ff17a1b..7199cf5e130 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33933,6 +33933,7 @@ Magus of the Balance|Commander 2018|5|R|{1}{W}|Creature - Human Wizard|2|2|{4}{W Aminatou's Augury|Commander 2018|6|R|{6}{U}{U}|Sorcery|||Exile the top eight cards of your library. You may put a land card from among them onto the battlefield. Until end of turn, for each nonland card type, you may cast a card of that type from among the exiled cards without paying its mana cost.| Echo Storm|Commander 2018|7|R|{3}{U}{U}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game. You may choose new targets for the copies.$Create a token that's a copy of target artifact.| Estrid's Invocation|Commander 2018|8|R|{2}{U}|Enchantment|||You may have Estrid's Invocation enter the battlefield as a copy of any enchantment you control, except it gains "At the beginning of your upkeep, you may exile this enchantment. If you do, return it to the battlefield under its owner's control."| +Ever-Watching Threshold|Commander 2018|9|R|{2}{U}|Enchantment|||Whenever an opponent attacks you and/or a planeswalker you control with one or more creatures, draw a card.| Loyal Drake|Commander 2018|10|U|{2}{U}|Creature - Drake|2|2|Flying$Lieutenant — At the beginning of combat on your turn, if you control your commander, draw a card.| Octopus Umbra|Commander 2018|11|R|{3}{U}{U}|Enchantment - Aura|||Enchant creature$Enchanted creature has base power and toughness 8/8 and has "Whenever this creature attacks, you may tap target creature with power 8 or less."$Totem armor| Primordial Mist|Commander 2018|12|R|{4}{U}|Enchantment|||At the beginning of your end step, you may manifest the top card of your library.| @@ -33986,6 +33987,7 @@ Isolated Watchtower|Commander 2018|59|R||Land|||{T}: Add {C}.${2}, {T}: Scry 1, Sigil of the Empty Throne|Commander 2018|74|R|{3}{W}{W}|Enchantment|||Whenever you cast an enchantment spell, create a 4/4 white Angel creature token with flying.| Terminus|Commander 2018|77|R|{4}{W}{W}|Sorcery|||Put all creatures on the bottom of their owners' libraries.$Miracle {W}| Winds of Rath|Commander 2018|79|R|{3}{W}{W}|Sorcery|||Destroy all creatures that aren't enchanted. They can't be regenerated.| +Brainstorm|Commander 2018|82|U|{U}|Instant|||Draw three cards, then put two cards from your hand on top of your library in any order.| Dictate of Kruphix|Commander 2018|86|R|{1}{U}{U}|Enchantment|||Flash$At the beginning of each player's draw step, that player draws an additional card.| Eel Umbra|Commander 2018|89|C|{1}{U}|Enchantment - Aura|||Flash| Portent|Commander 2018|97|C|{U}|Sorcery|||Look at the top three cards of target player's library, then put them back in any order. You may have that player shuffle their library.$Draw a card at the beginning of the next turn's upkeep.| @@ -34008,4 +34010,12 @@ Rampaging Baloths|Commander 2018|158|R|{4}{G}{G}|Creature - Beast|6|6|Trample$La Scute Mob|Commander 2018|161|R|{G}|Creature - Insect|1|1|At the beginning of your upkeep, if you control five or more lands, put four +1/+1 counters on Scute Mob.| Spawning Grounds|Commander 2018|163|R|{6}{G}{G}|Enchantment - Aura|||Enchant land$Enchanted land has "{T}: Create a 5/5 green Beast creature token with trample."| Bruna, Light of Alabaster|Commander 2018|170|M|{3}{W}{W}{U}|Legendary Creature - Angel|5|5|Flying, vigilance$Whenever Bruna, Light of Alabaster attacks or blocks, you may attach to it any number of Auras on the battlefield and you may put onto the battlefield attached to it any number of Aura cards that could enchant it from your graveyard and/or hand.| -Finest Hour|Commander 2018|180|R|{2}{G}{W}{U}|Enchantment|||Exalted$Whenever a creature you control attacks alone, if it's the first combat phase of the turn, untap that creature. After this phase, there is an additional combat phase.| \ No newline at end of file +Finest Hour|Commander 2018|180|R|{2}{G}{W}{U}|Enchantment|||Exalted$Whenever a creature you control attacks alone, if it's the first combat phase of the turn, untap that creature. After this phase, there is an additional combat phase.| +Commander's Sphere|Commander 2018|200|C|{3}|Artifact|||{T}: Add one mana of any color in your commander's color identity.$Sacrifice Commander's Sphere: Draw a card.| +Crystal Ball|Commander 2018|201|U|{3}|Artifact|||{1}, {T}: Scry 2.| +Sol Ring|Commander 2018|222|U|{1}|Artifact|||{T}: Add {C}{C}.| +Swiftfoot Boots|Commander 2018|225|U|{2}|Artifact - Equipment|||Equipped creature has hexproof and haste.$Equip {1}| +Command Tower|Commander 2018|240|C||Land|||{T}: Add one mana of any color in your commander's color identity.| +Mountain Valley|Commander 2018|268|U||Land|||Mountain Valley enters the battlefield tapped.${T}, Sacrifice Mountain Valley: Search your library for a Mountain or Forest card and put it onto the battlefield. Then shuffle your library.| +Myriad Landscape|Commander 2018|269|U||Land|||Myriad Landscape enters the battlefield tapped.${T}: Add {C}.${2}, {T}, Sacrifice Myriad Landscape: Search your library for up to two basic land cards that share a land type, put them onto the battlefield tapped, then shuffle your library.| +Rocky Tar Pit|Commander 2018|274|U||Land|||Rocky Tar Pit enters the battlefield tapped.${T}, Sacrifice Rocky Tar Pit: Search your library for a Swamp or Mountain card and put it onto the battlefield. Then shuffle your library.| \ No newline at end of file From 2d027dbacd570b818eaae4aa9f341adb9cf9cce1 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 21:16:29 -0400 Subject: [PATCH 42/71] Implemented Varina, Lich Queen --- .../src/mage/cards/v/VarinaLichQueen.java | 117 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 118 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/v/VarinaLichQueen.java diff --git a/Mage.Sets/src/mage/cards/v/VarinaLichQueen.java b/Mage.Sets/src/mage/cards/v/VarinaLichQueen.java new file mode 100644 index 00000000000..514473cd7be --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VarinaLichQueen.java @@ -0,0 +1,117 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.ExileFromGraveCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.ZombieToken; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author TheElk801 + */ +public final class VarinaLichQueen extends CardImpl { + + public VarinaLichQueen(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever you attack with one or more Zombies, draw that many cards, then discard that many cards. You gain that much life. + this.addAbility(new VarinaLichQueenTriggeredAbility()); + + // {2}, Exile two cards from your graveyard: Create a tapped 2/2 black Zombie creature token. + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new CreateTokenEffect( + new ZombieToken(), + 1, true, false + ), new GenericManaCost(2) + ); + ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard( + 2, new FilterCard("cards from your graveyard") + ))); + this.addAbility(ability); + } + + public VarinaLichQueen(final VarinaLichQueen card) { + super(card); + } + + @Override + public VarinaLichQueen copy() { + return new VarinaLichQueen(this); + } +} + +class VarinaLichQueenTriggeredAbility extends TriggeredAbilityImpl { + + public VarinaLichQueenTriggeredAbility() { + super(Zone.BATTLEFIELD, null, false); + } + + public VarinaLichQueenTriggeredAbility(final VarinaLichQueenTriggeredAbility ability) { + super(ability); + } + + @Override + public VarinaLichQueenTriggeredAbility copy() { + return new VarinaLichQueenTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + int attackingZombies = 0; + for (UUID attacker : game.getCombat().getAttackers()) { + Permanent creature = game.getPermanent(attacker); + if (creature != null + && creature.getControllerId() != null + && creature.isControlledBy(this.getControllerId()) + && creature.hasSubtype(SubType.ZOMBIE, game)) { + attackingZombies++; + } + } + if (attackingZombies > 0) { + this.getEffects().clear(); + addEffect(new DrawCardSourceControllerEffect(attackingZombies)); + addEffect(new DiscardControllerEffect(attackingZombies, false)); + addEffect(new GainLifeEffect(attackingZombies)); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever you attack with one or more Zombies, " + + "draw that many cards, then discard that many cards. " + + "You gain that much life."; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 03b97a4a6b5..0cccc5fb386 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -87,6 +87,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Turntimber Sower", 35, Rarity.RARE, mage.cards.t.TurntimberSower.class)); cards.add(new SetCardInfo("Tuvasa the Sunlit", 47, Rarity.MYTHIC, mage.cards.t.TuvasaTheSunlit.class)); cards.add(new SetCardInfo("Varchild, Betrayer of Kjeldor", 28, Rarity.RARE, mage.cards.v.VarchildBetrayerOfKjeldor.class)); + cards.add(new SetCardInfo("Varina, Lich Queen", 48, Rarity.MYTHIC, mage.cards.v.VarinaLichQueen.class)); cards.add(new SetCardInfo("Whiptongue Hydra", 36, Rarity.RARE, mage.cards.w.WhiptongueHydra.class)); cards.add(new SetCardInfo("Winds of Rath", 79, Rarity.RARE, mage.cards.w.WindsOfRath.class)); } From 14a688008f64e5508bd1a342660db2715135d307 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 26 Jul 2018 21:41:58 -0400 Subject: [PATCH 43/71] Implemented Yennet, Crypt Sovereign --- .../mage/cards/y/YennetCryptSovereign.java | 101 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 102 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/y/YennetCryptSovereign.java diff --git a/Mage.Sets/src/mage/cards/y/YennetCryptSovereign.java b/Mage.Sets/src/mage/cards/y/YennetCryptSovereign.java new file mode 100644 index 00000000000..59b7e84f17f --- /dev/null +++ b/Mage.Sets/src/mage/cards/y/YennetCryptSovereign.java @@ -0,0 +1,101 @@ +package mage.cards.y; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author TheElk801 + */ +public final class YennetCryptSovereign extends CardImpl { + + public YennetCryptSovereign(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SPHINX); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Menace + this.addAbility(new MenaceAbility()); + + // Whenever Yennet, Crypt Sovereign attacks, reveal the top card of your library. If that card's converted mana cost is odd, you may cast it without paying its mana cost. Otherwise, draw a card. + this.addAbility(new AttacksTriggeredAbility( + new YennetCryptSovereignEffect(), false + )); + } + + public YennetCryptSovereign(final YennetCryptSovereign card) { + super(card); + } + + @Override + public YennetCryptSovereign copy() { + return new YennetCryptSovereign(this); + } +} + +class YennetCryptSovereignEffect extends OneShotEffect { + + public YennetCryptSovereignEffect() { + super(Outcome.Benefit); + this.staticText = "reveal the top card of your library. " + + "If that card's converted mana cost is odd, " + + "you may cast it without paying its mana cost. " + + "Otherwise, draw a card"; + } + + public YennetCryptSovereignEffect(final YennetCryptSovereignEffect effect) { + super(effect); + } + + @Override + public YennetCryptSovereignEffect copy() { + return new YennetCryptSovereignEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null || !player.getLibrary().hasCards()) { + return false; + } + Card card = player.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + player.revealCards(source, new CardsImpl(card), game); + if (card.getConvertedManaCost() % 2 == 1) { + if (player.chooseUse(outcome, "Cast " + card.getLogName() + " without paying its mana cost?", source, game)) { + player.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + } + } else { + player.drawCards(1, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 0cccc5fb386..a3adae9eb3e 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -90,5 +90,6 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Varina, Lich Queen", 48, Rarity.MYTHIC, mage.cards.v.VarinaLichQueen.class)); cards.add(new SetCardInfo("Whiptongue Hydra", 36, Rarity.RARE, mage.cards.w.WhiptongueHydra.class)); cards.add(new SetCardInfo("Winds of Rath", 79, Rarity.RARE, mage.cards.w.WindsOfRath.class)); + cards.add(new SetCardInfo("Yennet, Crypt Sovereign", 51, Rarity.MYTHIC, mage.cards.y.YennetCryptSovereign.class)); } } From f58e33524dd6433439a91e8410bc2d18e6cd900c Mon Sep 17 00:00:00 2001 From: spjspj Date: Fri, 27 Jul 2018 18:53:34 +1000 Subject: [PATCH 44/71] Implement 1 card C18 --- .../src/main/resources/card-pictures-tok.txt | 1 + .../cards/a/ArixmethesSlumberingIsle.java | 121 ++++++++++++++++++ .../cards/b/BrudicladTelchorEngineer.java | 113 ++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 2 + .../main/java/mage/counters/CounterType.java | 1 + .../token/BrudicladTelchorMyrToken.java | 43 +++++++ 6 files changed, 281 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/a/ArixmethesSlumberingIsle.java create mode 100644 Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java create mode 100644 Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java diff --git a/Mage.Client/src/main/resources/card-pictures-tok.txt b/Mage.Client/src/main/resources/card-pictures-tok.txt index 664b4d79c31..05988555120 100644 --- a/Mage.Client/src/main/resources/card-pictures-tok.txt +++ b/Mage.Client/src/main/resources/card-pictures-tok.txt @@ -357,6 +357,7 @@ |Generate|TOK:C17|Rat|||DeathtouchRatToken| |Generate|TOK:C17|Vampire|||EdgarMarkovToken| |Generate|TOK:C17|Zombie|| +|Generate|TOK:C18|Myr|||BrudicladTelchorMyrToken| |Generate|TOK:CHK|Dragon Spirit|||TatsumaDragonToken| |Generate|TOK:CHK|Elemental|||SeedGuardianToken| |Generate|TOK:CHK|Illusion|||MelokuTheCloudedMirrorToken| diff --git a/Mage.Sets/src/mage/cards/a/ArixmethesSlumberingIsle.java b/Mage.Sets/src/mage/cards/a/ArixmethesSlumberingIsle.java new file mode 100644 index 00000000000..3c6578b392a --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArixmethesSlumberingIsle.java @@ -0,0 +1,121 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import static mage.constants.Layer.TypeChangingEffects_4; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterSpell; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author spjspj + */ +public final class ArixmethesSlumberingIsle extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a spell"); + + public ArixmethesSlumberingIsle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); + + addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.KRAKEN); + this.power = new MageInt(12); + this.toughness = new MageInt(12); + + // Arixmethes, Slumbering Isle enters the battlefield tapped with five slumber counters on it. + this.addAbility(new EntersBattlefieldTappedAbility()); + Effect effect = new AddCountersSourceEffect(CounterType.SLUMBER.createInstance(5)); + this.addAbility(new EntersBattlefieldAbility(effect, "with five slumber counters")); + + // As long as Arixmethes, Slumbering Isle has a slumber counter on it, it's a land. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( + new ArixmethesIsLandEffect(), + new SourceHasCounterCondition(CounterType.SLUMBER, 1, Integer.MAX_VALUE), + "As long as {this} has a slumber counter on it, it's a land"))); + + // Whenever you cast a spell, you may remove a slumber counter from Arixmethes. + this.addAbility(new SpellCastControllerTriggeredAbility(new RemoveCounterSourceEffect(CounterType.SLUMBER.createInstance(1)), true)); + + // {T}: Add {G}{U}. + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 1, 0, 0, 0, 0, 0), new TapSourceCost())); + } + + public ArixmethesSlumberingIsle(final ArixmethesSlumberingIsle card) { + super(card); + } + + @Override + public ArixmethesSlumberingIsle copy() { + return new ArixmethesSlumberingIsle(this); + } +} + +class ArixmethesIsLandEffect extends ContinuousEffectImpl { + + public ArixmethesIsLandEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + this.staticText = "As long as {this} has a slumber counter on it, it's a land"; + } + + public ArixmethesIsLandEffect(final ArixmethesIsLandEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public ArixmethesIsLandEffect copy() { + return new ArixmethesIsLandEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = game.getPermanent(source.getSourceId()); + + if (permanent != null) { + switch (layer) { + case TypeChangingEffects_4: + permanent.getCardType().clear(); + permanent.addCardType(CardType.LAND); + permanent.getSubtype(game).clear(); + break; + } + return true; + } + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.TypeChangingEffects_4; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java b/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java new file mode 100644 index 00000000000..6da9effd66a --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java @@ -0,0 +1,113 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.BrudicladTelchorMyrToken; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; +import mage.util.functions.EmptyApplyToPermanent; + +/** + * + * @author spjspj + */ +public final class BrudicladTelchorEngineer extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature tokens you control"); + + static { + filter.add(new TokenPredicate()); + } + + public BrudicladTelchorEngineer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{U}{R}"); + + addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ARTIFICER); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Creature tokens you control have haste. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield, filter, true))); + + // At the beginning of combat on your turn, create a 2/1 blue Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token. + this.addAbility(new BeginningOfCombatTriggeredAbility(new BrudicladTelchorCombatffect(), TargetController.YOU, false)); + } + + public BrudicladTelchorEngineer(final BrudicladTelchorEngineer card) { + super(card); + } + + @Override + public BrudicladTelchorEngineer copy() { + return new BrudicladTelchorEngineer(this); + } +} + +class BrudicladTelchorCombatffect extends OneShotEffect { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(" token you control. If you do, each other token you control becomes a copy of that token"); + + static { + filter.add(new TokenPredicate()); + } + + public BrudicladTelchorCombatffect() { + super(Outcome.Sacrifice); + this.staticText = " you may choose a token you control. If you do, each other token you control becomes a copy of that token"; + } + + public BrudicladTelchorCombatffect(final BrudicladTelchorCombatffect effect) { + super(effect); + } + + @Override + public BrudicladTelchorCombatffect copy() { + return new BrudicladTelchorCombatffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + CreateTokenEffect effect = new CreateTokenEffect(new BrudicladTelchorMyrToken(), 1); + + if (effect.apply(game, source)) { + TargetControlledPermanent target = new TargetControlledPermanent(0, 1, filter, true); + target.setNotTarget(true); + if (controller.choose(Outcome.Neutral, target, source.getSourceId(), game)) { + Permanent toCopyFromPermanent = game.getPermanent(target.getFirstTarget()); + + if (toCopyFromPermanent != null) { + for (Permanent toCopyToPermanent : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { + if (!toCopyToPermanent.equals(toCopyFromPermanent)) { + game.copyPermanent(toCopyFromPermanent, toCopyToPermanent.getId(), source, new EmptyApplyToPermanent()); + } + } + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index a3adae9eb3e..9928286208d 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -21,10 +21,12 @@ public final class Commander2018 extends ExpansionSet { this.blockName = "Command Zone"; cards.add(new SetCardInfo("Ancient Stone Idol", 53, Rarity.RARE, mage.cards.a.AncientStoneIdol.class)); + cards.add(new SetCardInfo("Arixmethes, Slumbering Isle", 38, Rarity.RARE, mage.cards.a.ArixmethesSlumberingIsle.class)); cards.add(new SetCardInfo("Avenger of Zendikar", 129, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class)); cards.add(new SetCardInfo("Bear Umbra", 131, Rarity.RARE, mage.cards.b.BearUmbra.class)); cards.add(new SetCardInfo("Bloodtracker", 14, Rarity.RARE, mage.cards.b.Bloodtracker.class)); cards.add(new SetCardInfo("Brainstorm", 82, Rarity.UNCOMMON, mage.cards.b.Brainstorm.class)); + cards.add(new SetCardInfo("Brudiclad, Telchor Engineer", 39, Rarity.MYTHIC, mage.cards.b.BrudicladTelchorEngineer.class)); cards.add(new SetCardInfo("Bruna, Light of Alabaster", 170, Rarity.MYTHIC, mage.cards.b.BrunaLightOfAlabaster.class)); cards.add(new SetCardInfo("Budoka Gardener", 134, Rarity.RARE, mage.cards.b.BudokaGardener.class)); cards.add(new SetCardInfo("Centaur Vinecrasher", 135, Rarity.RARE, mage.cards.c.CentaurVinecrasher.class)); diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index 7b3dc6ae5fd..2ded9a796bc 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -106,6 +106,7 @@ public enum CounterType { SHIELD("shield"), SHRED("shred"), SLIME("slime"), + SLUMBER("slumber"), SOOT("soot"), SPITE("spite"), SPORE("spore"), diff --git a/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java b/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java new file mode 100644 index 00000000000..33de29d06fa --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java @@ -0,0 +1,43 @@ +package mage.game.permanent.token; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +public final class BrudicladTelchorMyrToken extends TokenImpl { + + final static private List tokenImageSets = new ArrayList<>(); + + static { + tokenImageSets.addAll(Arrays.asList("C18")); + } + + public BrudicladTelchorMyrToken() { + this((String)null); + } + + public BrudicladTelchorMyrToken(String expansionSetCode) { + super("Myr", "2/1 blue Myr artifact creature token"); + this.setOriginalExpansionSetCode(expansionSetCode); + cardType.add(CardType.CREATURE); + cardType.add(CardType.ARTIFACT); + subtype.add(SubType.MYR); + color.setBlue(true); + power = new MageInt(2); + toughness = new MageInt(1); + + availableImageSetCodes = tokenImageSets; + } + + public BrudicladTelchorMyrToken(final BrudicladTelchorMyrToken token) { + super(token); + } + + public BrudicladTelchorMyrToken copy() { + return new BrudicladTelchorMyrToken(this); + } +} From e563e1338a73e395ca2ea22e3ca38944a020bb30 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 27 Jul 2018 08:33:38 -0400 Subject: [PATCH 45/71] updated C18 spoiler --- Mage.Sets/src/mage/sets/Commander2018.java | 6 ++++++ Utils/mtg-cards-data.txt | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 9928286208d..bb6d3652094 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -20,9 +20,11 @@ public final class Commander2018 extends ExpansionSet { super("Commander 2018 Edition", "C18", ExpansionSet.buildDate(2018, 8, 10), SetType.SUPPLEMENTAL); this.blockName = "Command Zone"; + cards.add(new SetCardInfo("Aethermage's Touch", 168, Rarity.RARE, mage.cards.a.AethermagesTouch.class)); cards.add(new SetCardInfo("Ancient Stone Idol", 53, Rarity.RARE, mage.cards.a.AncientStoneIdol.class)); cards.add(new SetCardInfo("Arixmethes, Slumbering Isle", 38, Rarity.RARE, mage.cards.a.ArixmethesSlumberingIsle.class)); cards.add(new SetCardInfo("Avenger of Zendikar", 129, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class)); + cards.add(new SetCardInfo("Banishing Stroke", 63, Rarity.UNCOMMON, mage.cards.b.BanishingStroke.class)); cards.add(new SetCardInfo("Bear Umbra", 131, Rarity.RARE, mage.cards.b.BearUmbra.class)); cards.add(new SetCardInfo("Bloodtracker", 14, Rarity.RARE, mage.cards.b.Bloodtracker.class)); cards.add(new SetCardInfo("Brainstorm", 82, Rarity.UNCOMMON, mage.cards.b.Brainstorm.class)); @@ -32,6 +34,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Centaur Vinecrasher", 135, Rarity.RARE, mage.cards.c.CentaurVinecrasher.class)); cards.add(new SetCardInfo("Chain Reaction", 121, Rarity.RARE, mage.cards.c.ChainReaction.class)); cards.add(new SetCardInfo("Chaos Warp", 122, Rarity.RARE, mage.cards.c.ChaosWarp.class)); + cards.add(new SetCardInfo("Cloudform", 83, Rarity.UNCOMMON, mage.cards.c.Cloudform.class)); cards.add(new SetCardInfo("Command Tower", 240, Rarity.COMMON, mage.cards.c.CommandTower.class)); cards.add(new SetCardInfo("Commander's Sphere", 200, Rarity.COMMON, mage.cards.c.CommandersSphere.class)); cards.add(new SetCardInfo("Crash of Rhino Beetles", 29, Rarity.RARE, mage.cards.c.CrashOfRhinoBeetles.class)); @@ -63,6 +66,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Loyal Unicorn", 4, Rarity.UNCOMMON, mage.cards.l.LoyalUnicorn.class)); cards.add(new SetCardInfo("Magus of the Balance", 5, Rarity.RARE, mage.cards.m.MagusOfTheBalance.class)); cards.add(new SetCardInfo("Mountain Valley", 268, Rarity.UNCOMMON, mage.cards.m.MountainValley.class)); + cards.add(new SetCardInfo("Mulldrifter", 94, Rarity.UNCOMMON, mage.cards.m.Mulldrifter.class)); cards.add(new SetCardInfo("Myriad Landscape", 269, Rarity.UNCOMMON, mage.cards.m.MyriadLandscape.class)); cards.add(new SetCardInfo("Nesting Dragon", 24, Rarity.RARE, mage.cards.n.NestingDragon.class)); cards.add(new SetCardInfo("Night Incarnate", 17, Rarity.RARE, mage.cards.n.NightIncarnate.class)); @@ -78,7 +82,9 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); cards.add(new SetCardInfo("Saheeli's Directive", 26, Rarity.RARE, mage.cards.s.SaheelisDirective.class)); cards.add(new SetCardInfo("Scute Mob", 161, Rarity.RARE, mage.cards.s.ScuteMob.class)); + cards.add(new SetCardInfo("Serra Avatar", 73, Rarity.MYTHIC, mage.cards.s.SerraAvatar.class)); cards.add(new SetCardInfo("Sigil of the Empty Throne", 74, Rarity.RARE, mage.cards.s.SigilOfTheEmptyThrone.class)); + cards.add(new SetCardInfo("Silent-Blade Oni", 191, Rarity.RARE, mage.cards.s.SilentBladeOni.class)); cards.add(new SetCardInfo("Sol Ring", 222, Rarity.UNCOMMON, mage.cards.s.SolRing.class)); cards.add(new SetCardInfo("Spawning Grounds", 163, Rarity.RARE, mage.cards.s.SpawningGrounds.class)); cards.add(new SetCardInfo("Swiftfoot Boots", 225, Rarity.UNCOMMON, mage.cards.s.SwiftfootBoots.class)); diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 7199cf5e130..e46a010877f 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33984,12 +33984,16 @@ Geode Golem|Commander 2018|56|U|{5}|Artifact Creature - Golem|5|3|Trample$Whenev Retrofitter Foundry|Commander 2018|57|R|{1}|Artifact|||{3}: Untap Retrofitter Foundry.${2}, {T}: Create a 1/1 colorless Servo artifact creature token.${1}, {T}, Sacrifice a Servo: Create a 1/1 colorless Thopter artifact creature token with flying.${T}, Sacrifice a Thopter: Create a 4/4 colorless Construct artifact creature token.| Forge of Heroes|Commander 2018|58|C||Land|||{T}: Add {C}.${T}: Choose target commander that entered the battlefield this turn. Put a +1/+1 counter on it if it's a creature and a loyalty counter on it if it's a planeswalker.| Isolated Watchtower|Commander 2018|59|R||Land|||{T}: Add {C}.${2}, {T}: Scry 1, then you may reveal the top card of your library. If a basic land card is revealed this way, put it onto the battlefield tapped. Activate this ability only if an opponent controls at least two more lands than you.| +Banishing Stroke|Commander 2018|63|U|{5}{W}|Instant|||Put target artifact, creature, or enchantment on the bottom of its owner's library.$Miracle {W}| +Serra Avatar|Commander 2018|73|M|{4}{W}{W}{W}|Creature - Avatar|*|*|Serra Avatar's power and toughness are each equal to your life total.$When Serra Avatar is put into a graveyard from anywhere, shuffle it into its owner's library.| Sigil of the Empty Throne|Commander 2018|74|R|{3}{W}{W}|Enchantment|||Whenever you cast an enchantment spell, create a 4/4 white Angel creature token with flying.| Terminus|Commander 2018|77|R|{4}{W}{W}|Sorcery|||Put all creatures on the bottom of their owners' libraries.$Miracle {W}| Winds of Rath|Commander 2018|79|R|{3}{W}{W}|Sorcery|||Destroy all creatures that aren't enchanted. They can't be regenerated.| Brainstorm|Commander 2018|82|U|{U}|Instant|||Draw three cards, then put two cards from your hand on top of your library in any order.| +Cloudform|Commander 2018|83|U|{1}{U}{U}|Enchantment|||When Cloudform enters the battlefield, it becomes an Aura with enchant creature. Manifest the top card of your library and attach Cloudform to it.$Enchanted creature has flying and hexproof.| Dictate of Kruphix|Commander 2018|86|R|{1}{U}{U}|Enchantment|||Flash$At the beginning of each player's draw step, that player draws an additional card.| Eel Umbra|Commander 2018|89|C|{1}{U}|Enchantment - Aura|||Flash| +Mulldrifter|Commander 2018|94|U|{4}{U}|Creature - Elemental|2|2|Flying$When Mulldrifter enters the battlefield, draw two cards.$Evoke {2}{U}| Portent|Commander 2018|97|C|{U}|Sorcery|||Look at the top three cards of target player's library, then put them back in any order. You may have that player shuffle their library.$Draw a card at the beginning of the next turn's upkeep.| Predict|Commander 2018|98|U|{1}{U}|Instant|||Choose a card name, then target player puts the top card of their library into their graveyard. If that card has the chosen name, you draw two cards. Otherwise, you draw a card.| Thopter Spy Network|Commander 2018|107|R|{2}{U}{U}|Enchantment|||At the beginning of your upkeep, if you control an artifact, create a 1/1 colorless Thopter artifact creature token with flying.$Whenever one or more artifact creatures you control deal combat damage to a player, draw a card.| @@ -34009,8 +34013,10 @@ Hydra Omnivore|Commander 2018|153|M|{4}{G}{G}|Creature - Hydra|8|8|Whenever Hydr Rampaging Baloths|Commander 2018|158|R|{4}{G}{G}|Creature - Beast|6|6|Trample$Landfall — Whenever a land enters the battlefield under your control, you may create a 4/4 green Beast creature token.| Scute Mob|Commander 2018|161|R|{G}|Creature - Insect|1|1|At the beginning of your upkeep, if you control five or more lands, put four +1/+1 counters on Scute Mob.| Spawning Grounds|Commander 2018|163|R|{6}{G}{G}|Enchantment - Aura|||Enchant land$Enchanted land has "{T}: Create a 5/5 green Beast creature token with trample."| +Aethermage's Touch|Commander 2018|168|R|{2}{W}{U}|Instant|||Reveal the top four cards of your library. You may put a creature card from among them onto the battlefield. It gains "At the beginning of your end step, return this creature to its owner's hand." Then put the rest of the cards revealed this way on the bottom of your library in any order.| Bruna, Light of Alabaster|Commander 2018|170|M|{3}{W}{W}{U}|Legendary Creature - Angel|5|5|Flying, vigilance$Whenever Bruna, Light of Alabaster attacks or blocks, you may attach to it any number of Auras on the battlefield and you may put onto the battlefield attached to it any number of Aura cards that could enchant it from your graveyard and/or hand.| Finest Hour|Commander 2018|180|R|{2}{G}{W}{U}|Enchantment|||Exalted$Whenever a creature you control attacks alone, if it's the first combat phase of the turn, untap that creature. After this phase, there is an additional combat phase.| +Silent-Blade Oni|Commander 2018|191|R|{3}{U}{U}{B}{B}|Creature - Demon Ninja|6|5|Ninjutsu {4}{U}{B}$Whenever Silent-Blade Oni deals combat damage to a player, look at that player's hand. You may cast a nonland card in it without paying that card's mana cost.| Commander's Sphere|Commander 2018|200|C|{3}|Artifact|||{T}: Add one mana of any color in your commander's color identity.$Sacrifice Commander's Sphere: Draw a card.| Crystal Ball|Commander 2018|201|U|{3}|Artifact|||{1}, {T}: Scry 2.| Sol Ring|Commander 2018|222|U|{1}|Artifact|||{T}: Add {C}{C}.| From ba2610b1d1390743d18f985c5a463ee3f3f64286 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 27 Jul 2018 09:07:10 -0400 Subject: [PATCH 46/71] Implemented Skull Storm --- Mage.Sets/src/mage/cards/s/SkullStorm.java | 88 ++++++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 89 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SkullStorm.java diff --git a/Mage.Sets/src/mage/cards/s/SkullStorm.java b/Mage.Sets/src/mage/cards/s/SkullStorm.java new file mode 100644 index 00000000000..164cf6e3033 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkullStorm.java @@ -0,0 +1,88 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.abilities.keyword.CommanderStormAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public final class SkullStorm extends CardImpl { + + public SkullStorm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{7}{B}{B}"); + + // When you cast this spell, copy it for each time you've cast your commander from the command zone this game. + this.addAbility(new CommanderStormAbility()); + + // Each opponent sacrifices a creature. Each opponent who can't loses half their life, rounded up. + this.getSpellAbility().addEffect(new SkullStormEffect()); + } + + public SkullStorm(final SkullStorm card) { + super(card); + } + + @Override + public SkullStorm copy() { + return new SkullStorm(this); + } +} + +class SkullStormEffect extends OneShotEffect { + + public SkullStormEffect() { + super(Outcome.Benefit); + this.staticText = "Each opponent sacrifices a creature. " + + "Each opponent who can't loses half their life, rounded up."; + } + + public SkullStormEffect(final SkullStormEffect effect) { + super(effect); + } + + @Override + public SkullStormEffect copy() { + return new SkullStormEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + game.getOpponents(source.getControllerId()).forEach((playerId) -> { + Player player = game.getPlayer(playerId); + if (!(player == null)) { + FilterPermanent filter = new FilterCreaturePermanent(); + filter.add(new ControllerIdPredicate(playerId)); + if (game.getBattlefield().getActivePermanents( + filter, source.getControllerId(), game + ).isEmpty()) { + int lifeToLose = (int) Math.ceil(player.getLife() / 2); + player.loseLife(lifeToLose, game, false); + } else { + Effect effect = new SacrificeEffect( + StaticFilters.FILTER_PERMANENT_CREATURE, 1, null + ); + effect.setTargetPointer(new FixedTarget(playerId, game)); + effect.apply(game, source); + } + } + }); + return true; + } +} +//doot doot diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index bb6d3652094..c01ebfaa4e0 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -85,6 +85,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Serra Avatar", 73, Rarity.MYTHIC, mage.cards.s.SerraAvatar.class)); cards.add(new SetCardInfo("Sigil of the Empty Throne", 74, Rarity.RARE, mage.cards.s.SigilOfTheEmptyThrone.class)); cards.add(new SetCardInfo("Silent-Blade Oni", 191, Rarity.RARE, mage.cards.s.SilentBladeOni.class)); + cards.add(new SetCardInfo("Skull Storm", 18, Rarity.COMMON, mage.cards.s.SkullStorm.class)); cards.add(new SetCardInfo("Sol Ring", 222, Rarity.UNCOMMON, mage.cards.s.SolRing.class)); cards.add(new SetCardInfo("Spawning Grounds", 163, Rarity.RARE, mage.cards.s.SpawningGrounds.class)); cards.add(new SetCardInfo("Swiftfoot Boots", 225, Rarity.UNCOMMON, mage.cards.s.SwiftfootBoots.class)); From 62584601a10bdb06243774ec99b604a55718a647 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 27 Jul 2018 11:27:08 -0400 Subject: [PATCH 47/71] updated MTGO 1v1 Commander banlist --- .../src/mage/deck/MTGO1v1Commander.java | 30 ++----------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/MTGO1v1Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/MTGO1v1Commander.java index 2d1f9ffb910..1b4a1f3e083 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/MTGO1v1Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/MTGO1v1Commander.java @@ -1,4 +1,3 @@ - package mage.deck; /** @@ -10,69 +9,46 @@ public class MTGO1v1Commander extends Commander { public MTGO1v1Commander() { super("MTGO 1v1 Commander"); banned.add("Ancestral Recall"); - banned.add("Ancient Tomb"); banned.add("Back to Basics"); banned.add("Balance"); banned.add("Baral, Chief of Compliance"); banned.add("Black Lotus"); banned.add("Braids, Cabal Minion"); - banned.add("Brainstorm"); banned.add("Channel"); - banned.add("Chrome Mox"); banned.add("Derevi, Empyrial Tactician"); - banned.add("Demonic Tutor"); - banned.add("Dig Through Time"); + banned.add("Doomsday"); banned.add("Edgar Markov"); banned.add("Edric, Spymaster of Trest"); banned.add("Emrakul, the Aeons Torn"); - banned.add("Enlightened Tutor"); - banned.add("Entomb"); + banned.add("Erayo, Soratami Ascendant"); banned.add("Fastbond"); banned.add("Food Chain"); - banned.add("Gaea's Cradle"); banned.add("Gifts Ungiven"); banned.add("Hermit Druid"); banned.add("Humility"); - banned.add("Imperial Seal"); banned.add("Karakas"); banned.add("Library of Alexandria"); - banned.add("Mana Crypt"); - banned.add("Mana Drain"); - banned.add("Mana Vault"); banned.add("Mind Twist"); banned.add("Moat"); - banned.add("Mox Diamond"); banned.add("Mox Emerald"); banned.add("Mox Jet"); banned.add("Mox Pearl"); banned.add("Mox Ruby"); banned.add("Mox Sapphire"); - banned.add("Mystical Tutor"); banned.add("Natural Order"); - banned.add("Necropotence"); banned.add("Oath of Druids"); - banned.add("Ponder"); - banned.add("Preordain"); banned.add("Rofellos, Llanowar Emissary"); + banned.add("Strip Mine"); banned.add("Sensei's Divining Top"); banned.add("Serra Ascendant"); - banned.add("Sol Ring"); - banned.add("Strip Mine"); banned.add("Survival of the Fittest"); banned.add("Sylvan Library"); - banned.add("Sylvan Tutor"); banned.add("The Tabernacle at Pendrell Vale"); banned.add("Time Vault"); banned.add("Time Walk"); banned.add("Tinker"); banned.add("Tolarian Academy"); - banned.add("Treachery"); - banned.add("Treasure Cruise"); - banned.add("Vial Smasher the Fierce"); - banned.add("Vampiric Tutor"); banned.add("Winter Orb"); - banned.add("Wordly Tutor"); - banned.add("Yamgmoth's Bargain"); banned.add("Zur the Enchanter"); } } From e70b1fadbe2d7ee95c9972a2ed08a005171c0722 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 27 Jul 2018 11:38:08 -0400 Subject: [PATCH 48/71] updated MTGO 1v1 commander rules to ban partners --- .../Mage.Deck.Constructed/src/mage/deck/Commander.java | 5 ++++- .../src/mage/deck/MTGO1v1Commander.java | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index 81e4030d252..439e7bf928e 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -1,4 +1,3 @@ - package mage.deck; import java.util.*; @@ -23,6 +22,7 @@ import mage.filter.FilterMana; public class Commander extends Constructed { protected List bannedCommander = new ArrayList<>(); + protected boolean partnerAllowed = true; public Commander() { this("Commander"); @@ -105,6 +105,9 @@ public class Commander extends Constructed { } if (deck.getSideboard().size() < 1 || deck.getSideboard().size() > 2) { + if ((deck.getSideboard().size() > 1 && !partnerAllowed)) { + invalid.put("Commander", "You may only have one commander"); + } invalid.put("Commander", "Sideboard must contain only the commander(s)"); valid = false; } else { diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/MTGO1v1Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/MTGO1v1Commander.java index 1b4a1f3e083..511d0d3f0e0 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/MTGO1v1Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/MTGO1v1Commander.java @@ -8,6 +8,8 @@ public class MTGO1v1Commander extends Commander { public MTGO1v1Commander() { super("MTGO 1v1 Commander"); + partnerAllowed = false; + banned.add("Ancestral Recall"); banned.add("Back to Basics"); banned.add("Balance"); From a66df1082f0d221ede123e207b40b29a68c30544 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 27 Jul 2018 11:56:44 -0400 Subject: [PATCH 49/71] Implemented Windgrace's Judgment --- .../src/mage/cards/w/WindgracesJudgment.java | 60 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 61 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/w/WindgracesJudgment.java diff --git a/Mage.Sets/src/mage/cards/w/WindgracesJudgment.java b/Mage.Sets/src/mage/cards/w/WindgracesJudgment.java new file mode 100644 index 00000000000..00d95d3090d --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WindgracesJudgment.java @@ -0,0 +1,60 @@ +package mage.cards.w; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPermanent; + +/** + * + * @author TheElk801 + */ +public final class WindgracesJudgment extends CardImpl { + + public WindgracesJudgment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}{G}"); + + // For any number of opponents, destroy target nonland permanent that player controls. + this.getSpellAbility().addEffect( + new DestroyTargetEffect(). + setText("For any number of opponents, " + + "destroy target nonland permanent " + + "that player controls") + ); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + if (ability instanceof SpellAbility) { + ability.getTargets().clear(); + game.getOpponents(ability.getControllerId()).forEach(playerId -> { + Player player = game.getPlayer(playerId); + if (player != null) { + FilterNonlandPermanent filter = new FilterNonlandPermanent( + "nonland permanent controlled by " + + player.getLogName() + ); + filter.add(new ControllerIdPredicate(playerId)); + ability.addTarget(new TargetPermanent(0, 1, filter, false)); + } + }); + } + } + + public WindgracesJudgment(final WindgracesJudgment card) { + super(card); + } + + @Override + public WindgracesJudgment copy() { + return new WindgracesJudgment(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index c01ebfaa4e0..5751546ccf7 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -98,6 +98,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Varchild, Betrayer of Kjeldor", 28, Rarity.RARE, mage.cards.v.VarchildBetrayerOfKjeldor.class)); cards.add(new SetCardInfo("Varina, Lich Queen", 48, Rarity.MYTHIC, mage.cards.v.VarinaLichQueen.class)); cards.add(new SetCardInfo("Whiptongue Hydra", 36, Rarity.RARE, mage.cards.w.WhiptongueHydra.class)); + cards.add(new SetCardInfo("Windgrace's Judgment", 49, Rarity.RARE, mage.cards.w.WindgracesJudgment.class)); cards.add(new SetCardInfo("Winds of Rath", 79, Rarity.RARE, mage.cards.w.WindsOfRath.class)); cards.add(new SetCardInfo("Yennet, Crypt Sovereign", 51, Rarity.MYTHIC, mage.cards.y.YennetCryptSovereign.class)); } From e6250c5969c12df54cd4afe7c7e94faf836c707e Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 27 Jul 2018 12:09:10 -0400 Subject: [PATCH 50/71] Implemented Endless Atlas --- Mage.Sets/src/mage/cards/e/EndlessAtlas.java | 74 ++++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 75 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EndlessAtlas.java diff --git a/Mage.Sets/src/mage/cards/e/EndlessAtlas.java b/Mage.Sets/src/mage/cards/e/EndlessAtlas.java new file mode 100644 index 00000000000..022cb4b44e3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EndlessAtlas.java @@ -0,0 +1,74 @@ +package mage.cards.e; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author TheElk801 + */ +public final class EndlessAtlas extends CardImpl { + + public EndlessAtlas(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // {2}, {T}: Draw a card. Activate this ability only if you control three or more lands with the same name. + Ability ability = new ActivateIfConditionActivatedAbility( + Zone.BATTLEFIELD, + new DrawCardSourceControllerEffect(1), + new GenericManaCost(2), + new EndlessAtlasCondition() + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public EndlessAtlas(final EndlessAtlas card) { + super(card); + } + + @Override + public EndlessAtlas copy() { + return new EndlessAtlas(this); + } +} + +class EndlessAtlasCondition implements Condition { + + @Override + public boolean apply(Game game, Ability source) { + Map landMap = new HashMap(); + for (Permanent land : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, + source.getControllerId(), game + )) { + if (land != null) { + int landCount = landMap.getOrDefault(land.getName(), 0); + if (landCount > 1) { + return true; + } + landMap.put(land.getName(), landCount + 1); + } + } + return false; + } + + @Override + public String toString() { + return "you control three or more lands with the same name"; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 5751546ccf7..55c291bf2af 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -46,6 +46,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Empyrial Storm", 2, Rarity.RARE, mage.cards.e.EmpyrialStorm.class)); cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); cards.add(new SetCardInfo("Enchantress's Presence", 141, Rarity.RARE, mage.cards.e.EnchantresssPresence.class)); + cards.add(new SetCardInfo("Endless Atlas", 55, Rarity.RARE, mage.cards.e.EndlessAtlas.class)); cards.add(new SetCardInfo("Entreat the Dead", 15, Rarity.RARE, mage.cards.e.EntreatTheDead.class)); cards.add(new SetCardInfo("Estrid's Invocation", 8, Rarity.RARE, mage.cards.e.EstridsInvocation.class)); cards.add(new SetCardInfo("Explosive Vegetation", 144, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); From 51c0bd0fee4a9fc6e3822841f40234f9ccf1c964 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 27 Jul 2018 12:42:47 -0400 Subject: [PATCH 51/71] Implemented Ever-Watching Threshold --- .../mage/cards/e/EverWatchingThreshold.java | 81 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 82 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EverWatchingThreshold.java diff --git a/Mage.Sets/src/mage/cards/e/EverWatchingThreshold.java b/Mage.Sets/src/mage/cards/e/EverWatchingThreshold.java new file mode 100644 index 00000000000..64cf1a648ab --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EverWatchingThreshold.java @@ -0,0 +1,81 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author TheElk801 + */ +public final class EverWatchingThreshold extends CardImpl { + + public EverWatchingThreshold(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + // Whenever an opponent attacks you and/or a planeswalker you control with one or more creatures, draw a card. + this.addAbility(new EverWatchingThresholdTriggeredAbility()); + } + + public EverWatchingThreshold(final EverWatchingThreshold card) { + super(card); + } + + @Override + public EverWatchingThreshold copy() { + return new EverWatchingThreshold(this); + } +} + +class EverWatchingThresholdTriggeredAbility extends TriggeredAbilityImpl { + + public EverWatchingThresholdTriggeredAbility() { + super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), false); + } + + public EverWatchingThresholdTriggeredAbility(final EverWatchingThresholdTriggeredAbility ability) { + super(ability); + } + + @Override + public EverWatchingThresholdTriggeredAbility copy() { + return new EverWatchingThresholdTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Player player = game.getPlayer(this.getControllerId()); + if (player == null) { + return false; + } + for (UUID attacker : game.getCombat().getAttackers()) { + Permanent creature = game.getPermanent(attacker); + if (creature != null + && player.hasOpponent(creature.getControllerId(), game) + && player.getId().equals(game.getCombat().getDefendingPlayerId(attacker, game))) { + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever an opponent attacks you " + + "and/or a planeswalker you control " + + "with one or more creatures, draw a card."; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 55c291bf2af..7d5b26769cd 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -49,6 +49,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Endless Atlas", 55, Rarity.RARE, mage.cards.e.EndlessAtlas.class)); cards.add(new SetCardInfo("Entreat the Dead", 15, Rarity.RARE, mage.cards.e.EntreatTheDead.class)); cards.add(new SetCardInfo("Estrid's Invocation", 8, Rarity.RARE, mage.cards.e.EstridsInvocation.class)); + cards.add(new SetCardInfo("Ever-Watching Threshold", 9, Rarity.RARE, mage.cards.e.EverWatchingThreshold.class)); cards.add(new SetCardInfo("Explosive Vegetation", 144, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); cards.add(new SetCardInfo("Finest Hour", 180, Rarity.RARE, mage.cards.f.FinestHour.class)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); From bda4c8d052ae0f1203007097b2436611442bdf04 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 27 Jul 2018 16:00:30 -0400 Subject: [PATCH 52/71] updated C18 spoiler --- Mage.Sets/src/mage/sets/Commander2018.java | 209 +++++++++++++++++++- Utils/mtg-cards-data.txt | 211 ++++++++++++++++++++- 2 files changed, 417 insertions(+), 3 deletions(-) diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 7d5b26769cd..69211aa5edb 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -20,88 +20,295 @@ public final class Commander2018 extends ExpansionSet { super("Commander 2018 Edition", "C18", ExpansionSet.buildDate(2018, 8, 10), SetType.SUPPLEMENTAL); this.blockName = "Command Zone"; + cards.add(new SetCardInfo("Acidic Slime", 127, Rarity.UNCOMMON, mage.cards.a.AcidicSlime.class)); + cards.add(new SetCardInfo("Adarkar Valkyrie", 60, Rarity.RARE, mage.cards.a.AdarkarValkyrie.class)); + cards.add(new SetCardInfo("Aether Gale", 80, Rarity.RARE, mage.cards.a.AetherGale.class)); cards.add(new SetCardInfo("Aethermage's Touch", 168, Rarity.RARE, mage.cards.a.AethermagesTouch.class)); + cards.add(new SetCardInfo("Ajani's Chosen", 61, Rarity.RARE, mage.cards.a.AjanisChosen.class)); + cards.add(new SetCardInfo("Akoum Refuge", 231, Rarity.UNCOMMON, mage.cards.a.AkoumRefuge.class)); + cards.add(new SetCardInfo("Akroma's Vengeance", 62, Rarity.RARE, mage.cards.a.AkromasVengeance.class)); cards.add(new SetCardInfo("Ancient Stone Idol", 53, Rarity.RARE, mage.cards.a.AncientStoneIdol.class)); + cards.add(new SetCardInfo("Arcane Sanctum", 232, Rarity.UNCOMMON, mage.cards.a.ArcaneSanctum.class)); + cards.add(new SetCardInfo("Archetype of Imagination", 81, Rarity.UNCOMMON, mage.cards.a.ArchetypeOfImagination.class)); cards.add(new SetCardInfo("Arixmethes, Slumbering Isle", 38, Rarity.RARE, mage.cards.a.ArixmethesSlumberingIsle.class)); + cards.add(new SetCardInfo("Army of the Damned", 113, Rarity.MYTHIC, mage.cards.a.ArmyOfTheDamned.class)); + cards.add(new SetCardInfo("Aura Gnarlid", 128, Rarity.COMMON, mage.cards.a.AuraGnarlid.class)); cards.add(new SetCardInfo("Avenger of Zendikar", 129, Rarity.MYTHIC, mage.cards.a.AvengerOfZendikar.class)); + cards.add(new SetCardInfo("Azorius Chancery", 233, Rarity.UNCOMMON, mage.cards.a.AzoriusChancery.class)); + cards.add(new SetCardInfo("Azorius Guildgate", 234, Rarity.COMMON, mage.cards.a.AzoriusGuildgate.class)); + cards.add(new SetCardInfo("Azorius Signet", 196, Rarity.UNCOMMON, mage.cards.a.AzoriusSignet.class)); + cards.add(new SetCardInfo("Baloth Woodcrasher", 130, Rarity.UNCOMMON, mage.cards.b.BalothWoodcrasher.class)); cards.add(new SetCardInfo("Banishing Stroke", 63, Rarity.UNCOMMON, mage.cards.b.BanishingStroke.class)); + cards.add(new SetCardInfo("Bant Charm", 169, Rarity.UNCOMMON, mage.cards.b.BantCharm.class)); + cards.add(new SetCardInfo("Barren Moor", 235, Rarity.COMMON, mage.cards.b.BarrenMoor.class)); cards.add(new SetCardInfo("Bear Umbra", 131, Rarity.RARE, mage.cards.b.BearUmbra.class)); + cards.add(new SetCardInfo("Blasphemous Act", 120, Rarity.RARE, mage.cards.b.BlasphemousAct.class)); + cards.add(new SetCardInfo("Blighted Woodland", 236, Rarity.UNCOMMON, mage.cards.b.BlightedWoodland.class)); + cards.add(new SetCardInfo("Blinkmoth Urn", 197, Rarity.RARE, mage.cards.b.BlinkmothUrn.class)); cards.add(new SetCardInfo("Bloodtracker", 14, Rarity.RARE, mage.cards.b.Bloodtracker.class)); + cards.add(new SetCardInfo("Blossoming Sands", 237, Rarity.COMMON, mage.cards.b.BlossomingSands.class)); + cards.add(new SetCardInfo("Bojuka Bog", 238, Rarity.COMMON, mage.cards.b.BojukaBog.class)); + cards.add(new SetCardInfo("Boon Satyr", 132, Rarity.RARE, mage.cards.b.BoonSatyr.class)); + cards.add(new SetCardInfo("Borderland Explorer", 133, Rarity.COMMON, mage.cards.b.BorderlandExplorer.class)); + cards.add(new SetCardInfo("Bosh, Iron Golem", 198, Rarity.RARE, mage.cards.b.BoshIronGolem.class)); cards.add(new SetCardInfo("Brainstorm", 82, Rarity.UNCOMMON, mage.cards.b.Brainstorm.class)); cards.add(new SetCardInfo("Brudiclad, Telchor Engineer", 39, Rarity.MYTHIC, mage.cards.b.BrudicladTelchorEngineer.class)); cards.add(new SetCardInfo("Bruna, Light of Alabaster", 170, Rarity.MYTHIC, mage.cards.b.BrunaLightOfAlabaster.class)); cards.add(new SetCardInfo("Budoka Gardener", 134, Rarity.RARE, mage.cards.b.BudokaGardener.class)); + cards.add(new SetCardInfo("Buried Ruin", 239, Rarity.UNCOMMON, mage.cards.b.BuriedRuin.class)); + cards.add(new SetCardInfo("Celestial Archon", 64, Rarity.RARE, mage.cards.c.CelestialArchon.class)); cards.add(new SetCardInfo("Centaur Vinecrasher", 135, Rarity.RARE, mage.cards.c.CentaurVinecrasher.class)); cards.add(new SetCardInfo("Chain Reaction", 121, Rarity.RARE, mage.cards.c.ChainReaction.class)); cards.add(new SetCardInfo("Chaos Warp", 122, Rarity.RARE, mage.cards.c.ChaosWarp.class)); + cards.add(new SetCardInfo("Charnelhoard Wurm", 171, Rarity.RARE, mage.cards.c.CharnelhoardWurm.class)); + cards.add(new SetCardInfo("Chief of the Foundry", 199, Rarity.UNCOMMON, mage.cards.c.ChiefOfTheFoundry.class)); cards.add(new SetCardInfo("Cloudform", 83, Rarity.UNCOMMON, mage.cards.c.Cloudform.class)); + cards.add(new SetCardInfo("Cold-Eyed Selkie", 172, Rarity.RARE, mage.cards.c.ColdEyedSelkie.class)); cards.add(new SetCardInfo("Command Tower", 240, Rarity.COMMON, mage.cards.c.CommandTower.class)); cards.add(new SetCardInfo("Commander's Sphere", 200, Rarity.COMMON, mage.cards.c.CommandersSphere.class)); + cards.add(new SetCardInfo("Consign to Dust", 136, Rarity.UNCOMMON, mage.cards.c.ConsignToDust.class)); + cards.add(new SetCardInfo("Conundrum Sphinx", 84, Rarity.RARE, mage.cards.c.ConundrumSphinx.class)); cards.add(new SetCardInfo("Crash of Rhino Beetles", 29, Rarity.RARE, mage.cards.c.CrashOfRhinoBeetles.class)); + cards.add(new SetCardInfo("Creeping Renaissance", 137, Rarity.RARE, mage.cards.c.CreepingRenaissance.class)); + cards.add(new SetCardInfo("Crib Swap", 65, Rarity.UNCOMMON, mage.cards.c.CribSwap.class)); cards.add(new SetCardInfo("Crystal Ball", 201, Rarity.UNCOMMON, mage.cards.c.CrystalBall.class)); + cards.add(new SetCardInfo("Cultivate", 138, Rarity.COMMON, mage.cards.c.Cultivate.class)); + cards.add(new SetCardInfo("Darksteel Citadel", 241, Rarity.UNCOMMON, mage.cards.d.DarksteelCitadel.class)); + cards.add(new SetCardInfo("Darksteel Juggernaut", 202, Rarity.RARE, mage.cards.d.DarksteelJuggernaut.class)); + cards.add(new SetCardInfo("Dawn's Reflection", 139, Rarity.COMMON, mage.cards.d.DawnsReflection.class)); + cards.add(new SetCardInfo("Daxos of Meletis", 173, Rarity.RARE, mage.cards.d.DaxosOfMeletis.class)); + cards.add(new SetCardInfo("Deathreap Ritual", 174, Rarity.UNCOMMON, mage.cards.d.DeathreapRitual.class)); + cards.add(new SetCardInfo("Decimate", 175, Rarity.RARE, mage.cards.d.Decimate.class)); + cards.add(new SetCardInfo("Devastation Tide", 85, Rarity.RARE, mage.cards.d.DevastationTide.class)); cards.add(new SetCardInfo("Dictate of Kruphix", 86, Rarity.RARE, mage.cards.d.DictateOfKruphix.class)); + cards.add(new SetCardInfo("Dimir Aqueduct", 242, Rarity.UNCOMMON, mage.cards.d.DimirAqueduct.class)); + cards.add(new SetCardInfo("Dimir Guildgate", 243, Rarity.COMMON, mage.cards.d.DimirGuildgate.class)); + cards.add(new SetCardInfo("Dimir Signet", 203, Rarity.UNCOMMON, mage.cards.d.DimirSignet.class)); + cards.add(new SetCardInfo("Dismal Backwater", 244, Rarity.COMMON, mage.cards.d.DismalBackwater.class)); + cards.add(new SetCardInfo("Dismantling Blow", 66, Rarity.COMMON, mage.cards.d.DismantlingBlow.class)); + cards.add(new SetCardInfo("Djinn of Wishes", 87, Rarity.RARE, mage.cards.d.DjinnOfWishes.class)); + cards.add(new SetCardInfo("Dream Cache", 88, Rarity.COMMON, mage.cards.d.DreamCache.class)); + cards.add(new SetCardInfo("Dreamstone Hedron", 204, Rarity.UNCOMMON, mage.cards.d.DreamstoneHedron.class)); + cards.add(new SetCardInfo("Duplicant", 205, Rarity.RARE, mage.cards.d.Duplicant.class)); + cards.add(new SetCardInfo("Duskmantle Seer", 176, Rarity.RARE, mage.cards.d.DuskmantleSeer.class)); cards.add(new SetCardInfo("Echo Storm", 7, Rarity.RARE, mage.cards.e.EchoStorm.class)); cards.add(new SetCardInfo("Eel Umbra", 89, Rarity.COMMON, mage.cards.e.EelUmbra.class)); cards.add(new SetCardInfo("Eidolon of Blossoms", 140, Rarity.RARE, mage.cards.e.EidolonOfBlossoms.class)); + cards.add(new SetCardInfo("Elderwood Scion", 177, Rarity.RARE, mage.cards.e.ElderwoodScion.class)); cards.add(new SetCardInfo("Empyrial Storm", 2, Rarity.RARE, mage.cards.e.EmpyrialStorm.class)); cards.add(new SetCardInfo("Enchanter's Bane", 21, Rarity.RARE, mage.cards.e.EnchantersBane.class)); cards.add(new SetCardInfo("Enchantress's Presence", 141, Rarity.RARE, mage.cards.e.EnchantresssPresence.class)); cards.add(new SetCardInfo("Endless Atlas", 55, Rarity.RARE, mage.cards.e.EndlessAtlas.class)); + cards.add(new SetCardInfo("Enigma Sphinx", 178, Rarity.RARE, mage.cards.e.EnigmaSphinx.class)); + cards.add(new SetCardInfo("Entreat the Angels", 67, Rarity.MYTHIC, mage.cards.e.EntreatTheAngels.class)); cards.add(new SetCardInfo("Entreat the Dead", 15, Rarity.RARE, mage.cards.e.EntreatTheDead.class)); + cards.add(new SetCardInfo("Epic Proportions", 142, Rarity.RARE, mage.cards.e.EpicProportions.class)); + cards.add(new SetCardInfo("Esper Charm", 179, Rarity.UNCOMMON, mage.cards.e.EsperCharm.class)); cards.add(new SetCardInfo("Estrid's Invocation", 8, Rarity.RARE, mage.cards.e.EstridsInvocation.class)); + cards.add(new SetCardInfo("Etherium Sculptor", 90, Rarity.COMMON, mage.cards.e.EtheriumSculptor.class)); cards.add(new SetCardInfo("Ever-Watching Threshold", 9, Rarity.RARE, mage.cards.e.EverWatchingThreshold.class)); + cards.add(new SetCardInfo("Evolving Wilds", 245, Rarity.COMMON, mage.cards.e.EvolvingWilds.class)); + cards.add(new SetCardInfo("Explore", 143, Rarity.COMMON, mage.cards.e.Explore.class)); cards.add(new SetCardInfo("Explosive Vegetation", 144, Rarity.UNCOMMON, mage.cards.e.ExplosiveVegetation.class)); + cards.add(new SetCardInfo("Far Wanderings", 145, Rarity.COMMON, mage.cards.f.FarWanderings.class)); + cards.add(new SetCardInfo("Farhaven Elf", 146, Rarity.COMMON, mage.cards.f.FarhavenElf.class)); + cards.add(new SetCardInfo("Fertile Ground", 147, Rarity.COMMON, mage.cards.f.FertileGround.class)); cards.add(new SetCardInfo("Finest Hour", 180, Rarity.RARE, mage.cards.f.FinestHour.class)); + cards.add(new SetCardInfo("Flameblast Dragon", 123, Rarity.RARE, mage.cards.f.FlameblastDragon.class)); + cards.add(new SetCardInfo("Forest", 305, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 306, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 307, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forge of Heroes", 58, Rarity.COMMON, mage.cards.f.ForgeOfHeroes.class)); + cards.add(new SetCardInfo("Forgotten Cave", 246, Rarity.COMMON, mage.cards.f.ForgottenCave.class)); + cards.add(new SetCardInfo("Forsaken Sanctuary", 247, Rarity.UNCOMMON, mage.cards.f.ForsakenSanctuary.class)); + cards.add(new SetCardInfo("Foundry of the Consuls", 248, Rarity.UNCOMMON, mage.cards.f.FoundryOfTheConsuls.class)); cards.add(new SetCardInfo("Fury Storm", 22, Rarity.RARE, mage.cards.f.FuryStorm.class)); + cards.add(new SetCardInfo("Gaze of Granite", 181, Rarity.RARE, mage.cards.g.GazeOfGranite.class)); cards.add(new SetCardInfo("Genesis Storm", 30, Rarity.RARE, mage.cards.g.GenesisStorm.class)); + cards.add(new SetCardInfo("Golgari Rot Farm", 249, Rarity.UNCOMMON, mage.cards.g.GolgariRotFarm.class)); + cards.add(new SetCardInfo("Grapple with the Past", 148, Rarity.COMMON, mage.cards.g.GrappleWithThePast.class)); + cards.add(new SetCardInfo("Great Furnace", 250, Rarity.COMMON, mage.cards.g.GreatFurnace.class)); + cards.add(new SetCardInfo("Grim Backwoods", 251, Rarity.RARE, mage.cards.g.GrimBackwoods.class)); + cards.add(new SetCardInfo("Grisly Salvage", 182, Rarity.COMMON, mage.cards.g.GrislySalvage.class)); + cards.add(new SetCardInfo("Ground Seal", 149, Rarity.RARE, mage.cards.g.GroundSeal.class)); + cards.add(new SetCardInfo("Gruul Turf", 252, Rarity.UNCOMMON, mage.cards.g.GruulTurf.class)); + cards.add(new SetCardInfo("Halimar Depths", 253, Rarity.COMMON, mage.cards.h.HalimarDepths.class)); + cards.add(new SetCardInfo("Harrow", 150, Rarity.COMMON, mage.cards.h.Harrow.class)); + cards.add(new SetCardInfo("Haunted Fengraf", 254, Rarity.COMMON, mage.cards.h.HauntedFengraf.class)); cards.add(new SetCardInfo("Heavenly Blademaster", 3, Rarity.RARE, mage.cards.h.HeavenlyBlademaster.class)); + cards.add(new SetCardInfo("Hedron Archive", 206, Rarity.UNCOMMON, mage.cards.h.HedronArchive.class)); + cards.add(new SetCardInfo("Hellkite Igniter", 124, Rarity.RARE, mage.cards.h.HellkiteIgniter.class)); cards.add(new SetCardInfo("Herald of the Pantheon", 151, Rarity.RARE, mage.cards.h.HeraldOfThePantheon.class)); + cards.add(new SetCardInfo("High Priest of Penance", 183, Rarity.RARE, mage.cards.h.HighPriestOfPenance.class)); + cards.add(new SetCardInfo("Highland Lake", 255, Rarity.UNCOMMON, mage.cards.h.HighlandLake.class)); + cards.add(new SetCardInfo("Hunting Wilds", 152, Rarity.UNCOMMON, mage.cards.h.HuntingWilds.class)); cards.add(new SetCardInfo("Hydra Omnivore", 153, Rarity.MYTHIC, mage.cards.h.HydraOmnivore.class)); + cards.add(new SetCardInfo("Inkwell Leviathan", 91, Rarity.RARE, mage.cards.i.InkwellLeviathan.class)); + cards.add(new SetCardInfo("Into the Roil", 92, Rarity.COMMON, mage.cards.i.IntoTheRoil.class)); + cards.add(new SetCardInfo("Island", 296, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 297, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 298, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Isolated Watchtower", 59, Rarity.RARE, mage.cards.i.IsolatedWatchtower.class)); + cards.add(new SetCardInfo("Izzet Boilerworks", 256, Rarity.UNCOMMON, mage.cards.i.IzzetBoilerworks.class)); + cards.add(new SetCardInfo("Izzet Guildgate", 257, Rarity.COMMON, mage.cards.i.IzzetGuildgate.class)); + cards.add(new SetCardInfo("Izzet Signet", 207, Rarity.UNCOMMON, mage.cards.i.IzzetSignet.class)); + cards.add(new SetCardInfo("Jeskai Infiltrator", 93, Rarity.RARE, mage.cards.j.JeskaiInfiltrator.class)); + cards.add(new SetCardInfo("Jund Panorama", 258, Rarity.COMMON, mage.cards.j.JundPanorama.class)); + cards.add(new SetCardInfo("Jungle Hollow", 259, Rarity.COMMON, mage.cards.j.JungleHollow.class)); + cards.add(new SetCardInfo("Jwar Isle Refuge", 260, Rarity.UNCOMMON, mage.cards.j.JwarIsleRefuge.class)); + cards.add(new SetCardInfo("Kazandu Refuge", 261, Rarity.UNCOMMON, mage.cards.k.KazanduRefuge.class)); cards.add(new SetCardInfo("Kestia, the Cultivator", 42, Rarity.MYTHIC, mage.cards.k.KestiaTheCultivator.class)); + cards.add(new SetCardInfo("Khalni Garden", 262, Rarity.COMMON, mage.cards.k.KhalniGarden.class)); + cards.add(new SetCardInfo("Khalni Heart Expedition", 154, Rarity.COMMON, mage.cards.k.KhalniHeartExpedition.class)); + cards.add(new SetCardInfo("Krosan Verge", 263, Rarity.UNCOMMON, mage.cards.k.KrosanVerge.class)); + cards.add(new SetCardInfo("Kruphix's Insight", 155, Rarity.COMMON, mage.cards.k.KruphixsInsight.class)); + cards.add(new SetCardInfo("Lavalanche", 184, Rarity.RARE, mage.cards.l.Lavalanche.class)); + cards.add(new SetCardInfo("Lightform", 68, Rarity.UNCOMMON, mage.cards.l.Lightform.class)); + cards.add(new SetCardInfo("Lonely Sandbar", 264, Rarity.COMMON, mage.cards.l.LonelySandbar.class)); cards.add(new SetCardInfo("Lord Windgrace", 43, Rarity.MYTHIC, mage.cards.l.LordWindgrace.class)); cards.add(new SetCardInfo("Loyal Apprentice", 23, Rarity.UNCOMMON, mage.cards.l.LoyalApprentice.class)); cards.add(new SetCardInfo("Loyal Drake", 10, Rarity.UNCOMMON, mage.cards.l.LoyalDrake.class)); cards.add(new SetCardInfo("Loyal Guardian", 31, Rarity.UNCOMMON, mage.cards.l.LoyalGuardian.class)); cards.add(new SetCardInfo("Loyal Subordinate", 16, Rarity.UNCOMMON, mage.cards.l.LoyalSubordinate.class)); cards.add(new SetCardInfo("Loyal Unicorn", 4, Rarity.UNCOMMON, mage.cards.l.LoyalUnicorn.class)); + cards.add(new SetCardInfo("Magmaquake", 125, Rarity.RARE, mage.cards.m.Magmaquake.class)); + cards.add(new SetCardInfo("Magnifying Glass", 208, Rarity.UNCOMMON, mage.cards.m.MagnifyingGlass.class)); cards.add(new SetCardInfo("Magus of the Balance", 5, Rarity.RARE, mage.cards.m.MagusOfTheBalance.class)); + cards.add(new SetCardInfo("Martial Coup", 69, Rarity.RARE, mage.cards.m.MartialCoup.class)); + cards.add(new SetCardInfo("Maverick Thopterist", 185, Rarity.UNCOMMON, mage.cards.m.MaverickThopterist.class)); + cards.add(new SetCardInfo("Meandering River", 265, Rarity.UNCOMMON, mage.cards.m.MeanderingRiver.class)); + cards.add(new SetCardInfo("Mimic Vat", 209, Rarity.RARE, mage.cards.m.MimicVat.class)); + cards.add(new SetCardInfo("Mind Stone", 210, Rarity.COMMON, mage.cards.m.MindStone.class)); + cards.add(new SetCardInfo("Mirrorworks", 211, Rarity.RARE, mage.cards.m.Mirrorworks.class)); + cards.add(new SetCardInfo("Moldgraf Monstrosity", 156, Rarity.RARE, mage.cards.m.MoldgrafMonstrosity.class)); + cards.add(new SetCardInfo("Moonlight Bargain", 114, Rarity.RARE, mage.cards.m.MoonlightBargain.class)); + cards.add(new SetCardInfo("Mortify", 186, Rarity.UNCOMMON, mage.cards.m.Mortify.class)); + cards.add(new SetCardInfo("Mortuary Mire", 266, Rarity.COMMON, mage.cards.m.MortuaryMire.class)); + cards.add(new SetCardInfo("Mosswort Bridge", 267, Rarity.RARE, mage.cards.m.MosswortBridge.class)); cards.add(new SetCardInfo("Mountain Valley", 268, Rarity.UNCOMMON, mage.cards.m.MountainValley.class)); + cards.add(new SetCardInfo("Mountain", 302, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 303, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 304, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mulldrifter", 94, Rarity.UNCOMMON, mage.cards.m.Mulldrifter.class)); + cards.add(new SetCardInfo("Myr Battlesphere", 212, Rarity.RARE, mage.cards.m.MyrBattlesphere.class)); cards.add(new SetCardInfo("Myriad Landscape", 269, Rarity.UNCOMMON, mage.cards.m.MyriadLandscape.class)); cards.add(new SetCardInfo("Nesting Dragon", 24, Rarity.RARE, mage.cards.n.NestingDragon.class)); + cards.add(new SetCardInfo("New Benalia", 270, Rarity.UNCOMMON, mage.cards.n.NewBenalia.class)); cards.add(new SetCardInfo("Night Incarnate", 17, Rarity.RARE, mage.cards.n.NightIncarnate.class)); + cards.add(new SetCardInfo("Ninja of the Deep Hours", 95, Rarity.COMMON, mage.cards.n.NinjaOfTheDeepHours.class)); cards.add(new SetCardInfo("Nylea's Colossus", 33, Rarity.RARE, mage.cards.n.NyleasColossus.class)); cards.add(new SetCardInfo("Octopus Umbra", 11, Rarity.RARE, mage.cards.o.OctopusUmbra.class)); + cards.add(new SetCardInfo("Orzhov Basilica", 271, Rarity.UNCOMMON, mage.cards.o.OrzhovBasilica.class)); + cards.add(new SetCardInfo("Orzhov Guildgate", 272, Rarity.COMMON, mage.cards.o.OrzhovGuildgate.class)); + cards.add(new SetCardInfo("Orzhov Signet", 213, Rarity.UNCOMMON, mage.cards.o.OrzhovSignet.class)); + cards.add(new SetCardInfo("Overgrowth", 157, Rarity.COMMON, mage.cards.o.Overgrowth.class)); cards.add(new SetCardInfo("Phyrexian Delver", 115, Rarity.RARE, mage.cards.p.PhyrexianDelver.class)); + cards.add(new SetCardInfo("Phyrexian Rebirth", 70, Rarity.RARE, mage.cards.p.PhyrexianRebirth.class)); + cards.add(new SetCardInfo("Pilgrim's Eye", 214, Rarity.COMMON, mage.cards.p.PilgrimsEye.class)); + cards.add(new SetCardInfo("Plains", 293, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 294, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 295, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ponder", 96, Rarity.COMMON, mage.cards.p.Ponder.class)); cards.add(new SetCardInfo("Portent", 97, Rarity.COMMON, mage.cards.p.Portent.class)); cards.add(new SetCardInfo("Predict", 98, Rarity.UNCOMMON, mage.cards.p.Predict.class)); + cards.add(new SetCardInfo("Prismatic Lens", 215, Rarity.UNCOMMON, mage.cards.p.PrismaticLens.class)); + cards.add(new SetCardInfo("Prototype Portal", 216, Rarity.RARE, mage.cards.p.PrototypePortal.class)); + cards.add(new SetCardInfo("Psychosis Crawler", 217, Rarity.RARE, mage.cards.p.PsychosisCrawler.class)); + cards.add(new SetCardInfo("Putrefy", 187, Rarity.UNCOMMON, mage.cards.p.Putrefy.class)); + cards.add(new SetCardInfo("Rakdos Carnarium", 273, Rarity.COMMON, mage.cards.r.RakdosCarnarium.class)); cards.add(new SetCardInfo("Rampaging Baloths", 158, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); cards.add(new SetCardInfo("Ravenous Slime", 34, Rarity.RARE, mage.cards.r.RavenousSlime.class)); + cards.add(new SetCardInfo("Reclamation Sage", 159, Rarity.UNCOMMON, mage.cards.r.ReclamationSage.class)); + cards.add(new SetCardInfo("Retreat to Hagra", 116, Rarity.UNCOMMON, mage.cards.r.RetreatToHagra.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); + cards.add(new SetCardInfo("Return to Dust", 71, Rarity.UNCOMMON, mage.cards.r.ReturnToDust.class)); + cards.add(new SetCardInfo("Reverse Engineer", 99, Rarity.UNCOMMON, mage.cards.r.ReverseEngineer.class)); + cards.add(new SetCardInfo("Righteous Authority", 188, Rarity.RARE, mage.cards.r.RighteousAuthority.class)); cards.add(new SetCardInfo("Rocky Tar Pit", 274, Rarity.UNCOMMON, mage.cards.r.RockyTarPit.class)); + cards.add(new SetCardInfo("Rubblehulk", 189, Rarity.RARE, mage.cards.r.Rubblehulk.class)); cards.add(new SetCardInfo("Ruinous Path", 117, Rarity.RARE, mage.cards.r.RuinousPath.class)); + cards.add(new SetCardInfo("Sage's Reverie", 72, Rarity.UNCOMMON, mage.cards.s.SagesReverie.class)); + cards.add(new SetCardInfo("Saheeli's Artistry", 100, Rarity.RARE, mage.cards.s.SaheelisArtistry.class)); cards.add(new SetCardInfo("Saheeli's Directive", 26, Rarity.RARE, mage.cards.s.SaheelisDirective.class)); + cards.add(new SetCardInfo("Sakura-Tribe Elder", 160, Rarity.COMMON, mage.cards.s.SakuraTribeElder.class)); + cards.add(new SetCardInfo("Savage Lands", 275, Rarity.UNCOMMON, mage.cards.s.SavageLands.class)); + cards.add(new SetCardInfo("Savage Twister", 190, Rarity.UNCOMMON, mage.cards.s.SavageTwister.class)); + cards.add(new SetCardInfo("Scoured Barrens", 276, Rarity.COMMON, mage.cards.s.ScouredBarrens.class)); + cards.add(new SetCardInfo("Scrabbling Claws", 218, Rarity.UNCOMMON, mage.cards.s.ScrabblingClaws.class)); cards.add(new SetCardInfo("Scute Mob", 161, Rarity.RARE, mage.cards.s.ScuteMob.class)); + cards.add(new SetCardInfo("Scuttling Doom Engine", 219, Rarity.RARE, mage.cards.s.ScuttlingDoomEngine.class)); + cards.add(new SetCardInfo("Seaside Citadel", 277, Rarity.UNCOMMON, mage.cards.s.SeasideCitadel.class)); + cards.add(new SetCardInfo("Seat of the Synod", 278, Rarity.COMMON, mage.cards.s.SeatOfTheSynod.class)); + cards.add(new SetCardInfo("Secluded Steppe", 279, Rarity.COMMON, mage.cards.s.SecludedSteppe.class)); + cards.add(new SetCardInfo("Seer's Lantern", 220, Rarity.COMMON, mage.cards.s.SeersLantern.class)); + cards.add(new SetCardInfo("Seer's Sundial", 221, Rarity.RARE, mage.cards.s.SeersSundial.class)); + cards.add(new SetCardInfo("Sejiri Refuge", 280, Rarity.UNCOMMON, mage.cards.s.SejiriRefuge.class)); + cards.add(new SetCardInfo("Selesnya Sanctuary", 281, Rarity.COMMON, mage.cards.s.SelesnyaSanctuary.class)); cards.add(new SetCardInfo("Serra Avatar", 73, Rarity.MYTHIC, mage.cards.s.SerraAvatar.class)); + cards.add(new SetCardInfo("Sharding Sphinx", 101, Rarity.RARE, mage.cards.s.ShardingSphinx.class)); cards.add(new SetCardInfo("Sigil of the Empty Throne", 74, Rarity.RARE, mage.cards.s.SigilOfTheEmptyThrone.class)); + cards.add(new SetCardInfo("Sigiled Starfish", 102, Rarity.COMMON, mage.cards.s.SigiledStarfish.class)); + cards.add(new SetCardInfo("Silent Sentinel", 75, Rarity.RARE, mage.cards.s.SilentSentinel.class)); cards.add(new SetCardInfo("Silent-Blade Oni", 191, Rarity.RARE, mage.cards.s.SilentBladeOni.class)); - cards.add(new SetCardInfo("Skull Storm", 18, Rarity.COMMON, mage.cards.s.SkullStorm.class)); + cards.add(new SetCardInfo("Simic Growth Chamber", 282, Rarity.UNCOMMON, mage.cards.s.SimicGrowthChamber.class)); + cards.add(new SetCardInfo("Skull Storm", 18, Rarity.RARE, mage.cards.s.SkullStorm.class)); + cards.add(new SetCardInfo("Snake Umbra", 162, Rarity.COMMON, mage.cards.s.SnakeUmbra.class)); cards.add(new SetCardInfo("Sol Ring", 222, Rarity.UNCOMMON, mage.cards.s.SolRing.class)); + cards.add(new SetCardInfo("Soul Snare", 76, Rarity.UNCOMMON, mage.cards.s.SoulSnare.class)); + cards.add(new SetCardInfo("Soul of Innistrad", 118, Rarity.MYTHIC, mage.cards.s.SoulOfInnistrad.class)); + cards.add(new SetCardInfo("Soul of New Phyrexia", 223, Rarity.MYTHIC, mage.cards.s.SoulOfNewPhyrexia.class)); cards.add(new SetCardInfo("Spawning Grounds", 163, Rarity.RARE, mage.cards.s.SpawningGrounds.class)); + cards.add(new SetCardInfo("Sphinx of Jwar Isle", 103, Rarity.RARE, mage.cards.s.SphinxOfJwarIsle.class)); + cards.add(new SetCardInfo("Sphinx of Uthuun", 104, Rarity.RARE, mage.cards.s.SphinxOfUthuun.class)); + cards.add(new SetCardInfo("Steel Hellkite", 224, Rarity.RARE, mage.cards.s.SteelHellkite.class)); + cards.add(new SetCardInfo("Stitch Together", 119, Rarity.UNCOMMON, mage.cards.s.StitchTogether.class)); + cards.add(new SetCardInfo("Submerged Boneyard", 283, Rarity.UNCOMMON, mage.cards.s.SubmergedBoneyard.class)); + cards.add(new SetCardInfo("Swamp", 299, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 300, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 301, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swiftfoot Boots", 225, Rarity.UNCOMMON, mage.cards.s.SwiftfootBoots.class)); + cards.add(new SetCardInfo("Swiftwater Cliffs", 284, Rarity.COMMON, mage.cards.s.SwiftwaterCliffs.class)); cards.add(new SetCardInfo("Tawnos, Urza's Apprentice", 45, Rarity.MYTHIC, mage.cards.t.TawnosUrzasApprentice.class)); + cards.add(new SetCardInfo("Telling Time", 105, Rarity.COMMON, mage.cards.t.TellingTime.class)); + cards.add(new SetCardInfo("Temple of the False God", 285, Rarity.UNCOMMON, mage.cards.t.TempleOfTheFalseGod.class)); cards.add(new SetCardInfo("Terminus", 77, Rarity.RARE, mage.cards.t.Terminus.class)); + cards.add(new SetCardInfo("Terramorphic Expanse", 286, Rarity.COMMON, mage.cards.t.TerramorphicExpanse.class)); cards.add(new SetCardInfo("Thantis the Warweaver", 46, Rarity.MYTHIC, mage.cards.t.ThantisTheWarweaver.class)); + cards.add(new SetCardInfo("Thirst for Knowledge", 106, Rarity.UNCOMMON, mage.cards.t.ThirstForKnowledge.class)); + cards.add(new SetCardInfo("Thopter Assembly", 226, Rarity.RARE, mage.cards.t.ThopterAssembly.class)); + cards.add(new SetCardInfo("Thopter Engineer", 126, Rarity.UNCOMMON, mage.cards.t.ThopterEngineer.class)); cards.add(new SetCardInfo("Thopter Spy Network", 107, Rarity.RARE, mage.cards.t.ThopterSpyNetwork.class)); + cards.add(new SetCardInfo("Thornwood Falls", 287, Rarity.COMMON, mage.cards.t.ThornwoodFalls.class)); + cards.add(new SetCardInfo("Tidings", 108, Rarity.UNCOMMON, mage.cards.t.Tidings.class)); + cards.add(new SetCardInfo("Tranquil Cove", 288, Rarity.COMMON, mage.cards.t.TranquilCove.class)); + cards.add(new SetCardInfo("Tranquil Expanse", 289, Rarity.UNCOMMON, mage.cards.t.TranquilExpanse.class)); + cards.add(new SetCardInfo("Tranquil Thicket", 290, Rarity.COMMON, mage.cards.t.TranquilThicket.class)); + cards.add(new SetCardInfo("Treasure Hunt", 109, Rarity.COMMON, mage.cards.t.TreasureHunt.class)); cards.add(new SetCardInfo("Turntimber Sower", 35, Rarity.RARE, mage.cards.t.TurntimberSower.class)); cards.add(new SetCardInfo("Tuvasa the Sunlit", 47, Rarity.MYTHIC, mage.cards.t.TuvasaTheSunlit.class)); + cards.add(new SetCardInfo("Unflinching Courage", 192, Rarity.UNCOMMON, mage.cards.u.UnflinchingCourage.class)); + cards.add(new SetCardInfo("Unquestioned Authority", 78, Rarity.UNCOMMON, mage.cards.u.UnquestionedAuthority.class)); + cards.add(new SetCardInfo("Unstable Obelisk", 227, Rarity.UNCOMMON, mage.cards.u.UnstableObelisk.class)); + cards.add(new SetCardInfo("Unwinding Clock", 228, Rarity.RARE, mage.cards.u.UnwindingClock.class)); + cards.add(new SetCardInfo("Utter End", 193, Rarity.RARE, mage.cards.u.UtterEnd.class)); cards.add(new SetCardInfo("Varchild, Betrayer of Kjeldor", 28, Rarity.RARE, mage.cards.v.VarchildBetrayerOfKjeldor.class)); cards.add(new SetCardInfo("Varina, Lich Queen", 48, Rarity.MYTHIC, mage.cards.v.VarinaLichQueen.class)); + cards.add(new SetCardInfo("Vessel of Endless Rest", 229, Rarity.UNCOMMON, mage.cards.v.VesselOfEndlessRest.class)); + cards.add(new SetCardInfo("Vow of Flight", 110, Rarity.UNCOMMON, mage.cards.v.VowOfFlight.class)); + cards.add(new SetCardInfo("Vow of Wildness", 164, Rarity.UNCOMMON, mage.cards.v.VowOfWildness.class)); + cards.add(new SetCardInfo("Warped Landscape", 291, Rarity.COMMON, mage.cards.w.WarpedLandscape.class)); cards.add(new SetCardInfo("Whiptongue Hydra", 36, Rarity.RARE, mage.cards.w.WhiptongueHydra.class)); + cards.add(new SetCardInfo("Whirler Rogue", 111, Rarity.UNCOMMON, mage.cards.w.WhirlerRogue.class)); + cards.add(new SetCardInfo("Whitewater Naiads", 112, Rarity.UNCOMMON, mage.cards.w.WhitewaterNaiads.class)); + cards.add(new SetCardInfo("Wild Growth", 165, Rarity.COMMON, mage.cards.w.WildGrowth.class)); cards.add(new SetCardInfo("Windgrace's Judgment", 49, Rarity.RARE, mage.cards.w.WindgracesJudgment.class)); cards.add(new SetCardInfo("Winds of Rath", 79, Rarity.RARE, mage.cards.w.WindsOfRath.class)); + cards.add(new SetCardInfo("Woodland Stream", 292, Rarity.COMMON, mage.cards.w.WoodlandStream.class)); + cards.add(new SetCardInfo("Worm Harvest", 194, Rarity.RARE, mage.cards.w.WormHarvest.class)); + cards.add(new SetCardInfo("Worn Powerstone", 230, Rarity.UNCOMMON, mage.cards.w.WornPowerstone.class)); + cards.add(new SetCardInfo("Yavimaya Elder", 166, Rarity.COMMON, mage.cards.y.YavimayaElder.class)); + cards.add(new SetCardInfo("Yavimaya Enchantress", 167, Rarity.COMMON, mage.cards.y.YavimayaEnchantress.class)); cards.add(new SetCardInfo("Yennet, Crypt Sovereign", 51, Rarity.MYTHIC, mage.cards.y.YennetCryptSovereign.class)); + cards.add(new SetCardInfo("Zendikar Incarnate", 195, Rarity.UNCOMMON, mage.cards.z.ZendikarIncarnate.class)); } } diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index e46a010877f..21f9c274c7c 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -33942,7 +33942,7 @@ Bloodtracker|Commander 2018|14|R|{3}{B}|Creature - Vampire Wizard|2|2|Flying${B} Entreat the Dead|Commander 2018|15|R|{X}{X}{B}{B}{B}|Sorcery|||Return X target creature cards from your graveyard to the battlefield.$Miracle {X}{B}{B}| Loyal Subordinate|Commander 2018|16|U|{2}{B}|Creature - Zombie|3|1|Menace$Lieutenant — At the beginning of combat on your turn, if you control your commander, each opponent loses 3 life.| Night Incarnate|Commander 2018|17|R|{4}{B}|Creature - Elemental|3|4|Deathtouch$When Night Incarnate leaves the battlefield, all creatures get -3/-3 until end of turn.$Evoke {3}{B}| -Skull Storm|Commander 2018|18|C|{7}{B}{B}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game.$Each opponent sacrifices a creature. Each opponent who can't loses half their life, rounded up.| +Skull Storm|Commander 2018|18|R|{7}{B}{B}|Sorcery|||When you cast this spell, copy it for each time you've cast your commander from the command zone this game.$Each opponent sacrifices a creature. Each opponent who can't loses half their life, rounded up.| Sower of Discord|Commander 2018|19|R|{4}{B}{B}|Creature - Demon|6|6|Flying$As Sower of Discord enters the battlefield, choose two players.$Whenever damage is dealt to one of the chosen players, the other chosen player also loses that much life.| Emissary of Grudges|Commander 2018|20|R|{5}{R}|Creature - Efreet|6|5|Flying, haste$As Emissary of Grudges enters the battlefield, secretly choose an opponent.$Reveal the player you chose: Choose new targets for target spell or ability if it's controlled by the chosen player and if it targets you or a permanent you control. Activate this ability only once.| Enchanter's Bane|Commander 2018|21|R|{1}{R}|Enchantment|||At the beginning of your end step, target enchantment deals damage equal to its converted mana cost to its controller unless that player sacrifices it.| @@ -33984,44 +33984,251 @@ Geode Golem|Commander 2018|56|U|{5}|Artifact Creature - Golem|5|3|Trample$Whenev Retrofitter Foundry|Commander 2018|57|R|{1}|Artifact|||{3}: Untap Retrofitter Foundry.${2}, {T}: Create a 1/1 colorless Servo artifact creature token.${1}, {T}, Sacrifice a Servo: Create a 1/1 colorless Thopter artifact creature token with flying.${T}, Sacrifice a Thopter: Create a 4/4 colorless Construct artifact creature token.| Forge of Heroes|Commander 2018|58|C||Land|||{T}: Add {C}.${T}: Choose target commander that entered the battlefield this turn. Put a +1/+1 counter on it if it's a creature and a loyalty counter on it if it's a planeswalker.| Isolated Watchtower|Commander 2018|59|R||Land|||{T}: Add {C}.${2}, {T}: Scry 1, then you may reveal the top card of your library. If a basic land card is revealed this way, put it onto the battlefield tapped. Activate this ability only if an opponent controls at least two more lands than you.| +Adarkar Valkyrie|Commander 2018|60|R|{4}{W}{W}|Snow Creature - Angel|4|5|Flying, vigilance${T}: When target creature other than Adarkar Valkyrie dies this turn, return that card to the battlefield under your control.| +Ajani's Chosen|Commander 2018|61|R|{2}{W}{W}|Creature - Cat Soldier|3|3|Whenever an enchantment enters the battlefield under your control, create a 2/2 white Cat creature token. If that enchantment is an Aura, you may attach it to the token.| +Akroma's Vengeance|Commander 2018|62|R|{4}{W}{W}|Sorcery|||Destroy all artifacts, creatures, and enchantments.$Cycling {3}| Banishing Stroke|Commander 2018|63|U|{5}{W}|Instant|||Put target artifact, creature, or enchantment on the bottom of its owner's library.$Miracle {W}| +Celestial Archon|Commander 2018|64|R|{3}{W}{W}|Enchantment Creature - Archon|4|4|Bestow {5}{W}{W}$Flying, first strike$Enchanted creature gets +4/+4 and has flying and first strike.| +Crib Swap|Commander 2018|65|U|{2}{W}|Tribal Instant - Shapeshifter|||Changeling$Exile target creature. Its controller creates a 1/1 colorless Shapeshifter creature token with changeling.| +Dismantling Blow|Commander 2018|66|C|{2}{W}|Instant|||Kicker {2}{U}$Destroy target artifact or enchantment. If this spell was kicked, draw two cards.| +Entreat the Angels|Commander 2018|67|M|{X}{X}{W}{W}{W}|Sorcery|||Create X 4/4 white Angel creature tokens with flying.$Miracle {X}{W}{W}| +Lightform|Commander 2018|68|U|{1}{W}{W}|Enchantment|||When Lightform enters the battlefield, it becomes an Aura with enchant creature. Manifest the top card of your library and attach Lightform to it.$Enchanted creature has flying and lifelink.| +Martial Coup|Commander 2018|69|R|{X}{W}{W}|Sorcery|||Create X 1/1 white Soldier creature tokens. If X is 5 or more, destroy all other creatures.| +Phyrexian Rebirth|Commander 2018|70|R|{4}{W}{W}|Sorcery|||Destroy all creatures, then create an X/X colorless Horror artifact creature token, where X is the number of creatures destroyed this way.| +Return to Dust|Commander 2018|71|U|{2}{W}{W}|Instant|||Exile target artifact or enchantment. If you cast this spell during your main phase, you may exile up to one other target artifact or enchantment.| +Sage's Reverie|Commander 2018|72|U|{3}{W}|Enchantment - Aura|||Enchant creature$When Sage's Reverie enters the battlefield, draw a card for each Aura you control that's attached to a creature.$Enchanted creature gets +1/+1 for each Aura you control that's attached to a creature.| Serra Avatar|Commander 2018|73|M|{4}{W}{W}{W}|Creature - Avatar|*|*|Serra Avatar's power and toughness are each equal to your life total.$When Serra Avatar is put into a graveyard from anywhere, shuffle it into its owner's library.| Sigil of the Empty Throne|Commander 2018|74|R|{3}{W}{W}|Enchantment|||Whenever you cast an enchantment spell, create a 4/4 white Angel creature token with flying.| +Silent Sentinel|Commander 2018|75|R|{5}{W}{W}|Creature - Archon|4|6|Flying$Whenever Silent Sentinel attacks, you may return target enchantment card from your graveyard to the battlefield.| +Soul Snare|Commander 2018|76|U|{W}|Enchantment|||{W}, Sacrifice Soul Snare: Exile target creature that's attacking you or a planeswalker you control.| Terminus|Commander 2018|77|R|{4}{W}{W}|Sorcery|||Put all creatures on the bottom of their owners' libraries.$Miracle {W}| +Unquestioned Authority|Commander 2018|78|U|{2}{W}|Enchantment - Aura|||Enchant creature$When Unquestioned Authority enters the battlefield, draw a card.$Enchanted creature has protection from creatures.| Winds of Rath|Commander 2018|79|R|{3}{W}{W}|Sorcery|||Destroy all creatures that aren't enchanted. They can't be regenerated.| +Aether Gale|Commander 2018|80|R|{3}{U}{U}|Sorcery|||Return six target nonland permanents to their owners' hands.| +Archetype of Imagination|Commander 2018|81|U|{4}{U}{U}|Enchantment Creature - Human Wizard|3|2|Creatures you control have flying.$Creatures your opponents control lose flying and can't have or gain flying.| Brainstorm|Commander 2018|82|U|{U}|Instant|||Draw three cards, then put two cards from your hand on top of your library in any order.| Cloudform|Commander 2018|83|U|{1}{U}{U}|Enchantment|||When Cloudform enters the battlefield, it becomes an Aura with enchant creature. Manifest the top card of your library and attach Cloudform to it.$Enchanted creature has flying and hexproof.| +Conundrum Sphinx|Commander 2018|84|R|{2}{U}{U}|Creature - Sphinx|4|4|Flying$Whenever Conundrum Sphinx attacks, each player chooses a card name. Then each player reveals the top card of their library. If the card a player revealed has the name they chose, that player puts it into their hand. If it doesn't, that player puts it on the bottom of their library.| +Devastation Tide|Commander 2018|85|R|{3}{U}{U}|Sorcery|||Return all nonland permanents to their owners' hands.$Miracle {1}{U}| Dictate of Kruphix|Commander 2018|86|R|{1}{U}{U}|Enchantment|||Flash$At the beginning of each player's draw step, that player draws an additional card.| +Djinn of Wishes|Commander 2018|87|R|{3}{U}{U}|Creature - Djinn|4|4|Flying$Djinn of Wishes enters the battlefield with three wish counters on it.${2}{U}{U}, Remove a wish counter from Djinn of Wishes: Reveal the top card of your library. You may play that card without paying its mana cost. If you don't, exile it.| +Dream Cache|Commander 2018|88|C|{2}{U}|Sorcery|||Draw three cards, then put two cards from your hand both on top of your library or both on the bottom of your library.| Eel Umbra|Commander 2018|89|C|{1}{U}|Enchantment - Aura|||Flash| +Etherium Sculptor|Commander 2018|90|C|{1}{U}|Artifact Creature - Vedalken Artificer|1|2|Artifact spells you cast cost {1} less to cast.| +Inkwell Leviathan|Commander 2018|91|R|{7}{U}{U}|Artifact Creature - Leviathan|7|11|Islandwalk| +Into the Roil|Commander 2018|92|C|{1}{U}|Instant|||Kicker {1}{U}$Return target nonland permanent to its owner's hand. If this spell was kicked, draw a card.| +Jeskai Infiltrator|Commander 2018|93|R|{2}{U}|Creature - Human Monk|2|3|Jeskai Infiltrator can't be blocked as long as you control no other creatures.$When Jeskai Infiltrator deals combat damage to a player, exile it and the top card of your library in a face-down pile, shuffle that pile, then manifest those cards.| Mulldrifter|Commander 2018|94|U|{4}{U}|Creature - Elemental|2|2|Flying$When Mulldrifter enters the battlefield, draw two cards.$Evoke {2}{U}| +Ninja of the Deep Hours|Commander 2018|95|C|{3}{U}|Creature - Human Ninja|2|2|Ninjutsu {1}{U}$Whenever Ninja of the Deep Hours deals combat damage to a player, you may draw a card.| +Ponder|Commander 2018|96|C|{U}|Sorcery|||Look at the top three cards of your library, then put them back in any order. You may shuffle your library.$Draw a card.| Portent|Commander 2018|97|C|{U}|Sorcery|||Look at the top three cards of target player's library, then put them back in any order. You may have that player shuffle their library.$Draw a card at the beginning of the next turn's upkeep.| Predict|Commander 2018|98|U|{1}{U}|Instant|||Choose a card name, then target player puts the top card of their library into their graveyard. If that card has the chosen name, you draw two cards. Otherwise, you draw a card.| +Reverse Engineer|Commander 2018|99|U|{3}{U}{U}|Sorcery|||Improvise$Draw three cards.| +Saheeli's Artistry|Commander 2018|100|R|{4}{U}{U}|Sorcery|||Choose one or both —$• Create a token that's a copy of target artifact.$• Create a token that's a copy of target creature, except it's an artifact in addition to its other types.| +Sharding Sphinx|Commander 2018|101|R|{4}{U}{U}|Artifact Creature - Sphinx|4|4|Flying$Whenever an artifact creature you control deals combat damage to a player, you may create a 1/1 blue Thopter artifact creature token with flying.| +Sigiled Starfish|Commander 2018|102|C|{1}{U}|Creature - Starfish|0|3|{T}: Scry 1.| +Sphinx of Jwar Isle|Commander 2018|103|R|{4}{U}{U}|Creature - Sphinx|5|5|Flying$Shroud| +Sphinx of Uthuun|Commander 2018|104|R|{5}{U}{U}|Creature - Sphinx|5|6|Flying$When Sphinx of Uthuun enters the battlefield, reveal the top five cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other into your graveyard.| +Telling Time|Commander 2018|105|C|{1}{U}|Instant|||Look at the top three cards of your library. Put one of those cards into your hand, one on top of your library, and one on the bottom of your library.| +Thirst for Knowledge|Commander 2018|106|U|{2}{U}|Instant|||Draw three cards. Then discard two cards unless you discard an artifact card.| Thopter Spy Network|Commander 2018|107|R|{2}{U}{U}|Enchantment|||At the beginning of your upkeep, if you control an artifact, create a 1/1 colorless Thopter artifact creature token with flying.$Whenever one or more artifact creatures you control deal combat damage to a player, draw a card.| +Tidings|Commander 2018|108|U|{3}{U}{U}|Sorcery|||Draw four cards.| +Treasure Hunt|Commander 2018|109|C|{1}{U}|Sorcery|||Reveal cards from the top of your library until you reveal a nonland card, then put all cards revealed this way into your hand.| +Vow of Flight|Commander 2018|110|U|{2}{U}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +2/+2, has flying, and can't attack you or a planeswalker you control.| +Whirler Rogue|Commander 2018|111|U|{2}{U}{U}|Creature - Human Rogue Artificer|2|2|When Whirler Rogue enters the battlefield, create two 1/1 colorless Thopter artifact creature tokens with flying.$Tap two untapped artifacts you control: Target creature can't be blocked this turn.| +Whitewater Naiads|Commander 2018|112|U|{3}{U}{U}|Enchantment Creature - Nymph|4|4|Constellation — Whenever Whitewater Naiads or another enchantment enters the battlefield under your control, target creature can't be blocked this turn.| +Army of the Damned|Commander 2018|113|M|{5}{B}{B}{B}|Sorcery|||Create thirteen tapped 2/2 black Zombie creature tokens.$Flashback {7}{B}{B}{B}| +Moonlight Bargain|Commander 2018|114|R|{3}{B}{B}|Instant|||Look at the top five cards of your library. For each card, put that card into your graveyard unless you pay 2 life. Then put the rest into your hand.| Phyrexian Delver|Commander 2018|115|R|{3}{B}{B}|Creature - Zombie|3|2|When Phyrexian Delver enters the battlefield, return target creature card from your graveyard to the battlefield. You lose life equal to that card's converted mana cost.| +Retreat to Hagra|Commander 2018|116|U|{2}{B}|Enchantment|||Landfall — Whenever a land enters the battlefield under your control, choose one —$• Target creature gets +1/+0 and gains deathtouch until end of turn.$• Each opponent loses 1 life and you gain 1 life.| Ruinous Path|Commander 2018|117|R|{1}{B}{B}|Sorcery|||Destroy target creature or planeswalker.$Awaken 4—{5}{B}{B}| +Soul of Innistrad|Commander 2018|118|M|{4}{B}{B}|Creature - Avatar|6|6|Deathtouch${3}{B}{B}: Return up to three target creature cards from your graveyard to your hand.${3}{B}{B}, Exile Soul of Innistrad from your graveyard: Return up to three target creature cards from your graveyard to your hand.| +Stitch Together|Commander 2018|119|U|{B}{B}|Sorcery|||Return target creature card from your graveyard to your hand.$Threshold — Return that card from your graveyard to the battlefield instead if seven or more cards are in your graveyard.| +Blasphemous Act|Commander 2018|120|R|{8}{R}|Sorcery|||This spell costs {1} less to cast for each creature on the battlefield.$Blasphemous Act deals 13 damage to each creature.| Chain Reaction|Commander 2018|121|R|{2}{R}{R}|Sorcery|||Chain Reaction deals X damage to each creature, where X is the number of creatures on the battlefield.| Chaos Warp|Commander 2018|122|R|{2}{R}|Instant|||The owner of target permanent shuffles it into their library, then reveals the top card of their library. If it's a permanent card, they put it onto the battlefield.| +Flameblast Dragon|Commander 2018|123|R|{4}{R}{R}|Creature - Dragon|5|5|Flying$Whenever Flameblast Dragon attacks, you may pay {X}{R}. If you do, Flameblast Dragon deals X damage to any target.| +Hellkite Igniter|Commander 2018|124|R|{5}{R}{R}|Creature - Dragon|5|5|Flying, haste${1}{R}: Hellkite Igniter gets +X/+0 until end of turn, where X is the number of artifacts you control.| +Magmaquake|Commander 2018|125|R|{X}{R}{R}|Instant|||Magmaquake deals X damage to each creature without flying and each planeswalker.| +Thopter Engineer|Commander 2018|126|U|{2}{R}|Creature - Human Artificer|1|3|When Thopter Engineer enters the battlefield, create a 1/1 colorless Thopter artifact creature token with flying.$Artifact creatures you control have haste.| +Acidic Slime|Commander 2018|127|U|{3}{G}{G}|Creature - Ooze|2|2|Deathtouch$When Acidic Slime enters the battlefield, destroy target artifact, enchantment, or land.| +Aura Gnarlid|Commander 2018|128|C|{2}{G}|Creature - Beast|2|2|Creatures with power less than Aura Gnarlid's power can't block it.$Aura Gnarlid gets +1/+1 for each Aura on the battlefield.| Avenger of Zendikar|Commander 2018|129|M|{5}{G}{G}|Creature - Elemental|5|5|When Avenger of Zendikar enters the battlefield, create a 0/1 green Plant creature token for each land you control.$Landfall — Whenever a land enters the battlefield under your control, you may put a +1/+1 counter on each Plant creature you control.| +Baloth Woodcrasher|Commander 2018|130|U|{4}{G}{G}|Creature - Beast|4|4|Landfall — Whenever a land enters the battlefield under your control, Baloth Woodcrasher gets +4/+4 and gains trample until end of turn.| Bear Umbra|Commander 2018|131|R|{2}{G}{G}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +2/+2 and has "Whenever this creature attacks, untap all lands you control."$Totem armor| +Boon Satyr|Commander 2018|132|R|{1}{G}{G}|Enchantment Creature - Satyr|4|2|Flash$Bestow {3}{G}{G}$Enchanted creature gets +4/+2.| +Borderland Explorer|Commander 2018|133|C|{1}{G}|Creature - Elf Scout|3|1|When Borderland Explorer enters the battlefield, each player may discard a card. Each player who discarded a card this way may search their library for a basic land card, reveal it, put it into their hand, then shuffle their library.| Budoka Gardener|Commander 2018|134|R|{1}{G}|Creature - Human Monk|2|1|{T}: You may put a land card from your hand onto the battlefield. If you control ten or more lands, flip Budoka Gardener.| Centaur Vinecrasher|Commander 2018|135|R|{3}{G}|Creature - Plant Centaur|1|1|Trample$Centaur Vinecrasher enters the battlefield with a number of +1/+1 counters on it equal to the number of land cards in all graveyards.$Whenever a land card is put into a graveyard from anywhere, you may pay {G}{G}. If you do, return Centaur Vinecrasher from your graveyard to your hand.| +Consign to Dust|Commander 2018|136|U|{2}{G}|Instant|||Strive — This spell costs {2}{G} more to cast for each target beyond the first.$Destroy any number of target artifacts and/or enchantments.| +Creeping Renaissance|Commander 2018|137|R|{3}{G}{G}|Sorcery|||Choose a permanent type. Return all cards of the chosen type from your graveyard to your hand.$Flashback {5}{G}{G}| +Cultivate|Commander 2018|138|C|{2}{G}|Sorcery|||Search your library for up to two basic land cards, reveal those cards, and put one onto the battlefield tapped and the other into your hand. Then shuffle your library.| +Dawn's Reflection|Commander 2018|139|C|{3}{G}|Enchantment - Aura|||Enchant land$Whenever enchanted land is tapped for mana, its controller adds an additional two mana in any combination of colors.| Eidolon of Blossoms|Commander 2018|140|R|{2}{G}{G}|Enchantment Creature - Spirit|2|2|Constellation — Whenever Eidolon of Blossoms or another enchantment enters the battlefield under your control, draw a card.| Enchantress's Presence|Commander 2018|141|R|{2}{G}|Enchantment|||Whenever you cast an enchantment spell, draw a card.| +Epic Proportions|Commander 2018|142|R|{4}{G}{G}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature gets +5/+5 and has trample.| +Explore|Commander 2018|143|C|{1}{G}|Sorcery|||You may play an additional land this turn.$Draw a card.| Explosive Vegetation|Commander 2018|144|U|{3}{G}|Sorcery|||Search your library for up to two basic land cards and put them onto the battlefield tapped. Then shuffle your library.| +Far Wanderings|Commander 2018|145|C|{2}{G}|Sorcery|||Search your library for a basic land card, put that card onto the battlefield tapped, then shuffle your library.$Threshold — If seven or more cards are in your graveyard, instead search your library for up to three basic land cards, put them onto the battlefield tapped, then shuffle your library.| +Farhaven Elf|Commander 2018|146|C|{2}{G}|Creature - Elf Druid|1|1|When Farhaven Elf enters the battlefield, you may search your library for a basic land card and put it onto the battlefield tapped. If you do, shuffle your library.| +Fertile Ground|Commander 2018|147|C|{1}{G}|Enchantment - Aura|||Enchant land$Whenever enchanted land is tapped for mana, its controller adds an additional one mana of any color.| +Grapple with the Past|Commander 2018|148|C|{1}{G}|Instant|||Put the top three cards of your library into your graveyard, then you may return a creature or land card from your graveyard to your hand.| +Ground Seal|Commander 2018|149|R|{1}{G}|Enchantment|||When Ground Seal enters the battlefield, draw a card.$Cards in graveyards can't be the targets of spells or abilities.| +Harrow|Commander 2018|150|C|{2}{G}|Instant|||As an additional cost to cast this spell, sacrifice a land.$Search your library for up to two basic land cards and put them onto the battlefield. Then shuffle your library.| Herald of the Pantheon|Commander 2018|151|R|{1}{G}|Creature - Centaur Shaman|2|2|Enchantment spells you cast cost {1} less to cast.$Whenever you cast an enchantment spell, you gain 1 life.| +Hunting Wilds|Commander 2018|152|U|{3}{G}|Sorcery|||Kicker {3}{G}$Search your library for up to two Forest cards and put them onto the battlefield tapped. Then shuffle your library.$If this spell was kicked, untap all Forests put onto the battlefield this way. They become 3/3 green creatures with haste that are still lands.| Hydra Omnivore|Commander 2018|153|M|{4}{G}{G}|Creature - Hydra|8|8|Whenever Hydra Omnivore deals combat damage to an opponent, it deals that much damage to each other opponent.| +Khalni Heart Expedition|Commander 2018|154|C|{1}{G}|Enchantment|||Landfall — Whenever a land enters the battlefield under your control, you may put a quest counter on Khalni Heart Expedition.$Remove three quest counters from Khalni Heart Expedition and sacrifice it: Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle your library.| +Kruphix's Insight|Commander 2018|155|C|{2}{G}|Sorcery|||Reveal the top six cards of your library. Put up to three enchantment cards from among them into your hand and the rest of the revealed cards into your graveyard.| +Moldgraf Monstrosity|Commander 2018|156|R|{4}{G}{G}{G}|Creature - Insect|8|8|Trample$When Moldgraf Monstrosity dies, exile it, then return two creature cards at random from your graveyard to the battlefield.| +Overgrowth|Commander 2018|157|C|{2}{G}|Enchantment - Aura|||Enchant land$Whenever enchanted land is tapped for mana, its controller adds an additional {G}{G}.| Rampaging Baloths|Commander 2018|158|R|{4}{G}{G}|Creature - Beast|6|6|Trample$Landfall — Whenever a land enters the battlefield under your control, you may create a 4/4 green Beast creature token.| +Reclamation Sage|Commander 2018|159|U|{2}{G}|Creature - Elf Shaman|2|1|When Reclamation Sage enters the battlefield, you may destroy target artifact or enchantment.| +Sakura-Tribe Elder|Commander 2018|160|C|{1}{G}|Creature - Snake Shaman|1|1|Sacrifice Sakura-Tribe Elder: Search your library for a basic land card, put that card onto the battlefield tapped, then shuffle your library.| Scute Mob|Commander 2018|161|R|{G}|Creature - Insect|1|1|At the beginning of your upkeep, if you control five or more lands, put four +1/+1 counters on Scute Mob.| +Snake Umbra|Commander 2018|162|C|{2}{G}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +1/+1 and has "Whenever this creature deals damage to an opponent, you may draw a card."$Totem armor| Spawning Grounds|Commander 2018|163|R|{6}{G}{G}|Enchantment - Aura|||Enchant land$Enchanted land has "{T}: Create a 5/5 green Beast creature token with trample."| +Vow of Wildness|Commander 2018|164|U|{2}{G}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +3/+3, has trample, and can't attack you or a planeswalker you control.| +Wild Growth|Commander 2018|165|C|{G}|Enchantment - Aura|||Enchant land$Whenever enchanted land is tapped for mana, its controller adds an additional {G}.| +Yavimaya Elder|Commander 2018|166|C|{1}{G}{G}|Creature - Human Druid|2|1|When Yavimaya Elder dies, you may search your library for up to two basic land cards, reveal them, and put them into your hand. If you do, shuffle your library.${2}, Sacrifice Yavimaya Elder: Draw a card.| +Yavimaya Enchantress|Commander 2018|167|C|{2}{G}|Creature - Human Druid|2|2|Yavimaya Enchantress gets +1/+1 for each enchantment on the battlefield.| Aethermage's Touch|Commander 2018|168|R|{2}{W}{U}|Instant|||Reveal the top four cards of your library. You may put a creature card from among them onto the battlefield. It gains "At the beginning of your end step, return this creature to its owner's hand." Then put the rest of the cards revealed this way on the bottom of your library in any order.| +Bant Charm|Commander 2018|169|U|{G}{W}{U}|Instant|||Choose one —$• Destroy target artifact.$• Put target creature on the bottom of its owner's library.$• Counter target instant spell.| Bruna, Light of Alabaster|Commander 2018|170|M|{3}{W}{W}{U}|Legendary Creature - Angel|5|5|Flying, vigilance$Whenever Bruna, Light of Alabaster attacks or blocks, you may attach to it any number of Auras on the battlefield and you may put onto the battlefield attached to it any number of Aura cards that could enchant it from your graveyard and/or hand.| +Charnelhoard Wurm|Commander 2018|171|R|{4}{B}{R}{G}|Creature - Wurm|6|6|Trample$Whenever Charnelhoard Wurm deals damage to an opponent, you may return target card from your graveyard to your hand.| +Cold-Eyed Selkie|Commander 2018|172|R|{1}{G/U}{G/U}|Creature - Merfolk Rogue|1|1|Islandwalk$Whenever Cold-Eyed Selkie deals combat damage to a player, you may draw that many cards.| +Daxos of Meletis|Commander 2018|173|R|{1}{W}{U}|Legendary Creature - Human Soldier|2|2|Daxos of Meletis can't be blocked by creatures with power 3 or greater.$Whenever Daxos of Meletis deals combat damage to a player, exile the top card of that player's library. You gain life equal to that card's converted mana cost. Until end of turn, you may cast that card and you may spend mana as though it were mana of any color to cast that spell.| +Deathreap Ritual|Commander 2018|174|U|{2}{B}{G}|Enchantment|||Morbid — At the beginning of each end step, if a creature died this turn, you may draw a card.| +Decimate|Commander 2018|175|R|{2}{R}{G}|Sorcery|||Destroy target artifact, target creature, target enchantment, and target land.| +Duskmantle Seer|Commander 2018|176|R|{2}{U}{B}|Creature - Vampire Wizard|4|4|Flying$At the beginning of your upkeep, each player reveals the top card of their library, loses life equal to that card's converted mana cost, then puts it into their hand.| +Elderwood Scion|Commander 2018|177|R|{3}{G}{W}|Creature - Elemental|4|4|Trample, lifelink$Spells you cast that target Elderwood Scion cost {2} less to cast.$Spells your opponents cast that target Elderwood Scion cost {2} more to cast.| +Enigma Sphinx|Commander 2018|178|R|{4}{W}{U}{B}|Artifact Creature - Sphinx|5|4|Flying$When Enigma Sphinx is put into your graveyard from the battlefield, put it into your library third from the top.$Cascade| +Esper Charm|Commander 2018|179|U|{W}{U}{B}|Instant|||Choose one —$• Destroy target enchantment.$• Draw two cards.$• Target player discards two cards.| Finest Hour|Commander 2018|180|R|{2}{G}{W}{U}|Enchantment|||Exalted$Whenever a creature you control attacks alone, if it's the first combat phase of the turn, untap that creature. After this phase, there is an additional combat phase.| +Gaze of Granite|Commander 2018|181|R|{X}{B}{B}{G}|Sorcery|||Destroy each nonland permanent with converted mana cost X or less.| +Grisly Salvage|Commander 2018|182|C|{B}{G}|Instant|||Reveal the top five cards of your library. You may put a creature or land card from among them into your hand. Put the rest into your graveyard.| +High Priest of Penance|Commander 2018|183|R|{W}{B}|Creature - Human Cleric|1|1|Whenever High Priest of Penance is dealt damage, you may destroy target nonland permanent.| +Lavalanche|Commander 2018|184|R|{X}{B}{R}{G}|Sorcery|||Lavalanche deals X damage to target player or planeswalker and each creature that player or that planeswalker's controller controls.| +Maverick Thopterist|Commander 2018|185|U|{3}{U}{R}|Creature - Human Artificer|2|2|Improvise$When Maverick Thopterist enters the battlefield, create two 1/1 colorless Thopter artifact creature tokens with flying.| +Mortify|Commander 2018|186|U|{1}{W}{B}|Instant|||Destroy target creature or enchantment.| +Putrefy|Commander 2018|187|U|{1}{B}{G}|Instant|||Destroy target artifact or creature. It can't be regenerated.| +Righteous Authority|Commander 2018|188|R|{3}{W}{U}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +1/+1 for each card in its controller's hand.$At the beginning of the draw step of enchanted creature's controller, that player draws an additional card.| +Rubblehulk|Commander 2018|189|R|{4}{R}{G}|Creature - Elemental|*|*|Rubblehulk's power and toughness are each equal to the number of lands you control.$Bloodrush — {1}{R}{G}, Discard Rubblehulk: Target attacking creature gets +X/+X until end of turn, where X is the number of lands you control.| +Savage Twister|Commander 2018|190|U|{X}{R}{G}|Sorcery|||Savage Twister deals X damage to each creature.| Silent-Blade Oni|Commander 2018|191|R|{3}{U}{U}{B}{B}|Creature - Demon Ninja|6|5|Ninjutsu {4}{U}{B}$Whenever Silent-Blade Oni deals combat damage to a player, look at that player's hand. You may cast a nonland card in it without paying that card's mana cost.| +Unflinching Courage|Commander 2018|192|U|{1}{G}{W}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +2/+2 and has trample and lifelink.| +Utter End|Commander 2018|193|R|{2}{W}{B}|Instant|||Exile target nonland permanent.| +Worm Harvest|Commander 2018|194|R|{2}{B/G}{B/G}{B/G}|Sorcery|||Create a 1/1 black and green Worm creature token for each land card in your graveyard.$Retrace| +Zendikar Incarnate|Commander 2018|195|U|{2}{R}{G}|Creature - Elemental|*|4|Zendikar Incarnate's power is equal to the number of lands you control.| +Azorius Signet|Commander 2018|196|U|{2}|Artifact|||{1}, {T}: Add {W}{U}.| +Blinkmoth Urn|Commander 2018|197|R|{5}|Artifact|||At the beginning of each player's precombat main phase, if Blinkmoth Urn is untapped, that player adds {C} for each artifact they control.| +Bosh, Iron Golem|Commander 2018|198|R|{8}|Legendary Artifact Creature - Golem|6|7|Trample${3}{R}, Sacrifice an artifact: Bosh, Iron Golem deals damage equal to the sacrificed artifact's converted mana cost to any target.| +Chief of the Foundry|Commander 2018|199|U|{3}|Artifact Creature - Construct|2|3|Other artifact creatures you control get +1/+1.| Commander's Sphere|Commander 2018|200|C|{3}|Artifact|||{T}: Add one mana of any color in your commander's color identity.$Sacrifice Commander's Sphere: Draw a card.| Crystal Ball|Commander 2018|201|U|{3}|Artifact|||{1}, {T}: Scry 2.| +Darksteel Juggernaut|Commander 2018|202|R|{5}|Artifact Creature - Juggernaut|*|*|Indestructible$Darksteel Juggernaut's power and toughness are each equal to the number of artifacts you control.$Darksteel Juggernaut attacks each combat if able.| +Dimir Signet|Commander 2018|203|U|{2}|Artifact|||{1}, {T}: Add {U}{B}.| +Dreamstone Hedron|Commander 2018|204|U|{6}|Artifact|||{T}: Add {C}{C}{C}.${3}, {T}, Sacrifice Dreamstone Hedron: Draw three cards.| +Duplicant|Commander 2018|205|R|{6}|Artifact Creature - Shapeshifter|2|4|Imprint — When Duplicant enters the battlefield, you may exile target nontoken creature.$As long as a card exiled with Duplicant is a creature card, Duplicant has the power, toughness, and creature types of the last creature card exiled with Duplicant. It's still a Shapeshifter.| +Hedron Archive|Commander 2018|206|U|{4}|Artifact|||{T}: Add {C}{C}.${2}, {T}, Sacrifice Hedron Archive: Draw two cards.| +Izzet Signet|Commander 2018|207|U|{2}|Artifact|||{1}, {T}: Add {U}{R}.| +Magnifying Glass|Commander 2018|208|U|{3}|Artifact|||{T}: Add {C}.${4}, {T}: Investigate.| +Mimic Vat|Commander 2018|209|R|{3}|Artifact|||Imprint — Whenever a nontoken creature dies, you may exile that card. If you do, return each other card exiled with Mimic Vat to its owner's graveyard.${3}, {T}: Create a token that's a copy of a card exiled with Mimic Vat. It gains haste. Exile it at the beginning of the next end step.| +Mind Stone|Commander 2018|210|C|{2}|Artifact|||{T}: Add {C}.${1}, {T}, Sacrifice Mind Stone: Draw a card.| +Mirrorworks|Commander 2018|211|R|{5}|Artifact|||Whenever another nontoken artifact enters the battlefield under your control, you may pay {2}. If you do, create a token that's a copy of that artifact.| +Myr Battlesphere|Commander 2018|212|R|{7}|Artifact Creature - Myr Construct|4|7|When Myr Battlesphere enters the battlefield, create four 1/1 colorless Myr artifact creature tokens.$Whenever Myr Battlesphere attacks, you may tap X untapped Myr you control. If you do, Myr Battlesphere gets +X/+0 until end of turn and deals X damage to the player or planeswalker it's attacking.| +Orzhov Signet|Commander 2018|213|U|{2}|Artifact|||{1}, {T}: Add {W}{B}.| +Pilgrim's Eye|Commander 2018|214|C|{3}|Artifact Creature - Thopter|1|1|Flying$When Pilgrim's Eye enters the battlefield, you may search your library for a basic land card, reveal it, put it into your hand, then shuffle your library.| +Prismatic Lens|Commander 2018|215|U|{2}|Artifact|||{T}: Add {C}.${1}, {T}: Add one mana of any color.| +Prototype Portal|Commander 2018|216|R|{4}|Artifact|||Imprint — When Prototype Portal enters the battlefield, you may exile an artifact card from your hand.${X}, {T}: Create a token that's a copy of the exiled card. X is the converted mana cost of that card.| +Psychosis Crawler|Commander 2018|217|R|{5}|Artifact Creature - Horror|*|*|Psychosis Crawler's power and toughness are each equal to the number of cards in your hand.$Whenever you draw a card, each opponent loses 1 life.| +Scrabbling Claws|Commander 2018|218|U|{1}|Artifact|||{T}: Target player exiles a card from their graveyard.${1}, Sacrifice Scrabbling Claws: Exile target card from a graveyard. Draw a card.| +Scuttling Doom Engine|Commander 2018|219|R|{6}|Artifact Creature - Construct|6|6|Scuttling Doom Engine can't be blocked by creatures with power 2 or less.$When Scuttling Doom Engine dies, it deals 6 damage to target opponent or planeswalker.| +Seer's Lantern|Commander 2018|220|C|{3}|Artifact|||{T}: Add {C}.| +Seer's Sundial|Commander 2018|221|R|{4}|Artifact|||Landfall — Whenever a land enters the battlefield under your control, you may pay {2}. If you do, draw a card.| Sol Ring|Commander 2018|222|U|{1}|Artifact|||{T}: Add {C}{C}.| +Soul of New Phyrexia|Commander 2018|223|M|{6}|Artifact Creature - Avatar|6|6|Trample${5}: Permanents you control gain indestructible until end of turn.${5}, Exile Soul of New Phyrexia from your graveyard: Permanents you control gain indestructible until end of turn.| +Steel Hellkite|Commander 2018|224|R|{6}|Artifact Creature - Dragon|5|5|Flying${2}: Steel Hellkite gets +1/+0 until end of turn.${X}: Destroy each nonland permanent with converted mana cost X whose controller was dealt combat damage by Steel Hellkite this turn. Activate this ability only once each turn.| Swiftfoot Boots|Commander 2018|225|U|{2}|Artifact - Equipment|||Equipped creature has hexproof and haste.$Equip {1}| +Thopter Assembly|Commander 2018|226|R|{6}|Artifact Creature - Thopter|5|5|Flying$At the beginning of your upkeep, if you control no Thopters other than Thopter Assembly, return Thopter Assembly to its owner's hand and create five 1/1 colorless Thopter artifact creature tokens with flying.| +Unstable Obelisk|Commander 2018|227|U|{3}|Artifact|||{T}: Add {C}.${7}, {T}, Sacrifice Unstable Obelisk: Destroy target permanent.| +Unwinding Clock|Commander 2018|228|R|{4}|Artifact|||Untap all artifacts you control during each other player's untap step.| +Vessel of Endless Rest|Commander 2018|229|U|{3}|Artifact|||When Vessel of Endless Rest enters the battlefield, put target card from a graveyard on the bottom of its owner's library.${T}: Add one mana of any color.| +Worn Powerstone|Commander 2018|230|U|{3}|Artifact|||Worn Powerstone enters the battlefield tapped.${T}: Add {C}{C}.| +Akoum Refuge|Commander 2018|231|U||Land|||Akoum Refuge enters the battlefield tapped.$When Akoum Refuge enters the battlefield, you gain 1 life.${T}: Add {B} or {R}.| +Arcane Sanctum|Commander 2018|232|U||Land|||Arcane Sanctum enters the battlefield tapped.${T}: Add {W}, {U}, or {B}.| +Azorius Chancery|Commander 2018|233|U||Land|||Azorius Chancery enters the battlefield tapped.$When Azorius Chancery enters the battlefield, return a land you control to its owner's hand.${T}: Add {W}{U}.| +Azorius Guildgate|Commander 2018|234|C||Land - Gate|||Azorius Guildgate enters the battlefield tapped.${T}: Add {W} or {U}.| +Barren Moor|Commander 2018|235|C||Land|||Barren Moor enters the battlefield tapped.${T}: Add {B}.$Cycling {B}| +Blighted Woodland|Commander 2018|236|U||Land|||{T}: Add {C}.${3}{G}, {T}, Sacrifice Blighted Woodland: Search your library for up to two basic land cards and put them onto the battlefield tapped. Then shuffle your library.| +Blossoming Sands|Commander 2018|237|C||Land|||Blossoming Sands enters the battlefield tapped.$When Blossoming Sands enters the battlefield, you gain 1 life.${T}: Add {G} or {W}.| +Bojuka Bog|Commander 2018|238|C||Land|||Bojuka Bog enters the battlefield tapped.$When Bojuka Bog enters the battlefield, exile all cards from target player's graveyard.${T}: Add {B}.| +Buried Ruin|Commander 2018|239|U||Land|||{T}: Add {C}.${2}, {T}, Sacrifice Buried Ruin: Return target artifact card from your graveyard to your hand.| Command Tower|Commander 2018|240|C||Land|||{T}: Add one mana of any color in your commander's color identity.| +Darksteel Citadel|Commander 2018|241|U||Artifact Land|||Indestructible${T}: Add {C}.| +Dimir Aqueduct|Commander 2018|242|U||Land|||Dimir Aqueduct enters the battlefield tapped.$When Dimir Aqueduct enters the battlefield, return a land you control to its owner's hand.${T}: Add {U}{B}.| +Dimir Guildgate|Commander 2018|243|C||Land - Gate|||Dimir Guildgate enters the battlefield tapped.${T}: Add {U} or {B}.| +Dismal Backwater|Commander 2018|244|C||Land|||Dismal Backwater enters the battlefield tapped.$When Dismal Backwater enters the battlefield, you gain 1 life.${T}: Add {U} or {B}.| +Evolving Wilds|Commander 2018|245|C||Land|||{T}, Sacrifice Evolving Wilds: Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library.| +Forgotten Cave|Commander 2018|246|C||Land|||Forgotten Cave enters the battlefield tapped.${T}: Add {R}.$Cycling {R}| +Forsaken Sanctuary|Commander 2018|247|U||Land|||Forsaken Sanctuary enters the battlefield tapped.${T}: Add {W} or {B}.| +Foundry of the Consuls|Commander 2018|248|U||Land|||{T}: Add {C}.${5}, {T}, Sacrifice Foundry of the Consuls: Create two 1/1 colorless Thopter artifact creature tokens with flying.| +Golgari Rot Farm|Commander 2018|249|U||Land|||Golgari Rot Farm enters the battlefield tapped.$When Golgari Rot Farm enters the battlefield, return a land you control to its owner's hand.${T}: Add {B}{G}.| +Great Furnace|Commander 2018|250|C||Artifact Land|||{T}: Add {R}.| +Grim Backwoods|Commander 2018|251|R||Land|||{T}: Add {C}.${2}{B}{G}, {T}, Sacrifice a creature: Draw a card.| +Gruul Turf|Commander 2018|252|U||Land|||Gruul Turf enters the battlefield tapped.$When Gruul Turf enters the battlefield, return a land you control to its owner's hand.${T}: Add {R}{G}.| +Halimar Depths|Commander 2018|253|C||Land|||Halimar Depths enters the battlefield tapped.$When Halimar Depths enters the battlefield, look at the top three cards of your library, then put them back in any order.${T}: Add {U}.| +Haunted Fengraf|Commander 2018|254|C||Land|||{T}: Add {C}.${3}, {T}, Sacrifice Haunted Fengraf: Return a creature card at random from your graveyard to your hand.| +Highland Lake|Commander 2018|255|U||Land|||Highland Lake enters the battlefield tapped.${T}: Add {U} or {R}.| +Izzet Boilerworks|Commander 2018|256|U||Land|||Izzet Boilerworks enters the battlefield tapped.$When Izzet Boilerworks enters the battlefield, return a land you control to its owner's hand.${T}: Add {U}{R}.| +Izzet Guildgate|Commander 2018|257|C||Land - Gate|||Izzet Guildgate enters the battlefield tapped.${T}: Add {U} or {R}.| +Jund Panorama|Commander 2018|258|C||Land|||{T}: Add {C}.${1}, {T}, Sacrifice Jund Panorama: Search your library for a basic Swamp, Mountain, or Forest card and put it onto the battlefield tapped. Then shuffle your library.| +Jungle Hollow|Commander 2018|259|C||Land|||Jungle Hollow enters the battlefield tapped.$When Jungle Hollow enters the battlefield, you gain 1 life.${T}: Add {B} or {G}.| +Jwar Isle Refuge|Commander 2018|260|U||Land|||Jwar Isle Refuge enters the battlefield tapped.$When Jwar Isle Refuge enters the battlefield, you gain 1 life.${T}: Add {U} or {B}.| +Kazandu Refuge|Commander 2018|261|U||Land|||Kazandu Refuge enters the battlefield tapped.$When Kazandu Refuge enters the battlefield, you gain 1 life.${T}: Add {R} or {G}.| +Khalni Garden|Commander 2018|262|C||Land|||Khalni Garden enters the battlefield tapped.$When Khalni Garden enters the battlefield, create a 0/1 green Plant creature token.${T}: Add {G}.| +Krosan Verge|Commander 2018|263|U||Land|||Krosan Verge enters the battlefield tapped.${T}: Add {C}.${2}, {T}, Sacrifice Krosan Verge: Search your library for a Forest card and a Plains card and put them onto the battlefield tapped. Then shuffle your library.| +Lonely Sandbar|Commander 2018|264|C||Land|||Lonely Sandbar enters the battlefield tapped.${T}: Add {U}.$Cycling {U}| +Meandering River|Commander 2018|265|U||Land|||Meandering River enters the battlefield tapped.${T}: Add {W} or {U}.| +Mortuary Mire|Commander 2018|266|C||Land|||Mortuary Mire enters the battlefield tapped.$When Mortuary Mire enters the battlefield, you may put target creature card from your graveyard on top of your library.${T}: Add {B}.| +Mosswort Bridge|Commander 2018|267|R||Land|||Hideaway${T}: Add {G}.${G}, {T}: You may play the exiled card without paying its mana cost if creatures you control have total power 10 or greater.| Mountain Valley|Commander 2018|268|U||Land|||Mountain Valley enters the battlefield tapped.${T}, Sacrifice Mountain Valley: Search your library for a Mountain or Forest card and put it onto the battlefield. Then shuffle your library.| Myriad Landscape|Commander 2018|269|U||Land|||Myriad Landscape enters the battlefield tapped.${T}: Add {C}.${2}, {T}, Sacrifice Myriad Landscape: Search your library for up to two basic land cards that share a land type, put them onto the battlefield tapped, then shuffle your library.| -Rocky Tar Pit|Commander 2018|274|U||Land|||Rocky Tar Pit enters the battlefield tapped.${T}, Sacrifice Rocky Tar Pit: Search your library for a Swamp or Mountain card and put it onto the battlefield. Then shuffle your library.| \ No newline at end of file +New Benalia|Commander 2018|270|U||Land|||New Benalia enters the battlefield tapped.$When New Benalia enters the battlefield, scry 1.${T}: Add {W}.| +Orzhov Basilica|Commander 2018|271|U||Land|||Orzhov Basilica enters the battlefield tapped.$When Orzhov Basilica enters the battlefield, return a land you control to its owner's hand.${T}: Add {W}{B}.| +Orzhov Guildgate|Commander 2018|272|C||Land - Gate|||Orzhov Guildgate enters the battlefield tapped.${T}: Add {W} or {B}.| +Rakdos Carnarium|Commander 2018|273|C||Land|||Rakdos Carnarium enters the battlefield tapped.$When Rakdos Carnarium enters the battlefield, return a land you control to its owner's hand.${T}: Add {B}{R}.| +Rocky Tar Pit|Commander 2018|274|U||Land|||Rocky Tar Pit enters the battlefield tapped.${T}, Sacrifice Rocky Tar Pit: Search your library for a Swamp or Mountain card and put it onto the battlefield. Then shuffle your library.| +Savage Lands|Commander 2018|275|U||Land|||Savage Lands enters the battlefield tapped.${T}: Add {B}, {R}, or {G}.| +Scoured Barrens|Commander 2018|276|C||Land|||Scoured Barrens enters the battlefield tapped.$When Scoured Barrens enters the battlefield, you gain 1 life.${T}: Add {W} or {B}.| +Seaside Citadel|Commander 2018|277|U||Land|||Seaside Citadel enters the battlefield tapped.${T}: Add {G}, {W}, or {U}.| +Seat of the Synod|Commander 2018|278|C||Artifact Land|||(Seat of the Synod isn't a spell.)${T}: Add {U}.| +Secluded Steppe|Commander 2018|279|C||Land|||Secluded Steppe enters the battlefield tapped.${T}: Add {W}.$Cycling {W}| +Sejiri Refuge|Commander 2018|280|U||Land|||Sejiri Refuge enters the battlefield tapped.$When Sejiri Refuge enters the battlefield, you gain 1 life.${T}: Add {W} or {U}.| +Selesnya Sanctuary|Commander 2018|281|C||Land|||Selesnya Sanctuary enters the battlefield tapped.$When Selesnya Sanctuary enters the battlefield, return a land you control to its owner's hand.${T}: Add {G}{W}.| +Simic Growth Chamber|Commander 2018|282|U||Land|||Simic Growth Chamber enters the battlefield tapped.$When Simic Growth Chamber enters the battlefield, return a land you control to its owner's hand.${T}: Add {G}{U}.| +Submerged Boneyard|Commander 2018|283|U||Land|||Submerged Boneyard enters the battlefield tapped.${T}: Add {U} or {B}.| +Swiftwater Cliffs|Commander 2018|284|C||Land|||Swiftwater Cliffs enters the battlefield tapped.$When Swiftwater Cliffs enters the battlefield, you gain 1 life.${T}: Add {U} or {R}.| +Temple of the False God|Commander 2018|285|U||Land|||{T}: Add {C}{C}. Activate this ability only if you control five or more lands.| +Terramorphic Expanse|Commander 2018|286|C||Land|||{T}, Sacrifice Terramorphic Expanse: Search your library for a basic land card and put it onto the battlefield tapped. Then shuffle your library.| +Thornwood Falls|Commander 2018|287|C||Land|||Thornwood Falls enters the battlefield tapped.$When Thornwood Falls enters the battlefield, you gain 1 life.${T}: Add {G} or {U}.| +Tranquil Cove|Commander 2018|288|C||Land|||Tranquil Cove enters the battlefield tapped.$When Tranquil Cove enters the battlefield, you gain 1 life.${T}: Add {W} or {U}.| +Tranquil Expanse|Commander 2018|289|U||Land|||Tranquil Expanse enters the battlefield tapped.${T}: Add {G} or {W}.| +Tranquil Thicket|Commander 2018|290|C||Land|||Tranquil Thicket enters the battlefield tapped.${T}: Add {G}.$Cycling {G}| +Warped Landscape|Commander 2018|291|C||Land|||{T}: Add {C}.${2}, {T}, Sacrifice Warped Landscape: Search your library for a basic land card and put it onto the battlefield tapped. Then shuffle your library.| +Woodland Stream|Commander 2018|292|C||Land|||Woodland Stream enters the battlefield tapped.${T}: Add {G} or {U}.| +Plains|Commander 2018|293|C||Basic Land - Plains|||({T}: Add {W}.)| +Plains|Commander 2018|294|C||Basic Land - Plains|||({T}: Add {W}.)| +Plains|Commander 2018|295|C||Basic Land - Plains|||({T}: Add {W}.)| +Island|Commander 2018|296|C||Basic Land - Island|||({T}: Add {U}.)| +Island|Commander 2018|297|C||Basic Land - Island|||({T}: Add {U}.)| +Island|Commander 2018|298|C||Basic Land - Island|||({T}: Add {U}.)| +Swamp|Commander 2018|299|C||Basic Land - Swamp|||({T}: Add {B}.)| +Swamp|Commander 2018|300|C||Basic Land - Swamp|||({T}: Add {B}.)| +Swamp|Commander 2018|301|C||Basic Land - Swamp|||({T}: Add {B}.)| +Mountain|Commander 2018|302|C||Basic Land - Mountain|||({T}: Add {R}.)| +Mountain|Commander 2018|303|C||Basic Land - Mountain|||({T}: Add {R}.)| +Mountain|Commander 2018|304|C||Basic Land - Mountain|||({T}: Add {R}.)| +Forest|Commander 2018|305|C||Basic Land - Forest|||({T}: Add {G}.)| +Forest|Commander 2018|306|C||Basic Land - Forest|||({T}: Add {G}.)| +Forest|Commander 2018|307|C||Basic Land - Forest|||({T}: Add {G}.)| \ No newline at end of file From fe65d595ac377ad1331188507a20ce919dd0f029 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Fri, 27 Jul 2018 20:38:05 -0400 Subject: [PATCH 53/71] Implemented Boreas Charger --- Mage.Sets/src/mage/cards/b/BoreasCharger.java | 168 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 169 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/b/BoreasCharger.java diff --git a/Mage.Sets/src/mage/cards/b/BoreasCharger.java b/Mage.Sets/src/mage/cards/b/BoreasCharger.java new file mode 100644 index 00000000000..826bf3c5987 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BoreasCharger.java @@ -0,0 +1,168 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.FilterPlayer; +import mage.filter.StaticFilters; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author TheElk801 + */ +public final class BoreasCharger extends CardImpl { + + public BoreasCharger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.PEGASUS); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Boreas Charger leaves the battlefield, choose an opponent who controls more lands than you. Search your library for a number of Plains cards equal to the difference and reveal them. Put one of them onto the battlefield tapped and the rest into your hand. Then shuffle your library. + this.addAbility(new LeavesBattlefieldTriggeredAbility( + new BoreasChargerEffect(), false + )); + } + + public BoreasCharger(final BoreasCharger card) { + super(card); + } + + @Override + public BoreasCharger copy() { + return new BoreasCharger(this); + } +} + +class BoreasChargerEffect extends OneShotEffect { + + private static final FilterPlayer filter + = new FilterPlayer("opponent who controls more lands than you"); + private static final FilterCard filter2 + = new FilterCard("Plains cards"); + private static final FilterCard filter3 + = new FilterCard("a card to put onto the battlefield tapped"); + + static { + filter.add(new BoreasChargerPredicate()); + filter2.add(new SubtypePredicate(SubType.PLAINS)); + } + + public BoreasChargerEffect() { + super(Outcome.Benefit); + this.staticText = "choose an opponent who controls more lands than you. " + + "Search your library for a number of Plains cards " + + "equal to the difference and reveal them. " + + "Put one of them onto the battlefield tapped " + + "and the rest into your hand. Then shuffle your library"; + } + + public BoreasChargerEffect(final BoreasChargerEffect effect) { + super(effect); + } + + @Override + public BoreasChargerEffect copy() { + return new BoreasChargerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getSourceId()); + if (controller == null) { + return false; + } + TargetPlayer target = new TargetPlayer(1, 1, true, filter); + controller.choose(outcome, target, source.getSourceId(), game); + Player opponent = game.getPlayer(target.getFirstTarget()); + if (opponent == null) { + controller.shuffleLibrary(source, game); + return false; + } + int landDifference = game.getBattlefield().getAllActivePermanents( + StaticFilters.FILTER_LANDS, opponent.getId(), game + ).size(); + landDifference -= game.getBattlefield().getAllActivePermanents( + StaticFilters.FILTER_LANDS, controller.getId(), game + ).size(); + landDifference = Math.abs(landDifference); + TargetCardInLibrary target2 + = new TargetCardInLibrary(0, landDifference, filter2); + Cards cardsToHand = new CardsImpl(); + if (controller.searchLibrary(target2, game)) { + for (UUID cardId : target2.getTargets()) { + Card card = game.getCard(cardId); + if (card != null) { + cardsToHand.add(card); + } + } + } + if (cardsToHand.isEmpty()) { + controller.shuffleLibrary(source, game); + return true; + } + TargetCard target3 = new TargetCard(Zone.LIBRARY, filter3); + Card cardToBattlefield = null; + if (controller.choose(outcome, cardsToHand, target3, game)) { + cardToBattlefield = cardsToHand.get(target2.getFirstTarget(), game); + cardsToHand.remove(cardToBattlefield); + } + if (cardToBattlefield != null) { + controller.moveCards( + cardToBattlefield, Zone.BATTLEFIELD, source, game, + true, false, true, null + ); + } + controller.moveCards(cardsToHand, Zone.HAND, source, game); + controller.shuffleLibrary(source, game); + return true; + } +} + +class BoreasChargerPredicate implements ObjectSourcePlayerPredicate> { + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Player targetPlayer = input.getObject(); + UUID playerId = input.getPlayerId(); + if (targetPlayer == null || playerId == null) { + return false; + } + if (!targetPlayer.hasOpponent(playerId, game)) { + return false; + } + int countTargetPlayer = game.getBattlefield().countAll( + StaticFilters.FILTER_LANDS, targetPlayer.getId(), game + ); + int countController = game.getBattlefield().countAll( + StaticFilters.FILTER_LANDS, playerId, game + ); + + return countTargetPlayer > countController; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 69211aa5edb..c3aa0955e28 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -50,6 +50,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Bojuka Bog", 238, Rarity.COMMON, mage.cards.b.BojukaBog.class)); cards.add(new SetCardInfo("Boon Satyr", 132, Rarity.RARE, mage.cards.b.BoonSatyr.class)); cards.add(new SetCardInfo("Borderland Explorer", 133, Rarity.COMMON, mage.cards.b.BorderlandExplorer.class)); + cards.add(new SetCardInfo("Boreas Charger", 1, Rarity.RARE, mage.cards.b.BoreasCharger.class)); cards.add(new SetCardInfo("Bosh, Iron Golem", 198, Rarity.RARE, mage.cards.b.BoshIronGolem.class)); cards.add(new SetCardInfo("Brainstorm", 82, Rarity.UNCOMMON, mage.cards.b.Brainstorm.class)); cards.add(new SetCardInfo("Brudiclad, Telchor Engineer", 39, Rarity.MYTHIC, mage.cards.b.BrudicladTelchorEngineer.class)); From 76d0baa792ed3aef22ca79918c1362c35d46b69f Mon Sep 17 00:00:00 2001 From: Will Hall Date: Fri, 27 Jul 2018 18:33:58 -0700 Subject: [PATCH 54/71] Implemented Gyrus, Waker of Corpses --- .../src/mage/cards/g/GyrusWakerOfCorpses.java | 129 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + .../common/ManaSpentToCastCount.java | 2 +- 3 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java diff --git a/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java b/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java new file mode 100644 index 00000000000..b7224b44243 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java @@ -0,0 +1,129 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.dynamicvalue.common.ManaSpentToCastCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author Will + */ +public final class GyrusWakerOfCorpses extends CardImpl { + + private static final FilterCreatureCard filter = new FilterCreatureCard("target creature card with lesser power from your graveyard"); + + static { + filter.add(new GyrusWakerOfCorpsesPowerLessThanSourcePredicate()); + } + + public GyrusWakerOfCorpses(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{B}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HYDRA); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Gyrus, Walker of Corpses enters the battlefield with a number of +1/+1 counters on it equal to the amount of mana spent to cast it. + Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), new ManaSpentToCastCount(), true); + effect.setText("with a number of +1/+1 counters on it equal to the amount of mana spent to cast it"); + this.addAbility(new EntersBattlefieldAbility(effect)); + + // Whenever Gyrus attacks, you may exile target creature card with lesser power from your graveyard. If you do, create a token that’s a copy of that card and that’s tapped and attacking. Exile the token at the end of combat. + Ability ability = new AttacksTriggeredAbility(new GyrusWakerOfCorpsesEffect(), true); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + } + + public GyrusWakerOfCorpses(final GyrusWakerOfCorpses card) { + super(card); + } + + @Override + public GyrusWakerOfCorpses copy() { + return new GyrusWakerOfCorpses(this); + } +} + +class GyrusWakerOfCorpsesEffect extends OneShotEffect { + + public GyrusWakerOfCorpsesEffect() { + super(Outcome.Copy); + this.staticText = "exile target creature card with lesser power from your graveyard. If you do, create a token that’s a copy of that card and that’s tapped and attacking. Exile the token at the end of combat."; + } + + public GyrusWakerOfCorpsesEffect(final GyrusWakerOfCorpsesEffect effect) { + super(effect); + } + + @Override + public GyrusWakerOfCorpsesEffect copy() { + return new GyrusWakerOfCorpsesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + + Card card = game.getCard(source.getFirstTarget()); + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null || card == null) { + return false; + } + controller.moveCards(card, Zone.EXILED, source, game); + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(source.getControllerId(), null, true, 1, true, true); + effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game))); + effect.apply(game, source); + for (Permanent addedToken : effect.getAddedPermanent()) { + Effect exileEffect = new ExileTargetEffect(); + exileEffect.setTargetPointer(new FixedTarget(addedToken, game)); + new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), false).apply(game, source); + } + return true; + } +} + +class GyrusWakerOfCorpsesPowerLessThanSourcePredicate implements ObjectSourcePlayerPredicate> { + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(input.getSourceId()); + return sourcePermanent != null && input.getObject().getPower().getValue() < sourcePermanent.getPower().getValue(); + } + + @Override + public String toString() { + return "lesser power"; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index c3aa0955e28..65db6e261d5 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -133,6 +133,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Grisly Salvage", 182, Rarity.COMMON, mage.cards.g.GrislySalvage.class)); cards.add(new SetCardInfo("Ground Seal", 149, Rarity.RARE, mage.cards.g.GroundSeal.class)); cards.add(new SetCardInfo("Gruul Turf", 252, Rarity.UNCOMMON, mage.cards.g.GruulTurf.class)); + cards.add(new SetCardInfo("Gyrus, Waker of Corpses", 41, Rarity.MYTHIC, mage.cards.g.GyrusWakerOfCorpses.class)); cards.add(new SetCardInfo("Halimar Depths", 253, Rarity.COMMON, mage.cards.h.HalimarDepths.class)); cards.add(new SetCardInfo("Harrow", 150, Rarity.COMMON, mage.cards.h.Harrow.class)); cards.add(new SetCardInfo("Haunted Fengraf", 254, Rarity.COMMON, mage.cards.h.HauntedFengraf.class)); diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaSpentToCastCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaSpentToCastCount.java index d2e841f7206..767c185e7a6 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaSpentToCastCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaSpentToCastCount.java @@ -29,7 +29,7 @@ public class ManaSpentToCastCount implements DynamicValue { } if (spell != null) { // NOT the cmc of the spell on the stack - return spell.getSpellAbility().getManaCostsToPay().convertedManaCost() + spell.getSpellAbility().getManaCostsToPay().getX(); + return spell.getSpellAbility().getManaCostsToPay().convertedManaCost(); } return 0; } From ded41fd1e09986d854f45e864a1f2a066260a4c1 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sat, 28 Jul 2018 11:00:53 -0400 Subject: [PATCH 55/71] fixed Frenetic Efreet not flipping coins if not on the battlefield (fixes #5176) --- .../src/mage/cards/f/FreneticEfreet.java | 36 +++++++++++-------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/Mage.Sets/src/mage/cards/f/FreneticEfreet.java b/Mage.Sets/src/mage/cards/f/FreneticEfreet.java index 836e1fd82e7..b2f407420be 100644 --- a/Mage.Sets/src/mage/cards/f/FreneticEfreet.java +++ b/Mage.Sets/src/mage/cards/f/FreneticEfreet.java @@ -1,4 +1,3 @@ - package mage.cards.f; import java.util.UUID; @@ -25,16 +24,20 @@ import mage.players.Player; public final class FreneticEfreet extends CardImpl { public FreneticEfreet(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}"); this.subtype.add(SubType.EFREET); this.power = new MageInt(2); this.toughness = new MageInt(1); // Flying this.addAbility(FlyingAbility.getInstance()); - + // {0}: Flip a coin. If you win the flip, Frenetic Efreet phases out. If you lose the flip, sacrifice Frenetic Efreet. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new FreneticEfreetEffect(), new GenericManaCost(0))); + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new FreneticEfreetEffect(), + new GenericManaCost(0) + )); } public FreneticEfreet(final FreneticEfreet card) { @@ -50,8 +53,9 @@ public final class FreneticEfreet extends CardImpl { class FreneticEfreetEffect extends OneShotEffect { public FreneticEfreetEffect() { - super(Outcome.Damage); - staticText = "Flip a coin. If you win the flip, {this} phases out. If you lose the flip, sacrifice {this}"; + super(Outcome.Neutral); + staticText = "Flip a coin. If you win the flip, " + + "{this} phases out. If you lose the flip, sacrifice {this}"; } public FreneticEfreetEffect(FreneticEfreetEffect effect) { @@ -62,15 +66,19 @@ class FreneticEfreetEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && permanent != null) { - if (controller.flipCoin(game)) { - return permanent.phaseOut(game); - } else { - permanent.sacrifice(source.getSourceId(), game); - return true; - } + if (controller == null) { + return false; + } + boolean flip = controller.flipCoin(game); + if (permanent == null) { + return false; + } + if (flip) { + return permanent.phaseOut(game); + } else { + permanent.sacrifice(source.getSourceId(), game); + return true; } - return false; } @Override From b757f15313824baf44b0cd168b7e24e19e2c7f88 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sat, 28 Jul 2018 14:47:34 -0400 Subject: [PATCH 56/71] Implemented Vedalken Humiliator --- .../src/mage/cards/v/VedalkenHumiliator.java | 61 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 62 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/v/VedalkenHumiliator.java diff --git a/Mage.Sets/src/mage/cards/v/VedalkenHumiliator.java b/Mage.Sets/src/mage/cards/v/VedalkenHumiliator.java new file mode 100644 index 00000000000..9997b830b2d --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VedalkenHumiliator.java @@ -0,0 +1,61 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.common.MetalcraftCondition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.continuous.LoseAllAbilitiesAllEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessAllEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; + +/** + * + * @author TheElk801 + */ +public final class VedalkenHumiliator extends CardImpl { + + public VedalkenHumiliator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.VEDALKEN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Metalcraft — Whenever Vedalken Humiliator attacks, if you control three or more artifacts, creatures your opponents control lose all abilities and have base power and toughness 1/1 until end of turn. + TriggeredAbility ability = new AttacksTriggeredAbility( + new SetPowerToughnessAllEffect( + 1, 1, Duration.EndOfTurn, + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, + true + ), false + ); + ability.addEffect(new LoseAllAbilitiesAllEffect( + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE, + Duration.EndOfTurn + )); + this.addAbility(new ConditionalTriggeredAbility( + ability, MetalcraftCondition.instance, + "Metalcraft — Whenever {this} attacks, " + + "if you control three or more artifacts, " + + "creatures your opponents control lose all abilities " + + "and have base power and toughness 1/1 until end of turn." + )); + } + + public VedalkenHumiliator(final VedalkenHumiliator card) { + super(card); + } + + @Override + public VedalkenHumiliator copy() { + return new VedalkenHumiliator(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 65db6e261d5..10754bafc2f 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -295,6 +295,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Utter End", 193, Rarity.RARE, mage.cards.u.UtterEnd.class)); cards.add(new SetCardInfo("Varchild, Betrayer of Kjeldor", 28, Rarity.RARE, mage.cards.v.VarchildBetrayerOfKjeldor.class)); cards.add(new SetCardInfo("Varina, Lich Queen", 48, Rarity.MYTHIC, mage.cards.v.VarinaLichQueen.class)); + cards.add(new SetCardInfo("Vedalken Humiliator", 13, Rarity.RARE, mage.cards.v.VedalkenHumiliator.class)); cards.add(new SetCardInfo("Vessel of Endless Rest", 229, Rarity.UNCOMMON, mage.cards.v.VesselOfEndlessRest.class)); cards.add(new SetCardInfo("Vow of Flight", 110, Rarity.UNCOMMON, mage.cards.v.VowOfFlight.class)); cards.add(new SetCardInfo("Vow of Wildness", 164, Rarity.UNCOMMON, mage.cards.v.VowOfWildness.class)); From c2c7aff4f7e957706e85f2235548ff1cdf845e64 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sat, 28 Jul 2018 15:01:20 -0400 Subject: [PATCH 57/71] fixed the formatting on some ability words --- Mage.Sets/src/mage/cards/a/ArgentSphinx.java | 2 +- Mage.Sets/src/mage/cards/a/AuriokEdgewright.java | 2 +- Mage.Sets/src/mage/cards/a/AuriokSunchaser.java | 4 ++-- Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java | 4 ++-- Mage.Sets/src/mage/cards/b/BleakCovenVampires.java | 4 ++-- Mage.Sets/src/mage/cards/b/BrimstoneVolley.java | 4 ++-- Mage.Sets/src/mage/cards/c/CarapaceForger.java | 2 +- Mage.Sets/src/mage/cards/c/CaravanVigil.java | 2 +- Mage.Sets/src/mage/cards/c/ChromeSteed.java | 2 +- Mage.Sets/src/mage/cards/c/ConcussiveBolt.java | 4 ++-- Mage.Sets/src/mage/cards/d/DeathreapRitual.java | 2 +- Mage.Sets/src/mage/cards/d/Dispatch.java | 2 +- Mage.Sets/src/mage/cards/d/DispenseJustice.java | 2 +- Mage.Sets/src/mage/cards/e/EzurisBrigade.java | 2 +- Mage.Sets/src/mage/cards/f/FesterhideBoar.java | 2 +- Mage.Sets/src/mage/cards/g/GalvanicBlast.java | 4 ++-- Mage.Sets/src/mage/cards/g/GhalmasWarden.java | 2 +- Mage.Sets/src/mage/cards/g/GravetillerWurm.java | 2 +- Mage.Sets/src/mage/cards/g/GruesomeDiscovery.java | 4 ++-- Mage.Sets/src/mage/cards/h/HollowhengeScavenger.java | 4 ++-- Mage.Sets/src/mage/cards/h/HungerOfTheHowlpack.java | 4 ++-- Mage.Sets/src/mage/cards/i/IndomitableArchangel.java | 2 +- Mage.Sets/src/mage/cards/j/JorKadeenThePrevailer.java | 4 ++-- Mage.Sets/src/mage/cards/k/KuldothaPhoenix.java | 2 +- Mage.Sets/src/mage/cards/l/LumengridDrake.java | 2 +- Mage.Sets/src/mage/cards/m/MaliciousAffliction.java | 2 +- Mage.Sets/src/mage/cards/m/MirranMettle.java | 2 +- Mage.Sets/src/mage/cards/m/MoltenPsyche.java | 2 +- Mage.Sets/src/mage/cards/m/MorkrutBanshee.java | 4 ++-- Mage.Sets/src/mage/cards/p/PredatorsHowl.java | 2 +- Mage.Sets/src/mage/cards/p/PuresteelPaladin.java | 4 ++-- Mage.Sets/src/mage/cards/r/RazorfieldRhino.java | 2 +- Mage.Sets/src/mage/cards/r/ReaperFromTheAbyss.java | 2 +- Mage.Sets/src/mage/cards/r/RustedRelic.java | 2 +- Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java | 4 ++-- Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java | 2 +- Mage.Sets/src/mage/cards/s/SnapsailGlider.java | 2 +- Mage.Sets/src/mage/cards/s/SomberwaldSpider.java | 2 +- Mage.Sets/src/mage/cards/s/SpiralingDuelist.java | 2 +- Mage.Sets/src/mage/cards/s/SpireSerpent.java | 2 +- Mage.Sets/src/mage/cards/s/StoicRebuttal.java | 2 +- Mage.Sets/src/mage/cards/t/TragicSlip.java | 4 ++-- Mage.Sets/src/mage/cards/u/UlvenwaldBear.java | 2 +- Mage.Sets/src/mage/cards/v/VedalkenCertarch.java | 2 +- Mage.Sets/src/mage/cards/w/Wakedancer.java | 4 ++-- Mage.Sets/src/mage/cards/w/WoodlandSleuth.java | 4 ++-- .../mage/test/cards/abilities/keywords/MetalcraftTest.java | 2 +- .../src/test/java/org/mage/test/cards/rules/CantCastTest.java | 2 +- 48 files changed, 64 insertions(+), 64 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/ArgentSphinx.java b/Mage.Sets/src/mage/cards/a/ArgentSphinx.java index e3c98324de0..7f76777b23d 100644 --- a/Mage.Sets/src/mage/cards/a/ArgentSphinx.java +++ b/Mage.Sets/src/mage/cards/a/ArgentSphinx.java @@ -36,7 +36,7 @@ public final class ArgentSphinx extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - // Metalcraft - {U}: Exile Argent Sphinx. Return it to the battlefield under your control at the beginning of the next end step. Activate this ability only if you control three or more artifacts. + // Metalcraft — {U}: Exile Argent Sphinx. Return it to the battlefield under your control at the beginning of the next end step. Activate this ability only if you control three or more artifacts. Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new ArgentSphinxEffect(), new ManaCostsImpl("{U}"), MetalcraftCondition.instance); ability.setAbilityWord(AbilityWord.METALCRAFT); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AuriokEdgewright.java b/Mage.Sets/src/mage/cards/a/AuriokEdgewright.java index f4d24b54469..a38161a38a5 100644 --- a/Mage.Sets/src/mage/cards/a/AuriokEdgewright.java +++ b/Mage.Sets/src/mage/cards/a/AuriokEdgewright.java @@ -22,7 +22,7 @@ import mage.constants.Zone; */ public final class AuriokEdgewright extends CardImpl { - protected static String effectText = "Metalcraft - Auriok Edgewright has double strike as long as you control three or more artifacts."; + protected static String effectText = "Metalcraft — Auriok Edgewright has double strike as long as you control three or more artifacts."; public AuriokEdgewright(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{W}"); diff --git a/Mage.Sets/src/mage/cards/a/AuriokSunchaser.java b/Mage.Sets/src/mage/cards/a/AuriokSunchaser.java index 6d071200ba8..249c912b492 100644 --- a/Mage.Sets/src/mage/cards/a/AuriokSunchaser.java +++ b/Mage.Sets/src/mage/cards/a/AuriokSunchaser.java @@ -23,8 +23,8 @@ import mage.constants.Zone; */ public final class AuriokSunchaser extends CardImpl { - protected static String effect1Text = "Metalcraft - As long as you control three or more artifacts, Auriok Sunchaser gets +2/+2"; - protected static String effect2Text = "Metalcraft - As long as you control three or more artifacts, Auriok Sunchaser has flying"; + protected static String effect1Text = "Metalcraft — As long as you control three or more artifacts, Auriok Sunchaser gets +2/+2"; + protected static String effect2Text = "Metalcraft — As long as you control three or more artifacts, Auriok Sunchaser has flying"; public AuriokSunchaser(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); diff --git a/Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java b/Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java index fef59f0aaab..53de13427a4 100644 --- a/Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java +++ b/Mage.Sets/src/mage/cards/b/BladeTribeBerserkers.java @@ -22,7 +22,7 @@ import mage.constants.SubType; */ public final class BladeTribeBerserkers extends CardImpl { - private static final String effectText = "Metalcraft - When Blade-Tribe Berserkers enters the battlefield, if you control three or more artifacts, Blade-Tribe Berserkers gets +3/+3 and gains haste until end of turn."; + private static final String effectText = "Metalcraft — When Blade-Tribe Berserkers enters the battlefield, if you control three or more artifacts, Blade-Tribe Berserkers gets +3/+3 and gains haste until end of turn."; public BladeTribeBerserkers(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); @@ -31,7 +31,7 @@ public final class BladeTribeBerserkers extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); - //Metalcraft - When Blade-Tribe Berserkers enters the battlefield, if you control three or more artifacts, Blade-Tribe Berserkers gets +3/+3 and gains haste until end of turn. + //Metalcraft — When Blade-Tribe Berserkers enters the battlefield, if you control three or more artifacts, Blade-Tribe Berserkers gets +3/+3 and gains haste until end of turn. TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new BoostSourceEffect(3, 3, Duration.EndOfTurn), false); ability.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MetalcraftCondition.instance, effectText)); diff --git a/Mage.Sets/src/mage/cards/b/BleakCovenVampires.java b/Mage.Sets/src/mage/cards/b/BleakCovenVampires.java index 605e3cf3b23..61ec1d16679 100644 --- a/Mage.Sets/src/mage/cards/b/BleakCovenVampires.java +++ b/Mage.Sets/src/mage/cards/b/BleakCovenVampires.java @@ -22,7 +22,7 @@ import mage.target.TargetPlayer; */ public final class BleakCovenVampires extends CardImpl { - private static final String effectText = "Metalcraft - When Bleak Coven Vampires enters the battlefield, if you control three or more artifacts, target player loses 4 life and you gain 4 life."; + private static final String effectText = "Metalcraft — When Bleak Coven Vampires enters the battlefield, if you control three or more artifacts, target player loses 4 life and you gain 4 life."; public BleakCovenVampires(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); @@ -31,7 +31,7 @@ public final class BleakCovenVampires extends CardImpl { this.power = new MageInt(4); this.toughness = new MageInt(3); - //Metalcraft - When Bleak Coven Vampires enters the battlefield, if you control three or more artifacts, target player loses 4 life and you gain 4 life. + //Metalcraft — When Bleak Coven Vampires enters the battlefield, if you control three or more artifacts, target player loses 4 life and you gain 4 life. TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new LoseLifeTargetEffect(4), false); ability.addEffect(new GainLifeEffect(4)); Target target = new TargetPlayer(); diff --git a/Mage.Sets/src/mage/cards/b/BrimstoneVolley.java b/Mage.Sets/src/mage/cards/b/BrimstoneVolley.java index b0d2761eac0..dd37a947c6d 100644 --- a/Mage.Sets/src/mage/cards/b/BrimstoneVolley.java +++ b/Mage.Sets/src/mage/cards/b/BrimstoneVolley.java @@ -24,7 +24,7 @@ public final class BrimstoneVolley extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // Brimstone Volley deals 3 damage to any target. - // Morbid - Brimstone Volley deals 5 damage to that creature or player instead if a creature died this turn. + // Morbid — Brimstone Volley deals 5 damage to that creature or player instead if a creature died this turn. this.getSpellAbility().addEffect(new BrimstoneVolleyEffect()); this.getSpellAbility().addTarget(new TargetAnyTarget()); } @@ -43,7 +43,7 @@ class BrimstoneVolleyEffect extends OneShotEffect { public BrimstoneVolleyEffect() { super(Outcome.Damage); - staticText = "{this} deals 3 damage to any target.\n Morbid - {this} deals 5 damage to that permanent or player instead if a creature died this turn"; + staticText = "{this} deals 3 damage to any target.\n Morbid — {this} deals 5 damage to that permanent or player instead if a creature died this turn"; } public BrimstoneVolleyEffect(final BrimstoneVolleyEffect effect) { diff --git a/Mage.Sets/src/mage/cards/c/CarapaceForger.java b/Mage.Sets/src/mage/cards/c/CarapaceForger.java index 7e8b3f6367f..03ce8bd225e 100644 --- a/Mage.Sets/src/mage/cards/c/CarapaceForger.java +++ b/Mage.Sets/src/mage/cards/c/CarapaceForger.java @@ -21,7 +21,7 @@ import mage.constants.Zone; * @author Loki */ public final class CarapaceForger extends CardImpl { - private static final String text = "Metalcraft - Carapace Forger gets +2/+2 as long as you control three or more artifacts"; + private static final String text = "Metalcraft — Carapace Forger gets +2/+2 as long as you control three or more artifacts"; public CarapaceForger (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); diff --git a/Mage.Sets/src/mage/cards/c/CaravanVigil.java b/Mage.Sets/src/mage/cards/c/CaravanVigil.java index 543efe0bfce..963e149db37 100644 --- a/Mage.Sets/src/mage/cards/c/CaravanVigil.java +++ b/Mage.Sets/src/mage/cards/c/CaravanVigil.java @@ -26,7 +26,7 @@ public final class CaravanVigil extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{G}"); // Search your library for a basic land card, reveal it, put it into your hand, then shuffle your library. - // Morbid - You may put that card onto the battlefield instead of putting it into your hand if a creature died this turn. + // Morbid — You may put that card onto the battlefield instead of putting it into your hand if a creature died this turn. this.getSpellAbility().addEffect(new CaravanVigilEffect()); } diff --git a/Mage.Sets/src/mage/cards/c/ChromeSteed.java b/Mage.Sets/src/mage/cards/c/ChromeSteed.java index d9053812486..b0e34f7e10f 100644 --- a/Mage.Sets/src/mage/cards/c/ChromeSteed.java +++ b/Mage.Sets/src/mage/cards/c/ChromeSteed.java @@ -21,7 +21,7 @@ import mage.constants.Zone; * @author Loki */ public final class ChromeSteed extends CardImpl { - private static final String text = "Metalcraft - Chrome Steed gets +2/+2 as long as you control three or more artifacts"; + private static final String text = "Metalcraft — Chrome Steed gets +2/+2 as long as you control three or more artifacts"; public ChromeSteed (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); diff --git a/Mage.Sets/src/mage/cards/c/ConcussiveBolt.java b/Mage.Sets/src/mage/cards/c/ConcussiveBolt.java index b8f39e589a3..50103876f9a 100644 --- a/Mage.Sets/src/mage/cards/c/ConcussiveBolt.java +++ b/Mage.Sets/src/mage/cards/c/ConcussiveBolt.java @@ -29,7 +29,7 @@ public final class ConcussiveBolt extends CardImpl { // Concussive Bolt deals 4 damage to target player. this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); this.getSpellAbility().addEffect(new DamageTargetEffect(4)); - // Metalcraft - If you control three or more artifacts, creatures that player controls can't block this turn. + // Metalcraft — If you control three or more artifacts, creatures that player controls can't block this turn. this.getSpellAbility().addEffect(new ConcussiveBoltEffect()); this.getSpellAbility().addEffect(new ConcussiveBoltRestrictionEffect()); } @@ -48,7 +48,7 @@ class ConcussiveBoltEffect extends OneShotEffect { public ConcussiveBoltEffect() { super(Outcome.Benefit); - this.staticText = "Metalcraft - If you control three or more artifacts, creatures controlled by that player or by that planeswalker's controller can't block this turn."; + this.staticText = "Metalcraft — If you control three or more artifacts, creatures controlled by that player or by that planeswalker's controller can't block this turn."; } public ConcussiveBoltEffect(final ConcussiveBoltEffect effect) { diff --git a/Mage.Sets/src/mage/cards/d/DeathreapRitual.java b/Mage.Sets/src/mage/cards/d/DeathreapRitual.java index 5761d43d37b..afe72c7fbdd 100644 --- a/Mage.Sets/src/mage/cards/d/DeathreapRitual.java +++ b/Mage.Sets/src/mage/cards/d/DeathreapRitual.java @@ -20,7 +20,7 @@ public final class DeathreapRitual extends CardImpl { public DeathreapRitual(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{G}"); - // Morbid - At the beginning of each end step, if a creature died this turn, you may draw a card. + // Morbid — At the beginning of each end step, if a creature died this turn, you may draw a card. this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), TargetController.ANY, MorbidCondition.instance, true)); } diff --git a/Mage.Sets/src/mage/cards/d/Dispatch.java b/Mage.Sets/src/mage/cards/d/Dispatch.java index fe769a5fe18..6fd5815ce9e 100644 --- a/Mage.Sets/src/mage/cards/d/Dispatch.java +++ b/Mage.Sets/src/mage/cards/d/Dispatch.java @@ -22,7 +22,7 @@ public final class Dispatch extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}"); this.getSpellAbility().addEffect(new TapTargetEffect()); - this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new ExileTargetEffect(), MetalcraftCondition.instance, "Metalcraft - If you control three or more artifacts, exile that creature")); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new ExileTargetEffect(), MetalcraftCondition.instance, "Metalcraft — If you control three or more artifacts, exile that creature")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/d/DispenseJustice.java b/Mage.Sets/src/mage/cards/d/DispenseJustice.java index 16ea025c058..98da9261938 100644 --- a/Mage.Sets/src/mage/cards/d/DispenseJustice.java +++ b/Mage.Sets/src/mage/cards/d/DispenseJustice.java @@ -43,7 +43,7 @@ public final class DispenseJustice extends CardImpl { class DispenseJusticeEffect extends OneShotEffect { private static final String effectText = "Target player sacrifices an attacking creature.\r\n\r\n" - + "Metalcraft - That player sacrifices two attacking creatures instead if you control three or more artifacts"; + + "Metalcraft — That player sacrifices two attacking creatures instead if you control three or more artifacts"; private static final FilterAttackingCreature filter = new FilterAttackingCreature(); diff --git a/Mage.Sets/src/mage/cards/e/EzurisBrigade.java b/Mage.Sets/src/mage/cards/e/EzurisBrigade.java index 1235e8f298a..1602de0fe62 100644 --- a/Mage.Sets/src/mage/cards/e/EzurisBrigade.java +++ b/Mage.Sets/src/mage/cards/e/EzurisBrigade.java @@ -24,7 +24,7 @@ import mage.constants.Zone; * @author Loki */ public final class EzurisBrigade extends CardImpl { - private static final String text = "Metalcraft - As long as you control three or more artifacts, Ezuri's Brigade gets +4/+4 and has trample"; + private static final String text = "Metalcraft — As long as you control three or more artifacts, Ezuri's Brigade gets +4/+4 and has trample"; public EzurisBrigade (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{G}"); diff --git a/Mage.Sets/src/mage/cards/f/FesterhideBoar.java b/Mage.Sets/src/mage/cards/f/FesterhideBoar.java index fb053b0f709..9e80b1494ad 100644 --- a/Mage.Sets/src/mage/cards/f/FesterhideBoar.java +++ b/Mage.Sets/src/mage/cards/f/FesterhideBoar.java @@ -28,7 +28,7 @@ public final class FesterhideBoar extends CardImpl { this.toughness = new MageInt(3); this.addAbility(TrampleAbility.getInstance()); - // Morbid - Festerhide Boar enters the battlefield with two +1/+1 counters on it if a creature died this turn. + // Morbid — Festerhide Boar enters the battlefield with two +1/+1 counters on it if a creature died this turn. this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), MorbidCondition.instance, ""), "with two +1/+1 counters on it if a creature died this turn")); } diff --git a/Mage.Sets/src/mage/cards/g/GalvanicBlast.java b/Mage.Sets/src/mage/cards/g/GalvanicBlast.java index 6f18df57d98..6c696f13df9 100644 --- a/Mage.Sets/src/mage/cards/g/GalvanicBlast.java +++ b/Mage.Sets/src/mage/cards/g/GalvanicBlast.java @@ -16,14 +16,14 @@ import mage.target.common.TargetAnyTarget; */ public final class GalvanicBlast extends CardImpl { - private static final String effectText = "{this} deals 2 damage to anytarget.
Metalcraft - {this} deals 4 damage to that permanent or player instead if you control three or more artifacts"; + private static final String effectText = "{this} deals 2 damage to anytarget.
Metalcraft — {this} deals 4 damage to that permanent or player instead if you control three or more artifacts"; public GalvanicBlast(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); this.color.setRed(true); // Galvanic Blast deals 2 damage to any target. - // Metalcraft - Galvanic Blast deals 4 damage to that creature or player instead if you control three or more artifacts. + // Metalcraft — Galvanic Blast deals 4 damage to that creature or player instead if you control three or more artifacts. this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DamageTargetEffect(4), new DamageTargetEffect(2), MetalcraftCondition.instance, effectText)); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/g/GhalmasWarden.java b/Mage.Sets/src/mage/cards/g/GhalmasWarden.java index d6db8e9c294..22f8bb494b8 100644 --- a/Mage.Sets/src/mage/cards/g/GhalmasWarden.java +++ b/Mage.Sets/src/mage/cards/g/GhalmasWarden.java @@ -22,7 +22,7 @@ import mage.constants.Zone; */ public final class GhalmasWarden extends CardImpl { - private static final String text = "Metalcraft - Ghalma's Warden gets +2/+2 as long as you control three or more artifacts"; + private static final String text = "Metalcraft — Ghalma's Warden gets +2/+2 as long as you control three or more artifacts"; public GhalmasWarden (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); diff --git a/Mage.Sets/src/mage/cards/g/GravetillerWurm.java b/Mage.Sets/src/mage/cards/g/GravetillerWurm.java index f4af78c066e..dcd6c349670 100644 --- a/Mage.Sets/src/mage/cards/g/GravetillerWurm.java +++ b/Mage.Sets/src/mage/cards/g/GravetillerWurm.java @@ -28,7 +28,7 @@ public final class GravetillerWurm extends CardImpl { this.toughness = new MageInt(4); this.addAbility(TrampleAbility.getInstance()); - // Morbid - Gravetiller Wurm enters the battlefield with four +1/+1 counters on it if a creature died this turn. + // Morbid — Gravetiller Wurm enters the battlefield with four +1/+1 counters on it if a creature died this turn. this.addAbility(new EntersBattlefieldAbility(new ConditionalOneShotEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(4)), MorbidCondition.instance, ""), "with four +1/+1 counters on it if a creature died this turn")); } diff --git a/Mage.Sets/src/mage/cards/g/GruesomeDiscovery.java b/Mage.Sets/src/mage/cards/g/GruesomeDiscovery.java index 9c9789fd37d..f3221cdf1aa 100644 --- a/Mage.Sets/src/mage/cards/g/GruesomeDiscovery.java +++ b/Mage.Sets/src/mage/cards/g/GruesomeDiscovery.java @@ -31,12 +31,12 @@ public final class GruesomeDiscovery extends CardImpl { // Target player discards two cards. - // Morbid - If a creature died this turn, instead that player reveals their hand, you choose two cards from it, then that player discards those cards. + // Morbid — If a creature died this turn, instead that player reveals their hand, you choose two cards from it, then that player discards those cards. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new GruesomeDiscoveryEffect(), new DiscardTargetEffect(2), MorbidCondition.instance, - "Target player discards two cards. Morbid - If a creature died this turn, instead that player reveals their hand, you choose two cards from it, then that player discards those cards")); + "Target player discards two cards. Morbid — If a creature died this turn, instead that player reveals their hand, you choose two cards from it, then that player discards those cards")); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/h/HollowhengeScavenger.java b/Mage.Sets/src/mage/cards/h/HollowhengeScavenger.java index 339ef6426ad..0da64ee8dbd 100644 --- a/Mage.Sets/src/mage/cards/h/HollowhengeScavenger.java +++ b/Mage.Sets/src/mage/cards/h/HollowhengeScavenger.java @@ -19,7 +19,7 @@ import mage.constants.SubType; */ public final class HollowhengeScavenger extends CardImpl { - private static final String staticText = "Morbid - When {this} enters the battlefield, if a creature died this turn, you gain 5 life."; + private static final String staticText = "Morbid — When {this} enters the battlefield, if a creature died this turn, you gain 5 life."; public HollowhengeScavenger(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}{G}"); @@ -28,7 +28,7 @@ public final class HollowhengeScavenger extends CardImpl { this.power = new MageInt(4); this.toughness = new MageInt(5); - // Morbid - When Hollowhenge Scavenger enters the battlefield, if a creature died this turn, you gain 5 life. + // Morbid — When Hollowhenge Scavenger enters the battlefield, if a creature died this turn, you gain 5 life. TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(5)); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MorbidCondition.instance, staticText)); } diff --git a/Mage.Sets/src/mage/cards/h/HungerOfTheHowlpack.java b/Mage.Sets/src/mage/cards/h/HungerOfTheHowlpack.java index 5995ac16c07..c29819bd733 100644 --- a/Mage.Sets/src/mage/cards/h/HungerOfTheHowlpack.java +++ b/Mage.Sets/src/mage/cards/h/HungerOfTheHowlpack.java @@ -22,13 +22,13 @@ public final class HungerOfTheHowlpack extends CardImpl { // Put a +1/+1 counter on target creature. - // Morbid - Put three +1/+1 counters on that creature instead if a creature died this turn. + // Morbid — Put three +1/+1 counters on that creature instead if a creature died this turn. this.getSpellAbility().addEffect( new ConditionalOneShotEffect( new AddCountersTargetEffect(CounterType.P1P1.createInstance(3)), new AddCountersTargetEffect(CounterType.P1P1.createInstance()), MorbidCondition.instance, - "Put a +1/+1 counter on target creature. Morbid - Put three +1/+1 counters on that creature instead if a creature died this turn")); + "Put a +1/+1 counter on target creature. Morbid — Put three +1/+1 counters on that creature instead if a creature died this turn")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/i/IndomitableArchangel.java b/Mage.Sets/src/mage/cards/i/IndomitableArchangel.java index edc9cec8cb2..2a1e889e73d 100644 --- a/Mage.Sets/src/mage/cards/i/IndomitableArchangel.java +++ b/Mage.Sets/src/mage/cards/i/IndomitableArchangel.java @@ -25,7 +25,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate; */ public final class IndomitableArchangel extends CardImpl { - private static final String rule = "Metalcraft - Artifacts you control have shroud as long as you control three or more artifacts."; + private static final String rule = "Metalcraft — Artifacts you control have shroud as long as you control three or more artifacts."; private static final FilterPermanent filter = new FilterPermanent("Artifacts"); diff --git a/Mage.Sets/src/mage/cards/j/JorKadeenThePrevailer.java b/Mage.Sets/src/mage/cards/j/JorKadeenThePrevailer.java index 19cde3a53bf..0a9910044d7 100644 --- a/Mage.Sets/src/mage/cards/j/JorKadeenThePrevailer.java +++ b/Mage.Sets/src/mage/cards/j/JorKadeenThePrevailer.java @@ -23,7 +23,7 @@ import mage.filter.StaticFilters; */ public final class JorKadeenThePrevailer extends CardImpl { - private static final String effectText = "Metalcraft - Creatures you control get +3/+0 as long as you control three or more artifacts."; + private static final String effectText = "Metalcraft — Creatures you control get +3/+0 as long as you control three or more artifacts."; public JorKadeenThePrevailer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{W}"); @@ -37,7 +37,7 @@ public final class JorKadeenThePrevailer extends CardImpl { // First strike this.addAbility(FirstStrikeAbility.getInstance()); - // Metalcraft - Creatures you control get +3/+0 as long as you control three or more artifacts. + // Metalcraft — Creatures you control get +3/+0 as long as you control three or more artifacts. ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new BoostControlledEffect(3, 0, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE, false), MetalcraftCondition.instance, effectText); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); diff --git a/Mage.Sets/src/mage/cards/k/KuldothaPhoenix.java b/Mage.Sets/src/mage/cards/k/KuldothaPhoenix.java index 278caca7917..37a4218383e 100644 --- a/Mage.Sets/src/mage/cards/k/KuldothaPhoenix.java +++ b/Mage.Sets/src/mage/cards/k/KuldothaPhoenix.java @@ -37,7 +37,7 @@ public final class KuldothaPhoenix extends CardImpl { this.addAbility(FlyingAbility.getInstance()); this.addAbility(HasteAbility.getInstance()); - // Metalcraft - {4}: Return Kuldotha Phoenix from your graveyard to the battlefield. + // Metalcraft — {4}: Return Kuldotha Phoenix from your graveyard to the battlefield. // Activate this ability only during your upkeep and only if you control three or more artifacts. Ability ability = new ConditionalActivatedAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(), diff --git a/Mage.Sets/src/mage/cards/l/LumengridDrake.java b/Mage.Sets/src/mage/cards/l/LumengridDrake.java index 6cf66783fb1..884ac2cced3 100644 --- a/Mage.Sets/src/mage/cards/l/LumengridDrake.java +++ b/Mage.Sets/src/mage/cards/l/LumengridDrake.java @@ -20,7 +20,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class LumengridDrake extends CardImpl { - private static final String ruleText = "Metalcraft - When {this} enters the battlefield, if you control three or more artifacts, return target creature to its owner's hand."; + private static final String ruleText = "Metalcraft — When {this} enters the battlefield, if you control three or more artifacts, return target creature to its owner's hand."; public LumengridDrake(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); diff --git a/Mage.Sets/src/mage/cards/m/MaliciousAffliction.java b/Mage.Sets/src/mage/cards/m/MaliciousAffliction.java index 7df96dfdce9..56840b6b5b3 100644 --- a/Mage.Sets/src/mage/cards/m/MaliciousAffliction.java +++ b/Mage.Sets/src/mage/cards/m/MaliciousAffliction.java @@ -38,7 +38,7 @@ public final class MaliciousAffliction extends CardImpl { public MaliciousAffliction(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}{B}"); - // Morbid - When you cast Malicious Affliction, if a creature died this turn, you may copy Malicious Affliction and may choose a new target for the copy. + // Morbid — When you cast Malicious Affliction, if a creature died this turn, you may copy Malicious Affliction and may choose a new target for the copy. Ability ability = new ConditionalInterveningIfTriggeredAbility( new CastSourceTriggeredAbility(new CopySourceSpellEffect(), true), new LockedInCondition(MorbidCondition.instance), diff --git a/Mage.Sets/src/mage/cards/m/MirranMettle.java b/Mage.Sets/src/mage/cards/m/MirranMettle.java index d8f0751f0c7..50b66bd8e03 100644 --- a/Mage.Sets/src/mage/cards/m/MirranMettle.java +++ b/Mage.Sets/src/mage/cards/m/MirranMettle.java @@ -18,7 +18,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class MirranMettle extends CardImpl { - private static final String effectText = "Metalcraft - That creature gets +4/+4 until end of turn instead if you control three or more artifacts."; + private static final String effectText = "Metalcraft — That creature gets +4/+4 until end of turn instead if you control three or more artifacts."; public MirranMettle(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{G}"); diff --git a/Mage.Sets/src/mage/cards/m/MoltenPsyche.java b/Mage.Sets/src/mage/cards/m/MoltenPsyche.java index 0757e2fbd19..bd9f8b6e8de 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenPsyche.java +++ b/Mage.Sets/src/mage/cards/m/MoltenPsyche.java @@ -29,7 +29,7 @@ public final class MoltenPsyche extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}{R}"); // Each player shuffles the cards from their hand into their library, then draws that many cards. - // Metalcraft - If you control three or more artifacts, Molten Psyche deals damage to each opponent equal to the number of cards that player has drawn this turn. + // Metalcraft — If you control three or more artifacts, Molten Psyche deals damage to each opponent equal to the number of cards that player has drawn this turn. this.getSpellAbility().addEffect(new MoltenPsycheEffect()); this.getSpellAbility().addWatcher(new MoltenPsycheWatcher()); } diff --git a/Mage.Sets/src/mage/cards/m/MorkrutBanshee.java b/Mage.Sets/src/mage/cards/m/MorkrutBanshee.java index fba035c3c19..f3d68ccc2c9 100644 --- a/Mage.Sets/src/mage/cards/m/MorkrutBanshee.java +++ b/Mage.Sets/src/mage/cards/m/MorkrutBanshee.java @@ -20,7 +20,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class MorkrutBanshee extends CardImpl { - private static final String staticText = "Morbid - When {this} enters the battlefield, if a creature died this turn, target creature gets -4/-4 until end of turn."; + private static final String staticText = "Morbid — When {this} enters the battlefield, if a creature died this turn, target creature gets -4/-4 until end of turn."; public MorkrutBanshee(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); @@ -30,7 +30,7 @@ public final class MorkrutBanshee extends CardImpl { this.power = new MageInt(4); this.toughness = new MageInt(4); - // Morbid - When Morkut Banshee enters the battlefield, if a creature died this turn, target creature gets -4/-4 until end of turn. + // Morbid — When Morkut Banshee enters the battlefield, if a creature died this turn, target creature gets -4/-4 until end of turn. TriggeredAbility triggeredAbility = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-4, -4, Duration.EndOfTurn)); TriggeredAbility ability = new ConditionalInterveningIfTriggeredAbility(triggeredAbility, MorbidCondition.instance, staticText); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/p/PredatorsHowl.java b/Mage.Sets/src/mage/cards/p/PredatorsHowl.java index 38f2d633786..b0ebabf2149 100644 --- a/Mage.Sets/src/mage/cards/p/PredatorsHowl.java +++ b/Mage.Sets/src/mage/cards/p/PredatorsHowl.java @@ -21,7 +21,7 @@ public final class PredatorsHowl extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{G}"); // Create a 2/2 green Wolf creature token. - // Morbid - Create three 2/2 green Wolf creature tokens instead if a creature died this turn. + // Morbid — Create three 2/2 green Wolf creature tokens instead if a creature died this turn. Effect effect = new ConditionalOneShotEffect( new CreateTokenEffect(new WolfToken(), 3), new CreateTokenEffect(new WolfToken(), 1), diff --git a/Mage.Sets/src/mage/cards/p/PuresteelPaladin.java b/Mage.Sets/src/mage/cards/p/PuresteelPaladin.java index 395ea6b16e8..19252b5c053 100644 --- a/Mage.Sets/src/mage/cards/p/PuresteelPaladin.java +++ b/Mage.Sets/src/mage/cards/p/PuresteelPaladin.java @@ -39,11 +39,11 @@ public final class PuresteelPaladin extends CardImpl { // Whenever an Equipment enters the battlefield under your control, you may draw a card. this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), filter, true)); - // Metalcraft - Equipment you control have equip {0} as long as you control three or more artifacts + // Metalcraft — Equipment you control have equip {0} as long as you control three or more artifacts this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( new GainAbilityControlledEffect(new EquipAbility(Outcome.AddAbility, new GenericManaCost(0)), Duration.WhileOnBattlefield, filter), MetalcraftCondition.instance, - "Metalcraft - Equipment you control have equip {0} as long as you control three or more artifacts"))); + "Metalcraft — Equipment you control have equip {0} as long as you control three or more artifacts"))); } public PuresteelPaladin(final PuresteelPaladin card) { diff --git a/Mage.Sets/src/mage/cards/r/RazorfieldRhino.java b/Mage.Sets/src/mage/cards/r/RazorfieldRhino.java index bf23b4fca7a..28b09384e2a 100644 --- a/Mage.Sets/src/mage/cards/r/RazorfieldRhino.java +++ b/Mage.Sets/src/mage/cards/r/RazorfieldRhino.java @@ -28,7 +28,7 @@ public final class RazorfieldRhino extends CardImpl { this.power = new MageInt(4); this.toughness = new MageInt(4); ContinuousEffect effect1 = new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(effect1, MetalcraftCondition.instance, "Metalcraft - Razorfield Rhino gets +2/+2 as long as you control three or more artifacts"))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(effect1, MetalcraftCondition.instance, "Metalcraft — Razorfield Rhino gets +2/+2 as long as you control three or more artifacts"))); } public RazorfieldRhino (final RazorfieldRhino card) { diff --git a/Mage.Sets/src/mage/cards/r/ReaperFromTheAbyss.java b/Mage.Sets/src/mage/cards/r/ReaperFromTheAbyss.java index c9f2aa56786..c9a9bf3f10d 100644 --- a/Mage.Sets/src/mage/cards/r/ReaperFromTheAbyss.java +++ b/Mage.Sets/src/mage/cards/r/ReaperFromTheAbyss.java @@ -87,6 +87,6 @@ class ReaperFromTheAbyssAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Morbid - At the beginning of each end step, if a creature died this turn, destroy target non-demon creature."; + return "Morbid — At the beginning of each end step, if a creature died this turn, destroy target non-demon creature."; } } diff --git a/Mage.Sets/src/mage/cards/r/RustedRelic.java b/Mage.Sets/src/mage/cards/r/RustedRelic.java index b1303c1436e..95014e11eb4 100644 --- a/Mage.Sets/src/mage/cards/r/RustedRelic.java +++ b/Mage.Sets/src/mage/cards/r/RustedRelic.java @@ -29,7 +29,7 @@ public final class RustedRelic extends CardImpl { new ConditionalContinuousEffect( new BecomesCreatureSourceEffect(new RustedRelicToken(), "artifact", Duration.WhileOnBattlefield), MetalcraftCondition.instance, - "Metalcraft - {this} is a 5/5 Golem artifact creature as long as you control three or more artifacts"))); + "Metalcraft — {this} is a 5/5 Golem artifact creature as long as you control three or more artifacts"))); } public RustedRelic (final RustedRelic card) { diff --git a/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java b/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java index 544612e3fd6..b356cdac110 100644 --- a/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java +++ b/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java @@ -20,7 +20,7 @@ import mage.constants.SubType; */ public final class ScreechingSilcaw extends CardImpl { - private static final String text = "Metalcraft - Whenever Screeching Silcaw deals combat damage to a player, if you control three or more artifacts, that player puts the top four cards of their library into their graveyard."; + private static final String text = "Metalcraft — Whenever Screeching Silcaw deals combat damage to a player, if you control three or more artifacts, that player puts the top four cards of their library into their graveyard."; public ScreechingSilcaw(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); @@ -31,7 +31,7 @@ public final class ScreechingSilcaw extends CardImpl { this.addAbility(FlyingAbility.getInstance()); - //"Metalcraft - Whenever Screeching Silcaw deals combat damage to a player, if you control three or more artifacts, that player puts the top four cards of their library into their graveyard. + //"Metalcraft — Whenever Screeching Silcaw deals combat damage to a player, if you control three or more artifacts, that player puts the top four cards of their library into their graveyard. TriggeredAbility conditional = new ConditionalInterveningIfTriggeredAbility( new DealsCombatDamageToAPlayerTriggeredAbility(new PutLibraryIntoGraveTargetEffect(4), false, true), MetalcraftCondition.instance, text); diff --git a/Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java b/Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java index ffb876f5998..15b2be1cafd 100644 --- a/Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java +++ b/Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java @@ -41,7 +41,7 @@ public final class SkirsdagHighPriest extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(2); - // Morbid - {tap}, Tap two untapped creatures you control: Create a 5/5 black Demon creature token with flying. Activate this ability only if a creature died this turn. + // Morbid — {tap}, Tap two untapped creatures you control: Create a 5/5 black Demon creature token with flying. Activate this ability only if a creature died this turn. Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new DemonToken()), new TapSourceCost(), MorbidCondition.instance); ability.addCost(new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, false))); diff --git a/Mage.Sets/src/mage/cards/s/SnapsailGlider.java b/Mage.Sets/src/mage/cards/s/SnapsailGlider.java index 0650452dde5..7cc55dd5da2 100644 --- a/Mage.Sets/src/mage/cards/s/SnapsailGlider.java +++ b/Mage.Sets/src/mage/cards/s/SnapsailGlider.java @@ -23,7 +23,7 @@ import mage.constants.Zone; */ public final class SnapsailGlider extends CardImpl { - protected static String rule = "Metalcraft - Snapsail Glider has flying as long as you control three or more artifacts"; + protected static String rule = "Metalcraft — Snapsail Glider has flying as long as you control three or more artifacts"; public SnapsailGlider (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); diff --git a/Mage.Sets/src/mage/cards/s/SomberwaldSpider.java b/Mage.Sets/src/mage/cards/s/SomberwaldSpider.java index 4fb9b1ec7dd..177a0ec798f 100644 --- a/Mage.Sets/src/mage/cards/s/SomberwaldSpider.java +++ b/Mage.Sets/src/mage/cards/s/SomberwaldSpider.java @@ -28,7 +28,7 @@ public final class SomberwaldSpider extends CardImpl { this.toughness = new MageInt(4); this.addAbility(ReachAbility.getInstance()); - // Morbid - Somberwald Spider enters the battlefield with two +1/+1 counters on it if a creature died this turn. + // Morbid — Somberwald Spider enters the battlefield with two +1/+1 counters on it if a creature died this turn. this.addAbility(new EntersBattlefieldAbility( new ConditionalOneShotEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), MorbidCondition.instance, ""), "with two +1/+1 counters on it if a creature died this turn")); diff --git a/Mage.Sets/src/mage/cards/s/SpiralingDuelist.java b/Mage.Sets/src/mage/cards/s/SpiralingDuelist.java index fe37f728610..52af0e6edc4 100644 --- a/Mage.Sets/src/mage/cards/s/SpiralingDuelist.java +++ b/Mage.Sets/src/mage/cards/s/SpiralingDuelist.java @@ -22,7 +22,7 @@ import mage.constants.Zone; */ public final class SpiralingDuelist extends CardImpl { - private static final String effectText = "Metalcraft - Spiraling Duelist has double strike as long as you control three or more artifacts."; + private static final String effectText = "Metalcraft — Spiraling Duelist has double strike as long as you control three or more artifacts."; public SpiralingDuelist(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{R}"); diff --git a/Mage.Sets/src/mage/cards/s/SpireSerpent.java b/Mage.Sets/src/mage/cards/s/SpireSerpent.java index 0023dc7d2e2..a8338bd6519 100644 --- a/Mage.Sets/src/mage/cards/s/SpireSerpent.java +++ b/Mage.Sets/src/mage/cards/s/SpireSerpent.java @@ -25,7 +25,7 @@ import mage.constants.Zone; */ public final class SpireSerpent extends CardImpl { - private static final String abilityText1 = "Metalcraft - As long as you control three or more artifacts, {this} gets +2/+2"; + private static final String abilityText1 = "Metalcraft — As long as you control three or more artifacts, {this} gets +2/+2"; public SpireSerpent(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}"); diff --git a/Mage.Sets/src/mage/cards/s/StoicRebuttal.java b/Mage.Sets/src/mage/cards/s/StoicRebuttal.java index 7722c315e80..a9340141640 100644 --- a/Mage.Sets/src/mage/cards/s/StoicRebuttal.java +++ b/Mage.Sets/src/mage/cards/s/StoicRebuttal.java @@ -23,7 +23,7 @@ public final class StoicRebuttal extends CardImpl { public StoicRebuttal(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}{U}"); - // Metalcraft - Stoic Rebuttal costs {1} less to cast if you control three or more artifacts. + // Metalcraft — Stoic Rebuttal costs {1} less to cast if you control three or more artifacts. Ability ability = new SimpleStaticAbility(Zone.STACK, new SpellCostReductionSourceEffect(1, MetalcraftCondition.instance)); ability.setRuleAtTheTop(true); ability.setAbilityWord(AbilityWord.METALCRAFT); diff --git a/Mage.Sets/src/mage/cards/t/TragicSlip.java b/Mage.Sets/src/mage/cards/t/TragicSlip.java index 6b5b595f2c2..af22f6aa801 100644 --- a/Mage.Sets/src/mage/cards/t/TragicSlip.java +++ b/Mage.Sets/src/mage/cards/t/TragicSlip.java @@ -23,12 +23,12 @@ public final class TragicSlip extends CardImpl { // Target creature gets -1/-1 until end of turn. - // Morbid - That creature gets -13/-13 until end of turn instead if a creature died this turn. + // Morbid — That creature gets -13/-13 until end of turn instead if a creature died this turn. this.getSpellAbility().addEffect(new ConditionalContinuousEffect( new BoostTargetEffect(-13, -13, Duration.EndOfTurn), new BoostTargetEffect(-1, -1, Duration.EndOfTurn), new LockedInCondition(MorbidCondition.instance), - "Target creature gets -1/-1 until end of turn. Morbid - That creature gets -13/-13 until end of turn instead if a creature died this turn")); + "Target creature gets -1/-1 until end of turn. Morbid — That creature gets -13/-13 until end of turn instead if a creature died this turn")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/u/UlvenwaldBear.java b/Mage.Sets/src/mage/cards/u/UlvenwaldBear.java index d7c335f2f99..d219c273b84 100644 --- a/Mage.Sets/src/mage/cards/u/UlvenwaldBear.java +++ b/Mage.Sets/src/mage/cards/u/UlvenwaldBear.java @@ -29,7 +29,7 @@ public final class UlvenwaldBear extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - // Morbid - When Ulvenwald Bear enters the battlefield, if a creature died this turn, put two +1/+1 counters on target creature. + // Morbid — When Ulvenwald Bear enters the battlefield, if a creature died this turn, put two +1/+1 counters on target creature. Ability ability = new ConditionalInterveningIfTriggeredAbility(new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2), Outcome.BoostCreature)), MorbidCondition.instance, "When {this} enters the battlefield, if a creature died this turn, put two +1/+1 counters on target creature."); ability.addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/v/VedalkenCertarch.java b/Mage.Sets/src/mage/cards/v/VedalkenCertarch.java index 2e590c66e38..afa85439ab1 100644 --- a/Mage.Sets/src/mage/cards/v/VedalkenCertarch.java +++ b/Mage.Sets/src/mage/cards/v/VedalkenCertarch.java @@ -43,7 +43,7 @@ public final class VedalkenCertarch extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - // Metalcraft - {T}: Tap target artifact, creature, or land. Activate this ability only if you control three or more artifacts. + // Metalcraft — {T}: Tap target artifact, creature, or land. Activate this ability only if you control three or more artifacts. Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new TapSourceCost(), MetalcraftCondition.instance); ability.setAbilityWord(AbilityWord.METALCRAFT); ability.addTarget(new TargetPermanent(filter)); diff --git a/Mage.Sets/src/mage/cards/w/Wakedancer.java b/Mage.Sets/src/mage/cards/w/Wakedancer.java index 095f2420b0b..2616976978c 100644 --- a/Mage.Sets/src/mage/cards/w/Wakedancer.java +++ b/Mage.Sets/src/mage/cards/w/Wakedancer.java @@ -20,7 +20,7 @@ import mage.game.permanent.token.ZombieToken; */ public final class Wakedancer extends CardImpl { - private static final String staticText = "Morbid - When {this} enters the battlefield, if a creature died this turn, create a 2/2 black Zombie creature token."; + private static final String staticText = "Morbid — When {this} enters the battlefield, if a creature died this turn, create a 2/2 black Zombie creature token."; public Wakedancer(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); @@ -31,7 +31,7 @@ public final class Wakedancer extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - // Morbid - When Wakedancer enters the battlefield, if a creature died this turn, create a 2/2 black Zombie creature token. + // Morbid — When Wakedancer enters the battlefield, if a creature died this turn, create a 2/2 black Zombie creature token. TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new ZombieToken())); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MorbidCondition.instance, staticText)); } diff --git a/Mage.Sets/src/mage/cards/w/WoodlandSleuth.java b/Mage.Sets/src/mage/cards/w/WoodlandSleuth.java index 00b5fc45ef7..bb5b2b2a95e 100644 --- a/Mage.Sets/src/mage/cards/w/WoodlandSleuth.java +++ b/Mage.Sets/src/mage/cards/w/WoodlandSleuth.java @@ -27,7 +27,7 @@ import mage.util.RandomUtil; */ public final class WoodlandSleuth extends CardImpl { - private static final String staticText = "Morbid - When {this} enters the battlefield, if a creature died this turn, return a creature card at random from your graveyard to your hand."; + private static final String staticText = "Morbid — When {this} enters the battlefield, if a creature died this turn, return a creature card at random from your graveyard to your hand."; public WoodlandSleuth(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); @@ -38,7 +38,7 @@ public final class WoodlandSleuth extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(3); - // Morbid - When Woodland Sleuth enters the battlefield, if a creature died this turn, return a creature card at random from your graveyard to your hand. + // Morbid — When Woodland Sleuth enters the battlefield, if a creature died this turn, return a creature card at random from your graveyard to your hand. TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new WoodlandSleuthEffect()); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, MorbidCondition.instance, staticText)); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MetalcraftTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MetalcraftTest.java index 43d8fb89d3a..d37caa01a5f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MetalcraftTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MetalcraftTest.java @@ -23,7 +23,7 @@ public class MetalcraftTest extends CardTestPlayerBase { public void testMetalcraftFromBlinkmoth() { addCard(Zone.BATTLEFIELD, playerA, "Darksteel Citadel",1); - // Metalcraft - {this} is a 5/5 Golem artifact creature as long as you control three or more artifacts + // Metalcraft — {this} is a 5/5 Golem artifact creature as long as you control three or more artifacts addCard(Zone.BATTLEFIELD, playerA, "Rusted Relic", 1); // {T}: Add {C}to your mana pool. diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/rules/CantCastTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/rules/CantCastTest.java index 21e26f9570c..7fb74ea1ada 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/rules/CantCastTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/rules/CantCastTest.java @@ -127,7 +127,7 @@ public class CantCastTest extends CardTestPlayerBase { // Your opponents can't block with creatures with even converted mana costs. addCard(Zone.BATTLEFIELD, playerB, "Void Winnower"); - // Metalcraft - {T}: Add one mana of any color. Activate this ability only if you control three or more artifacts. + // Metalcraft — {T}: Add one mana of any color. Activate this ability only if you control three or more artifacts. addCard(Zone.HAND, playerA, "Mox Opal", 1); // {0} castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mox Opal"); From 5d2e95f1a69c6c89551c701d0047f440fb0de77b Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sat, 28 Jul 2018 15:32:31 -0400 Subject: [PATCH 58/71] Implemented Reality Scramble --- Mage.Sets/src/mage/cards/g/GenesisStorm.java | 3 +- .../src/mage/cards/r/RealityScramble.java | 111 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/cards/r/RealityScramble.java diff --git a/Mage.Sets/src/mage/cards/g/GenesisStorm.java b/Mage.Sets/src/mage/cards/g/GenesisStorm.java index c26ff95762c..48528b01284 100644 --- a/Mage.Sets/src/mage/cards/g/GenesisStorm.java +++ b/Mage.Sets/src/mage/cards/g/GenesisStorm.java @@ -7,6 +7,7 @@ import mage.abilities.keyword.CommanderStormAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.Cards; import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; @@ -62,7 +63,7 @@ class GenesisStormEffect extends OneShotEffect { if (controller == null) { return false; } - CardsImpl toReveal = new CardsImpl(); + Cards toReveal = new CardsImpl(); Card nonLandCard = null; for (Card card : controller.getLibrary().getCards(game)) { toReveal.add(card); diff --git a/Mage.Sets/src/mage/cards/r/RealityScramble.java b/Mage.Sets/src/mage/cards/r/RealityScramble.java new file mode 100644 index 00000000000..f3f8096971e --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RealityScramble.java @@ -0,0 +1,111 @@ +package mage.cards.r; + +import java.util.EnumSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.RetraceAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.other.OwnerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +/** + * + * @author TheElk801 + */ +public final class RealityScramble extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent("permanent you own"); + + static { + filter.add(new OwnerPredicate(TargetController.YOU)); + } + + public RealityScramble(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}{R}"); + + // Put target permanent you own on the bottom of your library. Reveal cards from the top of your library until you reveal a card that shares a card type with that permanent. Put that card onto the battlefield and the rest on the bottom of your library in a random order. + this.getSpellAbility().addEffect(new RealityScrambleEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + + // Retrace + this.addAbility(new RetraceAbility(this)); + } + + public RealityScramble(final RealityScramble card) { + super(card); + } + + @Override + public RealityScramble copy() { + return new RealityScramble(this); + } +} + +class RealityScrambleEffect extends OneShotEffect { + + public RealityScrambleEffect() { + super(Outcome.Benefit); + this.staticText = "Put target permanent you own " + + "on the bottom of your library. Reveal cards from " + + "the top of your library until you reveal a card " + + "that shares a card type with that permanent. " + + "Put that card onto the battlefield and the rest " + + "on the bottom of your library in a random order."; + } + + public RealityScrambleEffect(final RealityScrambleEffect effect) { + super(effect); + } + + @Override + public RealityScrambleEffect copy() { + return new RealityScrambleEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + Player controller = game.getPlayer(source.getControllerId()); + if (permanent == null || controller == null) { + return false; + } + Set types = EnumSet.noneOf(CardType.class); + types.addAll(permanent.getCardType()); + controller.putCardsOnBottomOfLibrary( + new CardsImpl(permanent), game, source, false + ); + Cards toReveal = new CardsImpl(); + Card cardToPlay = null; + for (Card card : controller.getLibrary().getCards(game)) { + toReveal.add(card); + for (CardType type : types) { + if (card.getCardType().contains(type)) { + cardToPlay = card; + break; + } + } + } + controller.revealCards(source, toReveal, game); + if (cardToPlay != null) { + controller.moveCards(cardToPlay, Zone.BATTLEFIELD, source, game); + toReveal.remove(cardToPlay); + } + controller.putCardsOnBottomOfLibrary(toReveal, game, source, false); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 10754bafc2f..c608cc8c28e 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -220,6 +220,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Rakdos Carnarium", 273, Rarity.COMMON, mage.cards.r.RakdosCarnarium.class)); cards.add(new SetCardInfo("Rampaging Baloths", 158, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); cards.add(new SetCardInfo("Ravenous Slime", 34, Rarity.RARE, mage.cards.r.RavenousSlime.class)); + cards.add(new SetCardInfo("Reality Scramble", 25, Rarity.RARE, mage.cards.r.RealityScramble.class)); cards.add(new SetCardInfo("Reclamation Sage", 159, Rarity.UNCOMMON, mage.cards.r.ReclamationSage.class)); cards.add(new SetCardInfo("Retreat to Hagra", 116, Rarity.UNCOMMON, mage.cards.r.RetreatToHagra.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); From db6211cd202d35038e2c9edafb4a29fc37b03a45 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sat, 28 Jul 2018 16:25:39 -0400 Subject: [PATCH 59/71] Implemented Saheeli, the Gifted --- .../src/mage/cards/s/SaheeliTheGifted.java | 162 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + .../common/CreateTokenCopyTargetEffect.java | 41 ++++- 3 files changed, 195 insertions(+), 9 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/s/SaheeliTheGifted.java diff --git a/Mage.Sets/src/mage/cards/s/SaheeliTheGifted.java b/Mage.Sets/src/mage/cards/s/SaheeliTheGifted.java new file mode 100644 index 00000000000..4e31f691b7f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SaheeliTheGifted.java @@ -0,0 +1,162 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.SpellAbility; +import mage.abilities.common.CanBeYourCommanderAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.CostModificationType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.ServoToken; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; +import mage.watchers.common.CastSpellLastTurnWatcher; + +/** + * + * @author TheElk801 + */ +public final class SaheeliTheGifted extends CardImpl { + + public SaheeliTheGifted(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{U}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SAHEELI); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(4)); + + // +1: Create a 1/1 colorless Servo artifact creature token. + this.addAbility(new LoyaltyAbility( + new CreateTokenEffect(new ServoToken()), 1 + )); + + // +1: The next spell you cast this turn costs {1} less to cast for each artifact you control as you cast it. + this.addAbility(new LoyaltyAbility( + new SaheeliTheGiftedCostReductionEffect(), 1 + )); + + // -7: For each artifact you control, create a token that's a copy of it. Those tokens gain haste. Exile those tokens at the beginning of the next end step. + this.addAbility(new LoyaltyAbility( + new SaheeliTheGiftedTokenEffect(), -7 + )); + + // Saheeli, the Gifted can be your commander. + this.addAbility(CanBeYourCommanderAbility.getInstance()); + } + + public SaheeliTheGifted(final SaheeliTheGifted card) { + super(card); + } + + @Override + public SaheeliTheGifted copy() { + return new SaheeliTheGifted(this); + } +} + +class SaheeliTheGiftedCostReductionEffect extends CostModificationEffectImpl { + + private int spellsCast; + + public SaheeliTheGiftedCostReductionEffect() { + super(Duration.EndOfTurn, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "the next spell you cast this turn costs {1} less to cast " + + "for each artifact you control as you cast it"; + } + + protected SaheeliTheGiftedCostReductionEffect(final SaheeliTheGiftedCostReductionEffect effect) { + super(effect); + this.spellsCast = effect.spellsCast; + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + if (watcher != null) { + spellsCast = watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()); + } + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + int artifactCount = game.getBattlefield().getAllActivePermanents( + StaticFilters.FILTER_PERMANENT_ARTIFACT_AN, + source.getControllerId(), game + ).size(); + CardUtil.reduceCost(abilityToModify, artifactCount); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + if (watcher != null) { + if (watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()) > spellsCast) { + discard(); // only one use + return false; + } + } + if (abilityToModify instanceof SpellAbility) { + return abilityToModify.isControlledBy(source.getControllerId()); + } + return false; + } + + @Override + public SaheeliTheGiftedCostReductionEffect copy() { + return new SaheeliTheGiftedCostReductionEffect(this); + } +} + +class SaheeliTheGiftedTokenEffect extends OneShotEffect { + + public SaheeliTheGiftedTokenEffect() { + super(Outcome.Benefit); + this.staticText = "for each artifact you control, " + + "create a token that's a copy of it. " + + "Those tokens gain haste. " + + "Exile those tokens at the beginning of the next end step."; + } + + public SaheeliTheGiftedTokenEffect(final SaheeliTheGiftedTokenEffect effect) { + super(effect); + } + + @Override + public SaheeliTheGiftedTokenEffect copy() { + return new SaheeliTheGiftedTokenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents( + StaticFilters.FILTER_PERMANENT_ARTIFACT_AN, + source.getControllerId(), game + )) { + if (permanent != null) { + CreateTokenCopyTargetEffect effect + = new CreateTokenCopyTargetEffect(); + effect.setTargetPointer(new FixedTarget(permanent, game)); + effect.setHasHaste(true); + effect.apply(game, source); + effect.exileTokensCreatedAtNextEndStep(game, source); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index c608cc8c28e..1401860a88e 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -233,6 +233,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Sage's Reverie", 72, Rarity.UNCOMMON, mage.cards.s.SagesReverie.class)); cards.add(new SetCardInfo("Saheeli's Artistry", 100, Rarity.RARE, mage.cards.s.SaheelisArtistry.class)); cards.add(new SetCardInfo("Saheeli's Directive", 26, Rarity.RARE, mage.cards.s.SaheelisDirective.class)); + cards.add(new SetCardInfo("Saheeli, the Gifted", 44, Rarity.MYTHIC, mage.cards.s.SaheeliTheGifted.class)); cards.add(new SetCardInfo("Sakura-Tribe Elder", 160, Rarity.COMMON, mage.cards.s.SakuraTribeElder.class)); cards.add(new SetCardInfo("Savage Lands", 275, Rarity.UNCOMMON, mage.cards.s.SavageLands.class)); cards.add(new SetCardInfo("Savage Twister", 190, Rarity.UNCOMMON, mage.cards.s.SavageTwister.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java index 40936884ef9..092c8ec92cb 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import java.util.ArrayList; @@ -8,6 +7,8 @@ import mage.MageObject; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.Mode; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; @@ -17,6 +18,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.SuperType; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.EmptyToken; @@ -124,14 +126,6 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { this.isntLegendary = effect.isntLegendary; } - public void setBecomesArtifact(boolean becomesArtifact) { - this.becomesArtifact = becomesArtifact; - } - - public void setIsntLegendary(boolean isntLegendary) { - this.isntLegendary = isntLegendary; - } - @Override public boolean apply(Game game, Ability source) { UUID targetId; @@ -282,4 +276,33 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { public void setUseLKI(boolean useLKI) { this.useLKI = useLKI; } + + public void setBecomesArtifact(boolean becomesArtifact) { + this.becomesArtifact = becomesArtifact; + } + + public void setIsntLegendary(boolean isntLegendary) { + this.isntLegendary = isntLegendary; + } + + public void setHasHaste(boolean hasHaste) { + this.hasHaste = hasHaste; + } + + public void exileTokensCreatedAtNextEndStep(Game game, Ability source) { + for (Permanent tokenPermanent : addedTokenPermanents) { + ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD); + exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect), source); + } + } + + public void exileTokensCreatedAtEndOfCombat(Game game, Ability source) { + for (Permanent tokenPermanent : addedTokenPermanents) { + + ExileTargetEffect exileEffect = new ExileTargetEffect(null, "", Zone.BATTLEFIELD); + exileEffect.setTargetPointer(new FixedTarget(tokenPermanent, game)); + game.addDelayedTriggeredAbility(new AtTheEndOfCombatDelayedTriggeredAbility(exileEffect), source); + } + } } From ac0b3315eafb62be72f29dd547a8881bd1886bae Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sat, 28 Jul 2018 17:18:52 -0400 Subject: [PATCH 60/71] Implemented Sower of Discord --- .../src/mage/cards/s/SowerOfDiscord.java | 162 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 163 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SowerOfDiscord.java diff --git a/Mage.Sets/src/mage/cards/s/SowerOfDiscord.java b/Mage.Sets/src/mage/cards/s/SowerOfDiscord.java new file mode 100644 index 00000000000..480837f2546 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SowerOfDiscord.java @@ -0,0 +1,162 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public final class SowerOfDiscord extends CardImpl { + + public SowerOfDiscord(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.subtype.add(SubType.DEMON); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // As Sower of Discord enters the battlefield, choose two players. + this.addAbility(new AsEntersBattlefieldAbility( + new BitterFeudEntersBattlefieldEffect() + )); + + // Whenever damage is dealt to one of the chosen players, the other chosen player also loses that much life. + this.addAbility(new SowerOfDiscordTriggeredAbility()); + } + + public SowerOfDiscord(final SowerOfDiscord card) { + super(card); + } + + @Override + public SowerOfDiscord copy() { + return new SowerOfDiscord(this); + } +} + +class BitterFeudEntersBattlefieldEffect extends OneShotEffect { + + public BitterFeudEntersBattlefieldEffect() { + super(Outcome.Damage); + staticText = "choose two players"; + } + + public BitterFeudEntersBattlefieldEffect(final BitterFeudEntersBattlefieldEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); + if (controller == null || permanent == null) { + return false; + } + TargetPlayer target = new TargetPlayer(2, 2, true); + controller.chooseTarget(outcome, target, source, game); + Player player1 = game.getPlayer(target.getFirstTarget()); + if (target.getTargets().size() <= 1) { + return false; + } + Player player2 = game.getPlayer(target.getTargets().get(1)); + if (player1 == null || player2 == null) { + return false; + } + game.getState().setValue(source.getSourceId() + "_player1", player1); + game.getState().setValue(source.getSourceId() + "_player2", player2); + game.informPlayers(permanent.getLogName() + ": " + + controller.getLogName() + " has chosen " + + player1.getLogName() + " and " + player2.getLogName() + ); + permanent.addInfo( + "chosen players", + "Chosen players: " + + player1.getName() + ", " + + player2.getName() + "", game + ); + return true; + } + + @Override + public BitterFeudEntersBattlefieldEffect copy() { + return new BitterFeudEntersBattlefieldEffect(this); + } + +} + +class SowerOfDiscordTriggeredAbility extends TriggeredAbilityImpl { + + public SowerOfDiscordTriggeredAbility() { + super(Zone.BATTLEFIELD, null); + } + + public SowerOfDiscordTriggeredAbility(final SowerOfDiscordTriggeredAbility ability) { + super(ability); + } + + @Override + public SowerOfDiscordTriggeredAbility copy() { + return new SowerOfDiscordTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + int damage = event.getAmount(); + Player player1 = (Player) game.getState().getValue( + this.getSourceId() + "_player1" + ); + Player player2 = (Player) game.getState().getValue( + this.getSourceId() + "_player2" + ); + if (player1 == null || player2 == null || damage == 0) { + return false; + } + Effect effect = new LoseLifeTargetEffect(damage); + if (event.getTargetId().equals(player1.getId())) { + this.getEffects().clear(); + effect.setTargetPointer(new FixedTarget(player2.getId())); + this.addEffect(effect); + return true; + } else if (event.getTargetId().equals(player2.getId())) { + this.getEffects().clear(); + effect.setTargetPointer(new FixedTarget(player1.getId())); + this.addEffect(effect); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever damage is dealt to one of the chosen players, " + + "the other chosen player also loses that much life."; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 1401860a88e..45fd3874db2 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -261,6 +261,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Soul Snare", 76, Rarity.UNCOMMON, mage.cards.s.SoulSnare.class)); cards.add(new SetCardInfo("Soul of Innistrad", 118, Rarity.MYTHIC, mage.cards.s.SoulOfInnistrad.class)); cards.add(new SetCardInfo("Soul of New Phyrexia", 223, Rarity.MYTHIC, mage.cards.s.SoulOfNewPhyrexia.class)); + cards.add(new SetCardInfo("Sower of Discord", 19, Rarity.RARE, mage.cards.s.SowerOfDiscord.class)); cards.add(new SetCardInfo("Spawning Grounds", 163, Rarity.RARE, mage.cards.s.SpawningGrounds.class)); cards.add(new SetCardInfo("Sphinx of Jwar Isle", 103, Rarity.RARE, mage.cards.s.SphinxOfJwarIsle.class)); cards.add(new SetCardInfo("Sphinx of Uthuun", 104, Rarity.RARE, mage.cards.s.SphinxOfUthuun.class)); From 97dcba265260928fc6cbfb2ee9b8a2513d6343d6 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sat, 28 Jul 2018 17:19:29 -0400 Subject: [PATCH 61/71] small fix --- Mage.Sets/src/mage/cards/s/SowerOfDiscord.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Mage.Sets/src/mage/cards/s/SowerOfDiscord.java b/Mage.Sets/src/mage/cards/s/SowerOfDiscord.java index 480837f2546..18d91f47571 100644 --- a/Mage.Sets/src/mage/cards/s/SowerOfDiscord.java +++ b/Mage.Sets/src/mage/cards/s/SowerOfDiscord.java @@ -40,7 +40,7 @@ public final class SowerOfDiscord extends CardImpl { // As Sower of Discord enters the battlefield, choose two players. this.addAbility(new AsEntersBattlefieldAbility( - new BitterFeudEntersBattlefieldEffect() + new SowerOfDiscordEntersBattlefieldEffect() )); // Whenever damage is dealt to one of the chosen players, the other chosen player also loses that much life. @@ -57,14 +57,14 @@ public final class SowerOfDiscord extends CardImpl { } } -class BitterFeudEntersBattlefieldEffect extends OneShotEffect { +class SowerOfDiscordEntersBattlefieldEffect extends OneShotEffect { - public BitterFeudEntersBattlefieldEffect() { + public SowerOfDiscordEntersBattlefieldEffect() { super(Outcome.Damage); staticText = "choose two players"; } - public BitterFeudEntersBattlefieldEffect(final BitterFeudEntersBattlefieldEffect effect) { + public SowerOfDiscordEntersBattlefieldEffect(final SowerOfDiscordEntersBattlefieldEffect effect) { super(effect); } @@ -101,8 +101,8 @@ class BitterFeudEntersBattlefieldEffect extends OneShotEffect { } @Override - public BitterFeudEntersBattlefieldEffect copy() { - return new BitterFeudEntersBattlefieldEffect(this); + public SowerOfDiscordEntersBattlefieldEffect copy() { + return new SowerOfDiscordEntersBattlefieldEffect(this); } } From 3407a3e7423a29f472f6d5210f0c56da4a0a8ab1 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sat, 28 Jul 2018 20:10:24 -0400 Subject: [PATCH 62/71] Implemented Coveted Jewel --- Mage.Sets/src/mage/cards/c/CovetedJewel.java | 135 +++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 136 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/CovetedJewel.java diff --git a/Mage.Sets/src/mage/cards/c/CovetedJewel.java b/Mage.Sets/src/mage/cards/c/CovetedJewel.java new file mode 100644 index 00000000000..63007242df7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CovetedJewel.java @@ -0,0 +1,135 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.abilities.effects.common.UntapSourceEffect; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; +import mage.abilities.mana.SimpleManaAbility; +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.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author TheElk801 + */ +public final class CovetedJewel extends CardImpl { + + public CovetedJewel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); + + // When Coveted Jewel enters the battlefield, draw three cards. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(3) + )); + + // {T}: Add three mana of any one color. + this.addAbility(new SimpleManaAbility( + Zone.BATTLEFIELD, + new AddManaOfAnyColorEffect(3), + new TapSourceCost() + )); + + // Whenever one or more creatures an opponent controls attack you and aren't blocked, that player draws three cards and gains control of Coveted Jewel. Untap it. + this.addAbility(new CovetedJewelTriggeredAbility()); + } + + public CovetedJewel(final CovetedJewel card) { + super(card); + } + + @Override + public CovetedJewel copy() { + return new CovetedJewel(this); + } +} + +class CovetedJewelTriggeredAbility extends TriggeredAbilityImpl { + + public CovetedJewelTriggeredAbility() { + super(Zone.BATTLEFIELD, new DrawCardTargetEffect(3), false); + this.addEffect(new CovetedJewelEffect()); + this.addEffect(new UntapSourceEffect()); + } + + public CovetedJewelTriggeredAbility(final CovetedJewelTriggeredAbility ability) { + super(ability); + } + + @Override + public CovetedJewelTriggeredAbility copy() { + return new CovetedJewelTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARE_BLOCKERS_STEP; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Player player = game.getPlayer(this.getControllerId()); + if (player == null) { + return false; + } + for (UUID attacker : game.getCombat().getAttackers()) { + Permanent creature = game.getPermanent(attacker); + if (creature != null + && player.hasOpponent(creature.getControllerId(), game) + && player.getId().equals(game.getCombat().getDefendingPlayerId(attacker, game)) + && !creature.isBlocked(game)) { + this.getEffects().setTargetPointer(new FixedTarget(this.getControllerId(), game)); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever one or more creatures an opponent controls attack you " + + "and aren't blocked, that player draws three cards " + + "and gains control of {this}. Untap it."; + } +} + +class CovetedJewelEffect extends ContinuousEffectImpl { + + public CovetedJewelEffect() { + super(Duration.Custom, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); + } + + public CovetedJewelEffect(final CovetedJewelEffect effect) { + super(effect); + } + + @Override + public CovetedJewelEffect copy() { + return new CovetedJewelEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + return false; + } + return permanent.changeControllerId(source.getFirstTarget(), game); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 45fd3874db2..c9e1253121f 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -69,6 +69,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Commander's Sphere", 200, Rarity.COMMON, mage.cards.c.CommandersSphere.class)); cards.add(new SetCardInfo("Consign to Dust", 136, Rarity.UNCOMMON, mage.cards.c.ConsignToDust.class)); cards.add(new SetCardInfo("Conundrum Sphinx", 84, Rarity.RARE, mage.cards.c.ConundrumSphinx.class)); + cards.add(new SetCardInfo("Coveted Jewel", 54, Rarity.RARE, mage.cards.c.CovetedJewel.class)); cards.add(new SetCardInfo("Crash of Rhino Beetles", 29, Rarity.RARE, mage.cards.c.CrashOfRhinoBeetles.class)); cards.add(new SetCardInfo("Creeping Renaissance", 137, Rarity.RARE, mage.cards.c.CreepingRenaissance.class)); cards.add(new SetCardInfo("Crib Swap", 65, Rarity.UNCOMMON, mage.cards.c.CribSwap.class)); From 3278139da32bbe0266d0261b047472cd6589f357 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sat, 28 Jul 2018 23:08:26 -0400 Subject: [PATCH 63/71] Implemented Myth Unbound --- Mage.Sets/src/mage/cards/m/MythUnbound.java | 113 ++++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 114 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/m/MythUnbound.java diff --git a/Mage.Sets/src/mage/cards/m/MythUnbound.java b/Mage.Sets/src/mage/cards/m/MythUnbound.java new file mode 100644 index 00000000000..28924a6075f --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MythUnbound.java @@ -0,0 +1,113 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.ZoneChangeAllTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.CostModificationType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.other.OwnerPredicate; +import mage.filter.predicate.permanent.CommanderPredicate; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * + * @author TheElk801 + */ +public final class MythUnbound extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(new CommanderPredicate()); + filter.add(new OwnerPredicate(TargetController.YOU)); + } + + public MythUnbound(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + // Your commander costs {1} less to cast for each time it's been cast from the command zone this game. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new MythUnboundCostReductionEffect() + )); + + // Whenever your commander is put into the command zone from anywhere, draw a card. + this.addAbility(new ZoneChangeAllTriggeredAbility( + Zone.BATTLEFIELD, Zone.ALL, Zone.COMMAND, + new DrawCardSourceControllerEffect(1), filter, + "Whenever your commander is put into " + + "the command zone from anywhere, ", false + )); + } + + public MythUnbound(final MythUnbound card) { + super(card); + } + + @Override + public MythUnbound copy() { + return new MythUnbound(this); + } +} + +class MythUnboundCostReductionEffect extends CostModificationEffectImpl { + + MythUnboundCostReductionEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "your commander costs {1} less to cast for each time " + + "it's been cast from the command zone this game"; + } + + MythUnboundCostReductionEffect(MythUnboundCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + Ability spellAbility = (SpellAbility) abilityToModify; + if (spellAbility != null) { + Integer amount = (Integer) game.getState().getValue(abilityToModify.getControllerId() + "_castCount"); + if (amount != null && amount > 0) { + CardUtil.reduceCost(spellAbility, amount); + return true; + } + } + return false; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + if (abilityToModify instanceof SpellAbility) { + if (abilityToModify.isControlledBy(source.getControllerId())) { + Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId()); + if (spell != null) { + return player.getCommandersIds().contains(spell.getId()); + } + } + } + return false; + } + + @Override + public MythUnboundCostReductionEffect copy() { + return new MythUnboundCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index c9e1253121f..c090a960a95 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -195,6 +195,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Mulldrifter", 94, Rarity.UNCOMMON, mage.cards.m.Mulldrifter.class)); cards.add(new SetCardInfo("Myr Battlesphere", 212, Rarity.RARE, mage.cards.m.MyrBattlesphere.class)); cards.add(new SetCardInfo("Myriad Landscape", 269, Rarity.UNCOMMON, mage.cards.m.MyriadLandscape.class)); + cards.add(new SetCardInfo("Myth Unbound", 32, Rarity.RARE, mage.cards.m.MythUnbound.class)); cards.add(new SetCardInfo("Nesting Dragon", 24, Rarity.RARE, mage.cards.n.NestingDragon.class)); cards.add(new SetCardInfo("New Benalia", 270, Rarity.UNCOMMON, mage.cards.n.NewBenalia.class)); cards.add(new SetCardInfo("Night Incarnate", 17, Rarity.RARE, mage.cards.n.NightIncarnate.class)); From 3875f42bac6880266a83058c5da30ac10da001a9 Mon Sep 17 00:00:00 2001 From: Samuel Sandeen Date: Sun, 29 Jul 2018 07:31:59 -0400 Subject: [PATCH 64/71] Refactor addCounters to fix bugs in edge cases. (#5154) Add code to check the controller of abilities on the stack instead of the controller of their source card or object. This fixes https://github.com/magefree/mage/issues/5152 --- .../cards/triggers/AbilityOwnershipTest.java | 56 +++++++++++++++++++ Mage/src/main/java/mage/cards/CardImpl.java | 10 +++- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/triggers/AbilityOwnershipTest.java diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/AbilityOwnershipTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/AbilityOwnershipTest.java new file mode 100644 index 00000000000..e1970fa1919 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/AbilityOwnershipTest.java @@ -0,0 +1,56 @@ +package org.mage.test.cards.triggers; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class AbilityOwnershipTest extends CardTestPlayerBase { + + @Test + public void testOwned() { + addCard(Zone.GRAVEYARD, playerB, "Soul Snuffers"); + addCard(Zone.GRAVEYARD, playerB, "Minister of Pain"); + + addCard(Zone.HAND, playerA, "Rise of the Dark Realms"); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 9); + addCard(Zone.BATTLEFIELD, playerA, "Obelisk Spider"); + + setLife(playerA, 20); + setLife(playerB, 20); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rise of the Dark Realms"); + setChoice(playerA, "Yes"); + addTarget(playerA, "Soul Snuffers"); // sacrifice to Exploit + + setStopAt(1, PhaseStep.END_COMBAT); + execute(); + + // Obelisk Spider Triggers twice once for the counter on Obelisk Spider. Once for the counter on Minister of Pain. + assertLife(playerA, 22); + assertLife(playerB, 18); + } + + @Test + public void testToGraveyard() { + addCard(Zone.GRAVEYARD, playerB, "Soul Snuffers"); + addCard(Zone.GRAVEYARD, playerB, "Minister of Pain"); + addCard(Zone.BATTLEFIELD, playerB, "Obelisk Spider"); + + addCard(Zone.HAND, playerA, "Rise of the Dark Realms"); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 9); + + setLife(playerA, 20); + setLife(playerB, 20); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rise of the Dark Realms"); + setChoice(playerA, "Yes"); + addTarget(playerA, "Soul Snuffers"); // sacrifice to Exploit + + setStopAt(1, PhaseStep.END_COMBAT); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + } +} diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index c682915fd5e..dd77793fc55 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -779,7 +779,15 @@ public abstract class CardImpl extends MageObjectImpl implements Card { @Override public boolean addCounters(Counter counter, Ability source, Game game, List appliedEffects, boolean isEffect) { boolean returnCode = true; - UUID sourceId = (source == null ? getId() : source.getSourceId()); + UUID sourceId = getId(); + if (source != null) { + MageObject object = game.getObject(source.getId()); + if (object instanceof StackObject) { + sourceId = source.getId(); + } else { + sourceId = source.getSourceId(); + } + } GameEvent countersEvent = GameEvent.getEvent(GameEvent.EventType.ADD_COUNTERS, objectId, sourceId, getControllerOrOwner(), counter.getName(), counter.getCount()); countersEvent.setAppliedEffects(appliedEffects); countersEvent.setFlag(isEffect); From a164dad83f23b0d1b40c39770babdfa317521671 Mon Sep 17 00:00:00 2001 From: Samuel Sandeen Date: Sun, 29 Jul 2018 07:40:48 -0400 Subject: [PATCH 65/71] Fix issues with Clone and Metallic Mimic (#5160) Fix bugs with Metallic Mimic and Adaptive Automaton and clone effects. Metallic Mimic and Adaptive Automaton were both using the technically correct EnterEventType specifier for their as enters the battlefield abilities. Despite it being technically correct this meant that their ability didn't trigger if they were cloned. Additionally EnterAttributeAddChosenSubtypeEffect changed the subtype of the base object which meant that clones entered in with the chosen subtype of the original. --- .../src/mage/cards/a/AdaptiveAutomaton.java | 35 +----------------- Mage.Sets/src/mage/cards/m/MetallicMimic.java | 2 + .../org/mage/test/cards/copy/CloneTest.java | 31 +++++++++++++++- .../continuous/AddChosenSubtypeEffect.java | 37 +++++++++++++++++++ .../EnterAttributeAddChosenSubtypeEffect.java | 10 ++--- 5 files changed, 75 insertions(+), 40 deletions(-) create mode 100644 Mage/src/main/java/mage/abilities/effects/common/continuous/AddChosenSubtypeEffect.java diff --git a/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java b/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java index cb47c035047..1e1341a51e9 100644 --- a/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java +++ b/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java @@ -3,10 +3,9 @@ package mage.cards.a; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; +import mage.abilities.effects.common.continuous.AddChosenSubtypeEffect; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.effects.common.continuous.BoostAllOfChosenSubtypeEffect; import mage.abilities.effects.common.enterAttribute.EnterAttributeAddChosenSubtypeEffect; @@ -15,8 +14,6 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; /** * @author nantuko @@ -42,7 +39,7 @@ public final class AdaptiveAutomaton extends CardImpl { ability.addEffect(new EnterAttributeAddChosenSubtypeEffect()); this.addAbility(ability); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AdaptiveAutomatonAddSubtypeEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AddChosenSubtypeEffect())); // Other creatures you control of the chosen type get +1/+1. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllOfChosenSubtypeEffect(1, 1, Duration.WhileOnBattlefield, filter, true))); } @@ -57,31 +54,3 @@ public final class AdaptiveAutomaton extends CardImpl { } } -class AdaptiveAutomatonAddSubtypeEffect extends ContinuousEffectImpl { - - public AdaptiveAutomatonAddSubtypeEffect() { - super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); - staticText = "{this} is the chosen type in addition to its other types"; - } - - public AdaptiveAutomatonAddSubtypeEffect(final AdaptiveAutomatonAddSubtypeEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - SubType subType = ChooseCreatureTypeEffect.getChoosenCreatureType(permanent.getId(), game); - if (subType != null && !permanent.hasSubtype(subType, game)) { - permanent.getSubtype(game).add(subType); - } - } - return true; - } - - @Override - public AdaptiveAutomatonAddSubtypeEffect copy() { - return new AdaptiveAutomatonAddSubtypeEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/m/MetallicMimic.java b/Mage.Sets/src/mage/cards/m/MetallicMimic.java index 58c8282e391..9dfcca6887d 100644 --- a/Mage.Sets/src/mage/cards/m/MetallicMimic.java +++ b/Mage.Sets/src/mage/cards/m/MetallicMimic.java @@ -4,6 +4,7 @@ package mage.cards.m; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.effects.common.continuous.AddChosenSubtypeEffect; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; @@ -36,6 +37,7 @@ public final class MetallicMimic extends CardImpl { // Metallic Mimic is the chosen type in addition to its other types. ability.addEffect(new EnterAttributeAddChosenSubtypeEffect()); this.addAbility(ability); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AddChosenSubtypeEffect())); // Each other creature you control of the chosen type enters the battlefield with an additional +1/+1 counter on it. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MetallicMimicReplacementEffect())); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CloneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CloneTest.java index 2bb567fbbd5..202b360e987 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CloneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CloneTest.java @@ -4,6 +4,7 @@ import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectsList; import mage.cards.Card; import mage.constants.PhaseStep; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.StaticFilters; @@ -89,7 +90,7 @@ public class CloneTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Llanowar Elves"); addCard(Zone.BATTLEFIELD, playerB, "Craw Wurm"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Public Executio", "Llanowar Elves"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Public Execution", "Llanowar Elves"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Clone"); setStopAt(1, PhaseStep.END_TURN); @@ -199,4 +200,32 @@ public class CloneTest extends CardTestPlayerBase { Assert.assertTrue("There should be a white and a blue Silvercoat Lion be on the battlefield", blueLion && whiteLion); } + @Test + public void testAdaptiveAutomaton() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.HAND, playerA, "Adaptive Automaton"); + + addCard(Zone.BATTLEFIELD, playerB, "Island", 4); + addCard(Zone.HAND, playerB, "Clone"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Adaptive Automaton"); + setChoice(playerA, "Elf"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Clone"); + setChoice(playerB, "Adaptive Automaton"); + setChoice(playerB, "Goblin"); + + setStopAt(2, PhaseStep.END_COMBAT); + execute(); + + assertPermanentCount(playerA, "Adaptive Automaton", 1); + Permanent original = getPermanent("Adaptive Automaton", playerA); + Assert.assertTrue("The original Adaptive Automaton should be an Elf", original.hasSubtype(SubType.ELF, currentGame)); + + assertPermanentCount(playerB, "Adaptive Automaton", 1); + Permanent clone = getPermanent("Adaptive Automaton", playerB); + Assert.assertFalse("The cloned Adaptive Automaton should not be as Elf", clone.hasSubtype(SubType.ELF, currentGame)); + Assert.assertTrue("The cloned Adaptive Automaton should be a Goblin", clone.hasSubtype(SubType.GOBLIN, currentGame)); + } + } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddChosenSubtypeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddChosenSubtypeEffect.java new file mode 100644 index 00000000000..bb86dce4a5d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddChosenSubtypeEffect.java @@ -0,0 +1,37 @@ +package mage.abilities.effects.common.continuous; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; + +public class AddChosenSubtypeEffect extends ContinuousEffectImpl { + + public AddChosenSubtypeEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); + staticText = "{this} is the chosen type in addition to its other types"; + } + + public AddChosenSubtypeEffect(final AddChosenSubtypeEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + SubType subType = ChooseCreatureTypeEffect.getChoosenCreatureType(permanent.getId(), game); + if (subType != null && !permanent.hasSubtype(subType, game)) { + permanent.getSubtype(game).add(subType); + } + } + return true; + } + + @Override + public AddChosenSubtypeEffect copy() { + return new AddChosenSubtypeEffect(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/enterAttribute/EnterAttributeAddChosenSubtypeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/enterAttribute/EnterAttributeAddChosenSubtypeEffect.java index edf8f95a1ed..b70c8bb1815 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/enterAttribute/EnterAttributeAddChosenSubtypeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/enterAttribute/EnterAttributeAddChosenSubtypeEffect.java @@ -11,6 +11,8 @@ import mage.game.permanent.Permanent; /** * + * IMPORTANT: This only adds the chosen subtype while the source permanent is entering the battlefield. + * You should also use @link{mage.abilities.effects.common.continuous.AddChosenSubtypeEffect} to make the subtype persist. * @author LevelX2 */ public class EnterAttributeAddChosenSubtypeEffect extends OneShotEffect { @@ -34,12 +36,8 @@ public class EnterAttributeAddChosenSubtypeEffect extends OneShotEffect { Permanent permanent = game.getPermanentEntering(source.getSourceId()); SubType subtype = (SubType) game.getState().getValue(source.getSourceId() + "_type"); if (permanent != null && subtype != null) { - MageObject mageObject = permanent.getBasicMageObject(game); - if (!mageObject.getSubtype(null).contains(subtype)) { - mageObject.getSubtype(null).add(subtype); - } - if (!permanent.getSubtype(null).contains(subtype)) { - permanent.getSubtype(null).add(subtype); + if (!permanent.getSubtype(game).contains(subtype)) { + permanent.getSubtype(game).add(subtype); } return true; } From 14520097a5601d3eb2e7fd3f4cfb3e40e9f83125 Mon Sep 17 00:00:00 2001 From: Samuel Sandeen Date: Sun, 29 Jul 2018 07:44:19 -0400 Subject: [PATCH 66/71] Fix issues with the ChosenSubtypePredicate and clone effects. (#5164) Update ChosenSubtypePredicate to be an ObjectPlayer predicate. This fixes how cards that use it act when cloned. Fixes https://github.com/magefree/mage/issues/5136 --- Mage.Sets/src/mage/cards/b/BelbesPortal.java | 2 +- Mage.Sets/src/mage/cards/b/BrassHerald.java | 2 +- .../src/mage/cards/c/CallerOfTheHunt.java | 2 +- Mage.Sets/src/mage/cards/h/HeraldsHorn.java | 2 +- Mage.Sets/src/mage/cards/k/KindredBoon.java | 2 +- .../src/mage/cards/k/KindredDiscovery.java | 2 +- .../mage/cards/m/MirrorOfTheForebears.java | 2 +- .../src/mage/cards/t/TravelersCloak.java | 2 +- .../cards/copy/CleverImpersonatorTest.java | 30 +++++++++++++++++++ .../mageobject/ChosenSubtypePredicate.java | 17 +++++------ 10 files changed, 45 insertions(+), 18 deletions(-) diff --git a/Mage.Sets/src/mage/cards/b/BelbesPortal.java b/Mage.Sets/src/mage/cards/b/BelbesPortal.java index 99433187af5..3364c22b2b6 100644 --- a/Mage.Sets/src/mage/cards/b/BelbesPortal.java +++ b/Mage.Sets/src/mage/cards/b/BelbesPortal.java @@ -30,7 +30,7 @@ public final class BelbesPortal extends CardImpl { this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.PutCreatureInPlay))); // {3}, {tap}: You may put a creature card of the chosen type from your hand onto the battlefield. FilterCreatureCard filter = new FilterCreatureCard("a creature card of the chosen type"); - filter.add(new ChosenSubtypePredicate(this.getId())); + filter.add(new ChosenSubtypePredicate()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutCardFromHandOntoBattlefieldEffect(filter), new ManaCostsImpl("{3}")); diff --git a/Mage.Sets/src/mage/cards/b/BrassHerald.java b/Mage.Sets/src/mage/cards/b/BrassHerald.java index 86d57ee69ba..870ccda042a 100644 --- a/Mage.Sets/src/mage/cards/b/BrassHerald.java +++ b/Mage.Sets/src/mage/cards/b/BrassHerald.java @@ -69,7 +69,7 @@ class BrassHeraldEntersEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { FilterCard filter = new FilterCard("creature cards of the chosen type"); - filter.add(new ChosenSubtypePredicate(source.getSourceId())); + filter.add(new ChosenSubtypePredicate()); return new RevealLibraryPutIntoHandEffect(4, filter, Zone.LIBRARY).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/c/CallerOfTheHunt.java b/Mage.Sets/src/mage/cards/c/CallerOfTheHunt.java index d27e9069319..f05249eeac4 100644 --- a/Mage.Sets/src/mage/cards/c/CallerOfTheHunt.java +++ b/Mage.Sets/src/mage/cards/c/CallerOfTheHunt.java @@ -49,7 +49,7 @@ public final class CallerOfTheHunt extends CardImpl { if (mageObject != null && effect.apply(game, ability)) { FilterPermanent filter = new FilterPermanent(); - filter.add(new ChosenSubtypePredicate(mageObject.getId())); + filter.add(new ChosenSubtypePredicate()); ContinuousEffect effectPower = new SetPowerSourceEffect(new PermanentsOnBattlefieldCount(filter), Duration.Custom); ContinuousEffect effectToughness = new SetToughnessSourceEffect(new PermanentsOnBattlefieldCount(filter), Duration.Custom); game.addEffect(effectPower, ability); diff --git a/Mage.Sets/src/mage/cards/h/HeraldsHorn.java b/Mage.Sets/src/mage/cards/h/HeraldsHorn.java index 7172601b325..1dfbd2b6ec3 100644 --- a/Mage.Sets/src/mage/cards/h/HeraldsHorn.java +++ b/Mage.Sets/src/mage/cards/h/HeraldsHorn.java @@ -79,7 +79,7 @@ class HeraldsHornEffect extends OneShotEffect { // If it's a creature card of the chosen type, you may reveal it and put it into your hand. FilterCreatureCard filter = new FilterCreatureCard("creature card of the chosen type"); - filter.add(new ChosenSubtypePredicate(source.getSourceId())); + filter.add(new ChosenSubtypePredicate()); String message = "Reveal the top card of your library and put that card into your hand?"; if (card != null) { if (filter.match(card, game) && controller.chooseUse(Outcome.Benefit, message, source, game)) { diff --git a/Mage.Sets/src/mage/cards/k/KindredBoon.java b/Mage.Sets/src/mage/cards/k/KindredBoon.java index a61037e021e..979ade1ccf8 100644 --- a/Mage.Sets/src/mage/cards/k/KindredBoon.java +++ b/Mage.Sets/src/mage/cards/k/KindredBoon.java @@ -42,7 +42,7 @@ public final class KindredBoon extends CardImpl { // {1}{W}: Put a divinity counter on target creature you control of the chosen type. FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature you control of the chosen type"); - filter.add(new ChosenSubtypePredicate(this.getId())); + filter.add(new ChosenSubtypePredicate()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.DIVINITY.createInstance()), new ManaCostsImpl("{1}{W}")); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/k/KindredDiscovery.java b/Mage.Sets/src/mage/cards/k/KindredDiscovery.java index 34ddc649653..9dc8464b32d 100644 --- a/Mage.Sets/src/mage/cards/k/KindredDiscovery.java +++ b/Mage.Sets/src/mage/cards/k/KindredDiscovery.java @@ -27,7 +27,7 @@ public final class KindredDiscovery extends CardImpl { // Whenever a creature you control of the chosen type enters the battlefield or attacks, draw a card. FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a creature you control of the chosen type"); - filter.add(new ChosenSubtypePredicate(this.getId())); + filter.add(new ChosenSubtypePredicate()); this.addAbility(new EntersBattlefieldOrAttacksAllTriggeredAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), filter, false)); } diff --git a/Mage.Sets/src/mage/cards/m/MirrorOfTheForebears.java b/Mage.Sets/src/mage/cards/m/MirrorOfTheForebears.java index 165770358e9..737385b8fef 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorOfTheForebears.java +++ b/Mage.Sets/src/mage/cards/m/MirrorOfTheForebears.java @@ -38,7 +38,7 @@ public final class MirrorOfTheForebears extends CardImpl { // 1: Until end of turn, Mirror of the Forebears becomes a copy of target creature you control of the chosen type, except it's an artifact in addition to its other types. FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - filter.add(new ChosenSubtypePredicate(this.getId())); + filter.add(new ChosenSubtypePredicate()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MirrorOfTheForebearsCopyEffect(), new ManaCostsImpl("{1}")); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/TravelersCloak.java b/Mage.Sets/src/mage/cards/t/TravelersCloak.java index 02f4ef13dcc..9145af115df 100644 --- a/Mage.Sets/src/mage/cards/t/TravelersCloak.java +++ b/Mage.Sets/src/mage/cards/t/TravelersCloak.java @@ -50,7 +50,7 @@ public final class TravelersCloak extends CardImpl { // Enchanted creature has landwalk of the chosen type. FilterLandPermanent filter = new FilterLandPermanent("Landwalk of the chosen type"); - filter.add(new ChosenSubtypePredicate(this.getId())); + filter.add(new ChosenSubtypePredicate()); Ability landwalkAbility = new LandwalkAbility(filter); Effect effect = new GainAbilityAttachedEffect(landwalkAbility, AttachmentType.AURA); effect.setText("Enchanted creature has landwalk of the chosen type"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java index 4f3e24dc01f..1cb16170ab4 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CleverImpersonatorTest.java @@ -191,4 +191,34 @@ public class CleverImpersonatorTest extends CardTestPlayerBase { assertType(dReflection, CardType.ENCHANTMENT, true); } + @Test + public void testKindredDiscovery() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.HAND, playerA, "Kindred Discovery"); + + + addCard(Zone.BATTLEFIELD, playerB, "Island", 5); + // Skip your draw step. + addCard(Zone.BATTLEFIELD, playerB, "Dragon Appeasement"); + addCard(Zone.HAND, playerB, "Clever Impersonator"); + addCard(Zone.HAND, playerB, "Ornithopter", 2); + addCard(Zone.HAND, playerB, "Memnite"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Kindred Discovery"); + setChoice(playerA, "Construct"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Clever Impersonator"); + setChoice(playerB, "Kindred Discovery"); + setChoice(playerB, "Thopter"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Ornithopter"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Ornithopter"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Memnite"); + + setStopAt(2, PhaseStep.END_COMBAT); + execute(); + + assertHandCount(playerB, 2); + } + } diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/ChosenSubtypePredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/ChosenSubtypePredicate.java index dd122607790..21a8c11bf8b 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/ChosenSubtypePredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/ChosenSubtypePredicate.java @@ -1,29 +1,26 @@ package mage.filter.predicate.mageobject; -import java.util.UUID; import mage.MageObject; import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.constants.SubType; -import mage.filter.predicate.Predicate; +import mage.filter.predicate.ObjectPlayerPredicate; +import mage.filter.predicate.ObjectSourcePlayer; import mage.game.Game; /** * * @author LoneFox */ -public class ChosenSubtypePredicate implements Predicate { +public class ChosenSubtypePredicate implements ObjectPlayerPredicate> { - private final UUID cardID; - - public ChosenSubtypePredicate(UUID cardID) { - this.cardID = cardID; + public ChosenSubtypePredicate() { } @Override - public boolean apply(MageObject input, Game game) { - SubType subType = ChooseCreatureTypeEffect.getChoosenCreatureType(cardID, game); - return input.hasSubtype(subType, game); + public boolean apply(ObjectSourcePlayer input, Game game) { + SubType subType = ChooseCreatureTypeEffect.getChoosenCreatureType(input.getSourceId(), game); + return input.getObject().hasSubtype(subType, game); } @Override From e5c1dfc4b7fe5cbf54f415fbbd25a7e8d7842258 Mon Sep 17 00:00:00 2001 From: Samuel Sandeen Date: Sun, 29 Jul 2018 08:16:07 -0400 Subject: [PATCH 67/71] Refactor ControlledCreaturesDealCombatDamagePlayerTriggeredAbility. (#5163) It now triggers once for each player damaged. Fixes https://github.com/magefree/mage/issues/5162 --- Mage.Sets/src/mage/cards/n/NaturesWill.java | 54 +++------------ Mage.Sets/src/mage/cards/s/StormTheVault.java | 7 ++ .../abilities/other/NaturesWillTest.java | 67 +++++++++++++++++++ .../abilities/other/StormTheVaultTest.java | 59 ++++++++++++++++ ...ealCombatDamagePlayerTriggeredAbility.java | 37 +++++----- 5 files changed, 160 insertions(+), 64 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/NaturesWillTest.java create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/StormTheVaultTest.java diff --git a/Mage.Sets/src/mage/cards/n/NaturesWill.java b/Mage.Sets/src/mage/cards/n/NaturesWill.java index f96bc4b0065..4c771bf5fee 100644 --- a/Mage.Sets/src/mage/cards/n/NaturesWill.java +++ b/Mage.Sets/src/mage/cards/n/NaturesWill.java @@ -1,20 +1,18 @@ package mage.cards.n; -import java.util.HashSet; -import java.util.List; -import java.util.Set; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.TapAllTargetPlayerControlsEffect; +import mage.abilities.effects.common.UntapAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.common.FilterLandPermanent; /** * @@ -26,7 +24,11 @@ public final class NaturesWill extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}"); // Whenever one or more creatures you control deal combat damage to a player, tap all lands that player controls and untap all lands you control. - this.addAbility(new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(new NaturesWillEffect())); + Effect tapAllEffect = new TapAllTargetPlayerControlsEffect(new FilterLandPermanent()); + tapAllEffect.setText("tap all lands that player controls"); + Ability ability = new ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone.BATTLEFIELD, tapAllEffect, true); + ability.addEffect(new UntapAllEffect(new FilterControlledLandPermanent())); + addAbility(ability); } public NaturesWill(final NaturesWill card) { @@ -38,37 +40,3 @@ public final class NaturesWill extends CardImpl { return new NaturesWill(this); } } - -class NaturesWillEffect extends OneShotEffect { - - public NaturesWillEffect() { - super(Outcome.Benefit); - this.staticText = "tap all lands that player controls and untap all lands you control"; - } - - public NaturesWillEffect(final NaturesWillEffect effect) { - super(effect); - } - - @Override - public NaturesWillEffect copy() { - return new NaturesWillEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Set damagedPlayers = (HashSet) this.getValue("damagedPlayers"); - if (damagedPlayers != null) { - List lands = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source.getSourceId(), game); - for (Permanent land : lands) { - if (damagedPlayers.contains(land.getControllerId())) { - land.tap(game); - } else if (land.isControlledBy(source.getControllerId())) { - land.untap(game); - } - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/s/StormTheVault.java b/Mage.Sets/src/mage/cards/s/StormTheVault.java index 41e3e483241..968f3b72d52 100644 --- a/Mage.Sets/src/mage/cards/s/StormTheVault.java +++ b/Mage.Sets/src/mage/cards/s/StormTheVault.java @@ -2,10 +2,14 @@ package mage.cards.s; import java.util.UUID; + +import mage.abilities.Ability; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.ControlledCreaturesDealCombatDamagePlayerTriggeredAbility; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.TransformAbility; @@ -17,6 +21,7 @@ import mage.constants.ComparisonType; import mage.constants.SuperType; import mage.constants.TargetController; import mage.filter.StaticFilters; +import mage.game.Game; import mage.game.permanent.token.TreasureToken; /** @@ -45,6 +50,8 @@ public final class StormTheVault extends CardImpl { } + + public StormTheVault(final StormTheVault card) { super(card); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/NaturesWillTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/NaturesWillTest.java new file mode 100644 index 00000000000..2c8d49e50ae --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/NaturesWillTest.java @@ -0,0 +1,67 @@ +package org.mage.test.cards.abilities.other; + +import mage.constants.MultiplayerAttackOption; +import mage.constants.PhaseStep; +import mage.constants.RangeOfInfluence; +import mage.constants.Zone; +import mage.game.FreeForAll; +import mage.game.Game; +import mage.game.GameException; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +import java.io.FileNotFoundException; + +public class NaturesWillTest extends CardTestPlayerBase { + @Override + protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 20); + playerA = createPlayer(game, playerA, "PlayerA"); + playerB = createPlayer(game, playerB, "PlayerB"); + playerC = createPlayer(game, playerC, "PlayerC"); + return game; + } + + + @Test + public void testAttackMultiplePlayers() { + addCard(Zone.HAND, playerA, "Nature's Will"); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); + addCard(Zone.BATTLEFIELD, playerA, "Suntail Hawk"); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 4); + addCard(Zone.BATTLEFIELD, playerC, "Island", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nature's Will"); + attack(1, playerA, "Grizzly Bears", playerB); + attack(1, playerA, "Suntail Hawk", playerC); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertTappedCount("Forest", false, 4); + assertTappedCount("Mountain", true, 4); + assertTappedCount("Island", true, 4); + } + + @Test + public void testAttackOnePlayer() { + addCard(Zone.HAND, playerA, "Nature's Will"); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 4); + addCard(Zone.BATTLEFIELD, playerC, "Island", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nature's Will"); + attack(1, playerA, "Grizzly Bears", playerB); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertTappedCount("Forest", false, 4); + assertTappedCount("Mountain", true, 4); + assertTappedCount("Island", false, 4); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/StormTheVaultTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/StormTheVaultTest.java new file mode 100644 index 00000000000..75f279af428 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/StormTheVaultTest.java @@ -0,0 +1,59 @@ +package org.mage.test.cards.abilities.other; + +import mage.constants.MultiplayerAttackOption; +import mage.constants.PhaseStep; +import mage.constants.RangeOfInfluence; +import mage.constants.Zone; +import mage.game.FreeForAll; +import mage.game.Game; +import mage.game.GameException; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +import java.io.FileNotFoundException; + +public class StormTheVaultTest extends CardTestPlayerBase { + @Override + protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 20); + playerA = createPlayer(game, playerA, "PlayerA"); + playerB = createPlayer(game, playerB, "PlayerB"); + playerC = createPlayer(game, playerC, "PlayerC"); + return game; + } + + + @Test + public void testAttackMultiplePlayers() { + addCard(Zone.BATTLEFIELD, playerA, "Storm the Vault"); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); + addCard(Zone.BATTLEFIELD, playerA, "Nessian Courser"); + addCard(Zone.BATTLEFIELD, playerA, "Suntail Hawk"); + addCard(Zone.BATTLEFIELD, playerA, "Lantern Kami"); + + attack(1, playerA, "Grizzly Bears", playerB); + attack(1, playerA, "Nessian Courser", playerB); + attack(1, playerA, "Suntail Hawk", playerC); + attack(1, playerA, "Lantern Kami", playerC); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Treasure", 2); + } + + @Test + public void testAttackOnePlayer() { + addCard(Zone.BATTLEFIELD, playerA, "Storm the Vault"); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); + addCard(Zone.BATTLEFIELD, playerA, "Suntail Hawk"); + + attack(1, playerA, "Grizzly Bears", playerB); + attack(1, playerA, "Suntail Hawk", playerB); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Treasure", 1); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/ControlledCreaturesDealCombatDamagePlayerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/ControlledCreaturesDealCombatDamagePlayerTriggeredAbility.java index 71c0d50bde7..9aa3611a459 100644 --- a/Mage/src/main/java/mage/abilities/common/ControlledCreaturesDealCombatDamagePlayerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/ControlledCreaturesDealCombatDamagePlayerTriggeredAbility.java @@ -4,6 +4,7 @@ package mage.abilities.common; import java.util.HashSet; import java.util.Set; import java.util.UUID; + import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.constants.Zone; @@ -11,8 +12,8 @@ import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; /** * @@ -20,22 +21,25 @@ import mage.game.permanent.Permanent; */ public class ControlledCreaturesDealCombatDamagePlayerTriggeredAbility extends TriggeredAbilityImpl { - private boolean madeDamage = false; private Set damagedPlayerIds = new HashSet<>(); + private boolean setTargetPointer; public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Effect effect) { this(Zone.BATTLEFIELD, effect); } public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone zone, Effect effect) { + this(zone, effect, false); + } + + public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(Zone zone, Effect effect, boolean setTargetPointer) { super(zone, effect, false); + this.setTargetPointer = setTargetPointer; } public ControlledCreaturesDealCombatDamagePlayerTriggeredAbility(final ControlledCreaturesDealCombatDamagePlayerTriggeredAbility ability) { super(ability); - this.madeDamage = ability.madeDamage; this.damagedPlayerIds = new HashSet<>(); - this.damagedPlayerIds.addAll(ability.damagedPlayerIds); } @Override @@ -55,28 +59,19 @@ public class ControlledCreaturesDealCombatDamagePlayerTriggeredAbility extends T if (event.getType() == EventType.DAMAGED_PLAYER) { DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; Permanent p = game.getPermanent(event.getSourceId()); - if (damageEvent.isCombatDamage() && p != null && p.isControlledBy(this.getControllerId())) { - madeDamage = true; + if (damageEvent.isCombatDamage() && p != null && p.isControlledBy(this.getControllerId()) && !damagedPlayerIds.contains(event.getPlayerId())) { damagedPlayerIds.add(event.getPlayerId()); - } - } - if (event.getType() == EventType.COMBAT_DAMAGE_STEP_PRIORITY) { - if (madeDamage) { - Set damagedPlayersCopy = new HashSet<>(); - damagedPlayersCopy.addAll(damagedPlayerIds); - for (Effect effect : this.getEffects()) { - effect.setValue("damagedPlayers", damagedPlayersCopy); + if (setTargetPointer) { + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getPlayerId())); + } } - damagedPlayerIds.clear(); - madeDamage = false; return true; } } - if (event.getType() == EventType.ZONE_CHANGE && event.getTargetId().equals(getSourceId())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.GRAVEYARD) { - damagedPlayerIds.clear(); - } + if (event.getType() == EventType.COMBAT_DAMAGE_STEP_PRIORITY || + (event.getType() == EventType.ZONE_CHANGE && event.getTargetId().equals(getSourceId()))) { + damagedPlayerIds.clear(); } return false; } From 43b91a1511721cedcb4c5badbdbe69a0d6ed88bc Mon Sep 17 00:00:00 2001 From: spjspj Date: Sun, 29 Jul 2018 23:24:57 +1000 Subject: [PATCH 68/71] Implement 1 card C18 --- .../src/mage/cards/p/PrimordialMist.java | 146 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 147 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/p/PrimordialMist.java diff --git a/Mage.Sets/src/mage/cards/p/PrimordialMist.java b/Mage.Sets/src/mage/cards/p/PrimordialMist.java new file mode 100644 index 00000000000..ee917e9486e --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PrimordialMist.java @@ -0,0 +1,146 @@ +package mage.cards.p; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.keyword.ManifestEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.other.FaceDownPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author spjspj + */ +public final class PrimordialMist extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("face down permanent"); + + static { + filter.add(new FaceDownPredicate()); + } + + public PrimordialMist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}"); + + // At the beginning of your end step, you may manifest the top card of your library. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new ManifestEffect(1), TargetController.YOU, true)); + + // Exile a face-down permanent you control face-up: You may play that card this turn + TargetPermanent target = new TargetPermanent(filter); + target.setNotTarget(true); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new PrimordialMistCastFromExileEffect(), + new PrimordialMistCost(target)); + this.addAbility(ability); + } + + public PrimordialMist(final PrimordialMist card) { + super(card); + } + + @Override + public PrimordialMist copy() { + return new PrimordialMist(this); + } +} + +class PrimordialMistCost extends CostImpl { + + TargetPermanent target; + + public PrimordialMistCost(TargetPermanent target) { + this.target = target; + this.text = "Exile a face-down permanent you control face-up"; + } + + public PrimordialMistCost(final PrimordialMistCost cost) { + super(cost); + this.target = cost.target.copy(); + } + + @Override + public PrimordialMistCost copy() { + return new PrimordialMistCost(this); + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + return target.canChoose(controllerId, game); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + Player controller = game.getPlayer(controllerId); + if (controller != null) { + if (target.choose(Outcome.Exile, controllerId, sourceId, game)) { + Card card = game.getCard(sourceId); + if (card != null) { + Permanent sourcePermanent = game.getPermanent(sourceId); + if (sourcePermanent != null) { + Permanent targetPermanent = game.getPermanent(target.getFirstTarget()); + Card targetCard = game.getCard(target.getFirstTarget()); + if (targetPermanent != null && targetCard != null) { + String exileName = sourcePermanent.getIdName() + " "; + controller.moveCardsToExile(targetPermanent, ability, game, true, sourceId, exileName); + targetPermanent.setFaceDown(false, game); + ContinuousEffect effect = new PrimordialMistCastFromExileEffect(); + effect.setTargetPointer(new FixedTarget(targetCard.getId(), targetCard.getZoneChangeCounter(game))); + game.addEffect(effect, ability); + this.setPaid(); + } + } + } + this.setPaid(); + return true; + } + } + return false; + } +} + +class PrimordialMistCastFromExileEffect extends AsThoughEffectImpl { + + public PrimordialMistCastFromExileEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); + staticText = "Exile a face-down permanent you control face-up. You may play the card from exile"; + } + + public PrimordialMistCastFromExileEffect(final PrimordialMistCastFromExileEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public PrimordialMistCastFromExileEffect copy() { + return new PrimordialMistCastFromExileEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + return source.isControlledBy(affectedControllerId) + && (game.getCard(getTargetPointer().getFirst(game, source)) != null); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 9928286208d..0f3853251b3 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -71,6 +71,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Phyrexian Delver", 115, Rarity.RARE, mage.cards.p.PhyrexianDelver.class)); cards.add(new SetCardInfo("Portent", 97, Rarity.COMMON, mage.cards.p.Portent.class)); cards.add(new SetCardInfo("Predict", 98, Rarity.UNCOMMON, mage.cards.p.Predict.class)); + cards.add(new SetCardInfo("Primordial Mist", 12, Rarity.RARE, mage.cards.p.PrimordialMist.class)); cards.add(new SetCardInfo("Rampaging Baloths", 158, Rarity.RARE, mage.cards.r.RampagingBaloths.class)); cards.add(new SetCardInfo("Ravenous Slime", 34, Rarity.RARE, mage.cards.r.RavenousSlime.class)); cards.add(new SetCardInfo("Retrofitter Foundry", 57, Rarity.RARE, mage.cards.r.RetrofitterFoundry.class)); From ef38467326aeef177b5f686ad406a53bea224d1d Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Sun, 29 Jul 2018 22:55:28 -0400 Subject: [PATCH 69/71] Implemented Estrid, the Masked --- .../src/mage/cards/e/EstridTheMasked.java | 160 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + .../src/main/java/mage/constants/SubType.java | 1 + .../mage/game/permanent/token/MaskToken.java | 43 +++++ 4 files changed, 205 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EstridTheMasked.java create mode 100644 Mage/src/main/java/mage/game/permanent/token/MaskToken.java diff --git a/Mage.Sets/src/mage/cards/e/EstridTheMasked.java b/Mage.Sets/src/mage/cards/e/EstridTheMasked.java new file mode 100644 index 00000000000..fee3b6e092c --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EstridTheMasked.java @@ -0,0 +1,160 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.CanBeYourCommanderAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; +import mage.abilities.effects.common.UntapAllControllerEffect; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterEnchantmentCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.EnchantedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.MaskToken; +import mage.players.Player; +import mage.target.TargetPermanent; + +/** + * + * @author TheElk801 + */ +public final class EstridTheMasked extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(); + private static final FilterPermanent filter2 = new FilterPermanent("another permanent"); + + static { + filter.add(new EnchantedPredicate()); + filter2.add(new AnotherPredicate()); + } + + public EstridTheMasked(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{G}{W}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ESTRID); + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); + + // +2: Untap each enchanted permanent you control. + this.addAbility(new LoyaltyAbility(new UntapAllControllerEffect( + filter, "untap each enchanted permanent you control" + ), 2)); + + // -1: Create a white Aura enchantment token named Mask attached to another target permanent. The token has enchant permanent and totem armor. + Ability ability = new LoyaltyAbility( + new EstridTheMaskedTokenEffect(), -1 + ); + ability.addTarget(new TargetPermanent(filter2)); + this.addAbility(ability); + + // -7: Put the top seven cards of your library into your graveyard. Return all non-Aura enchantment cards from your graveyard to the battlefield, then do the same for Aura cards. + this.addAbility(new LoyaltyAbility( + new EstridTheMaskedGraveyardEffect(), -7 + )); + + // Estrid, the Masked can be your commander. + this.addAbility(CanBeYourCommanderAbility.getInstance()); + } + + public EstridTheMasked(final EstridTheMasked card) { + super(card); + } + + @Override + public EstridTheMasked copy() { + return new EstridTheMasked(this); + } +} + +class EstridTheMaskedTokenEffect extends OneShotEffect { + + public EstridTheMaskedTokenEffect() { + super(Outcome.Benefit); + this.staticText = "create a white Aura enchantment token named Mask " + + "attached to another target permanent. " + + "The token has enchant permanent and totem armor"; + } + + public EstridTheMaskedTokenEffect(final EstridTheMaskedTokenEffect effect) { + super(effect); + } + + @Override + public EstridTheMaskedTokenEffect copy() { + return new EstridTheMaskedTokenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + CreateTokenEffect effect = new CreateTokenEffect(new MaskToken()); + effect.apply(game, source); + for (UUID tokenId : effect.getLastAddedTokenIds()) { + Permanent token = game.getPermanent(tokenId); + if (token == null) { + continue; + } + token.attachTo(source.getFirstTarget(), game); + } + return true; + } +} + +class EstridTheMaskedGraveyardEffect extends OneShotEffect { + + private static final FilterEnchantmentCard filter + = new FilterEnchantmentCard(); + private static final FilterEnchantmentCard filter2 + = new FilterEnchantmentCard(); + + static { + filter.add(Predicates.not(new SubtypePredicate(SubType.AURA))); + filter.add(new SubtypePredicate(SubType.AURA)); + } + + public EstridTheMaskedGraveyardEffect() { + super(Outcome.PutCardInPlay); + this.staticText = "put the top seven cards of your library " + + "into your graveyard. Return all non-Aura enchantment cards " + + "from your graveyard to the battlefield, " + + "then do the same for Aura cards"; + } + + public EstridTheMaskedGraveyardEffect(final EstridTheMaskedGraveyardEffect effect) { + super(effect); + } + + @Override + public EstridTheMaskedGraveyardEffect copy() { + return new EstridTheMaskedGraveyardEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + new PutTopCardOfLibraryIntoGraveControllerEffect(7).apply(game, source); + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + controller.moveCards(controller.getGraveyard().getCards( + filter, source.getSourceId(), source.getControllerId(), game + ), Zone.BATTLEFIELD, source, game); + controller.moveCards(controller.getGraveyard().getCards( + filter2, source.getSourceId(), source.getControllerId(), game + ), Zone.BATTLEFIELD, source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 463e666766c..2f7998b98c7 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -107,6 +107,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Epic Proportions", 142, Rarity.RARE, mage.cards.e.EpicProportions.class)); cards.add(new SetCardInfo("Esper Charm", 179, Rarity.UNCOMMON, mage.cards.e.EsperCharm.class)); cards.add(new SetCardInfo("Estrid's Invocation", 8, Rarity.RARE, mage.cards.e.EstridsInvocation.class)); + cards.add(new SetCardInfo("Estrid, the Masked", 40, Rarity.MYTHIC, mage.cards.e.EstridTheMasked.class)); cards.add(new SetCardInfo("Etherium Sculptor", 90, Rarity.COMMON, mage.cards.e.EtheriumSculptor.class)); cards.add(new SetCardInfo("Ever-Watching Threshold", 9, Rarity.RARE, mage.cards.e.EverWatchingThreshold.class)); cards.add(new SetCardInfo("Evolving Wilds", 245, Rarity.COMMON, mage.cards.e.EvolvingWilds.class)); diff --git a/Mage/src/main/java/mage/constants/SubType.java b/Mage/src/main/java/mage/constants/SubType.java index 49ca306dd6b..745320babd8 100644 --- a/Mage/src/main/java/mage/constants/SubType.java +++ b/Mage/src/main/java/mage/constants/SubType.java @@ -375,6 +375,7 @@ public enum SubType { DOOKU("Dooku", SubTypeSet.PlaneswalkerType, true), // Star Wars DOVIN("Dovin", SubTypeSet.PlaneswalkerType), ELSPETH("Elspeth", SubTypeSet.PlaneswalkerType), + ESTRID("Estrid", SubTypeSet.PlaneswalkerType), FREYALISE("Freyalise", SubTypeSet.PlaneswalkerType), GARRUK("Garruk", SubTypeSet.PlaneswalkerType), GIDEON("Gideon", SubTypeSet.PlaneswalkerType), diff --git a/Mage/src/main/java/mage/game/permanent/token/MaskToken.java b/Mage/src/main/java/mage/game/permanent/token/MaskToken.java new file mode 100644 index 00000000000..e133169b7ec --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/MaskToken.java @@ -0,0 +1,43 @@ +package mage.game.permanent.token; + +import mage.constants.CardType; +import mage.constants.SubType; +import mage.abilities.Ability; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.TotemArmorAbility; +import mage.constants.Outcome; +import mage.target.TargetPermanent; + +/** + * + * @author TheElk801 + */ +public final class MaskToken extends TokenImpl { + + public MaskToken() { + super( + "Mask", "white Aura enchantment token named Mask " + + "attached to another target permanent. " + + "The token has enchant permanent and totem armor." + ); + cardType.add(CardType.ENCHANTMENT); + color.setWhite(true); + subtype.add(SubType.AURA); + + TargetPermanent auraTarget = new TargetPermanent(); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + ability.addEffect(new AttachEffect(Outcome.BoostCreature)); + this.addAbility(ability); + + this.addAbility(new TotemArmorAbility()); + } + + public MaskToken(final MaskToken token) { + super(token); + } + + public MaskToken copy() { + return new MaskToken(this); + } +} From 251e0443df564cd300514f0ce0deb0f6647eabd6 Mon Sep 17 00:00:00 2001 From: spjspj Date: Mon, 30 Jul 2018 23:27:03 +1000 Subject: [PATCH 70/71] Treasure Nabber (C18) "All takesies, no givesies" --- .../src/mage/cards/t/TreasureNabber.java | 146 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + 2 files changed, 147 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/t/TreasureNabber.java diff --git a/Mage.Sets/src/mage/cards/t/TreasureNabber.java b/Mage.Sets/src/mage/cards/t/TreasureNabber.java new file mode 100644 index 00000000000..9a62b20545d --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TreasureNabber.java @@ -0,0 +1,146 @@ +package mage.cards.t; + +import java.util.List; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.ContinuousEffectImpl; +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.PhaseStep; +import mage.constants.SubLayer; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; +import mage.target.targetpointer.FixedTargets; + +/** + * + * @author spjspj + */ +public final class TreasureNabber extends CardImpl { + + public TreasureNabber(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever an opponent taps an artifact for mana, gain control of that artifact until the end of your next turn. + this.addAbility(new TreasureNabberAbility()); + } + + public TreasureNabber(final TreasureNabber card) { + super(card); + } + + @Override + public TreasureNabber copy() { + return new TreasureNabber(this); + } +} + +class TreasureNabberAbility extends TriggeredAbilityImpl { + + public TreasureNabberAbility() { + super(Zone.BATTLEFIELD, new TreasureNabberEffect()); + } + + public TreasureNabberAbility(TreasureNabberAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.TAPPED_FOR_MANA; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (game.getOpponents(controllerId).contains(event.getPlayerId())) { + Permanent permanent = game.getPermanent(event.getSourceId()); + if (permanent != null && permanent.isArtifact()) { + getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getId())); + return true; + } + } + return false; + } + + @Override + public TreasureNabberAbility copy() { + return new TreasureNabberAbility(this); + } + + @Override + public String getRule() { + return "Whenever an opponent taps an artifact for mana, gain control of that artifact until the end of your next turn"; + } +} + +class TreasureNabberEffect extends ContinuousEffectImpl { + + protected FixedTargets fixedTargets; + protected int startingTurn; + + TreasureNabberEffect() { + super(Duration.Custom, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); + this.staticText = "gain control of that artifact until the end of your next turn"; + startingTurn = 0; + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + startingTurn = game.getTurnNum(); + if (game.getPhase().getStep().getType() == PhaseStep.END_TURN) { + startingTurn = game.getTurnNum() + 1; + } + } + + TreasureNabberEffect(final TreasureNabberEffect effect) { + super(effect); + this.fixedTargets = effect.fixedTargets; + } + + @Override + public TreasureNabberEffect copy() { + return new TreasureNabberEffect(this); + } + + @Override + public boolean isInactive(Ability source, Game game) { + if (startingTurn != 0 && game.getTurnNum() >= startingTurn && game.getPhase().getStep().getType() == PhaseStep.END_TURN) { + if (game.isActivePlayer(source.getControllerId())) { + return true; + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + + if (permanent != null) { + permanent.changeControllerId(source.getControllerId(), game); + return true; + } + return false; + } + + public void setTargets(List targetedPermanents, Game game) { + this.fixedTargets = new FixedTargets(targetedPermanents, game); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 2f7998b98c7..98b2701e391 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -293,6 +293,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Tranquil Expanse", 289, Rarity.UNCOMMON, mage.cards.t.TranquilExpanse.class)); cards.add(new SetCardInfo("Tranquil Thicket", 290, Rarity.COMMON, mage.cards.t.TranquilThicket.class)); cards.add(new SetCardInfo("Treasure Hunt", 109, Rarity.COMMON, mage.cards.t.TreasureHunt.class)); + cards.add(new SetCardInfo("Treasure Nabber", 27, Rarity.RARE, mage.cards.t.TreasureNabber.class)); cards.add(new SetCardInfo("Turntimber Sower", 35, Rarity.RARE, mage.cards.t.TurntimberSower.class)); cards.add(new SetCardInfo("Tuvasa the Sunlit", 47, Rarity.MYTHIC, mage.cards.t.TuvasaTheSunlit.class)); cards.add(new SetCardInfo("Unflinching Courage", 192, Rarity.UNCOMMON, mage.cards.u.UnflinchingCourage.class)); From 0fa4c2d3246c01a5cc950744d72d44244c984ea5 Mon Sep 17 00:00:00 2001 From: Colin Redman Date: Wed, 1 Aug 2018 05:33:51 -0600 Subject: [PATCH 71/71] Implemented Aminatou, the Fateshifter --- .../mage/cards/a/AminatouTheFateShifter.java | 183 ++++++++++++++++++ Mage.Sets/src/mage/sets/Commander2018.java | 1 + .../src/main/java/mage/constants/SubType.java | 7 +- 3 files changed, 187 insertions(+), 4 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/a/AminatouTheFateShifter.java diff --git a/Mage.Sets/src/mage/cards/a/AminatouTheFateShifter.java b/Mage.Sets/src/mage/cards/a/AminatouTheFateShifter.java new file mode 100644 index 00000000000..64533667f53 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AminatouTheFateShifter.java @@ -0,0 +1,183 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlanswalkerEntersWithLoyalityCountersAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.Choice; +import mage.choices.ChoiceLeftOrRight; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.other.OwnerPredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.players.PlayerList; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInHand; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +public class AminatouTheFateShifter extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("permanent you own"); + + static { + filter.add(new OwnerPredicate(TargetController.YOU)); + filter.add(new AnotherPredicate()); + } + + public AminatouTheFateShifter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.PLANESWALKER},"{W}{U}{B}"); + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.AMINATOU); + + this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility(3)); + + // +1: Draw a card, then put a card from your hand on top of your library. + Ability ability = new LoyaltyAbility(new AminatouPlusEffect(), +1); + this.addAbility(ability); + + // -1: Exile another target permanent you own, then return it to the battlefield under your control. + ability = new LoyaltyAbility(new ExileTargetForSourceEffect(), -1); + ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // -6: Choose left or right. Each player gains control of all nonland permanents other than Aminatou, the + // Fateshifter controlled by the next player in the chosen direction. + ability = new LoyaltyAbility(new AminatouUltimateEffect(), -6); + this.addAbility(ability); + } + public AminatouTheFateShifter(final AminatouTheFateShifter card) { + super(card); + } + + @Override + public AminatouTheFateShifter copy() { + return new AminatouTheFateShifter(this); + } +} + +class AminatouPlusEffect extends OneShotEffect { + public AminatouPlusEffect() { + super(Outcome.DrawCard); + staticText = "draw a card, then put a card from your hand on top of your library"; + } + + public AminatouPlusEffect(final AminatouPlusEffect effect) { + super(effect); + } + + @Override + public AminatouPlusEffect copy() { + return new AminatouPlusEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.drawCards(1, game); + putOnLibrary(player, source, game); + return true; + } + return false; + } + + private boolean putOnLibrary(Player player, Ability source, Game game) { + TargetCardInHand target = new TargetCardInHand(); + if (target.canChoose(source.getSourceId(), player.getId(), game)) { + player.chooseTarget(Outcome.ReturnToHand, target, source, game); + Card card = player.getHand().get(target.getFirstTarget(), game); + if (card != null) { + return player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, true, false); + } + } + return false; + } +} + +class AminatouUltimateEffect extends OneShotEffect { + public AminatouUltimateEffect (){ + super(Outcome.Benefit); + staticText = "Choose left or right. Each player gains control of all nonland permanents other than Aminatou," + + " the Fateshifter controlled by the next player in the chosen direction."; + } + + public AminatouUltimateEffect(final AminatouUltimateEffect effect) { + super(effect); + } + + @Override + public AminatouUltimateEffect copy(){return new AminatouUltimateEffect(this);} + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Choice choice = new ChoiceLeftOrRight(); + if (!controller.choose(Outcome.Neutral, choice, game)) { + return false; + } + boolean left = choice.getChoice().equals("Left"); + PlayerList playerList = game.getState().getPlayerList().copy(); + // set playerlist to controller + while (!playerList.get().equals(source.getControllerId())) { + playerList.getNext(); + } + UUID currentPlayer = playerList.get(); + UUID nextPlayer; + UUID firstNextPlayer = null; + while (!getNextPlayerInDirection(left, playerList, game).equals(firstNextPlayer)) { + nextPlayer = playerList.get(); + if (nextPlayer == null) { + return false; + } + // skip players out of range + if (!game.getState().getPlayersInRange(controller.getId(), game).contains(nextPlayer)){ + continue; + } + // save first next player to check for iteration stop + if (firstNextPlayer == null) { + firstNextPlayer = nextPlayer; + } + FilterNonlandPermanent nextPlayerNonlandPermanentsFilter = new FilterNonlandPermanent(); + nextPlayerNonlandPermanentsFilter.add(new ControllerIdPredicate(nextPlayer)); + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(nextPlayerNonlandPermanentsFilter, game)) { + if (permanent.getId().equals(source.getSourceId())){ + continue; + } + ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfGame, currentPlayer); + effect.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect, source); + } + currentPlayer = nextPlayer; + } + return true; + } + return false; + } + + private UUID getNextPlayerInDirection(boolean left, PlayerList playerList, Game game) { + UUID nextPlayerId; + if (left) { + nextPlayerId = playerList.getNext(); + } else { + nextPlayerId = playerList.getPrevious(); + } + return nextPlayerId; + } +} + diff --git a/Mage.Sets/src/mage/sets/Commander2018.java b/Mage.Sets/src/mage/sets/Commander2018.java index 98b2701e391..7f1aeea8b0b 100644 --- a/Mage.Sets/src/mage/sets/Commander2018.java +++ b/Mage.Sets/src/mage/sets/Commander2018.java @@ -27,6 +27,7 @@ public final class Commander2018 extends ExpansionSet { cards.add(new SetCardInfo("Ajani's Chosen", 61, Rarity.RARE, mage.cards.a.AjanisChosen.class)); cards.add(new SetCardInfo("Akoum Refuge", 231, Rarity.UNCOMMON, mage.cards.a.AkoumRefuge.class)); cards.add(new SetCardInfo("Akroma's Vengeance", 62, Rarity.RARE, mage.cards.a.AkromasVengeance.class)); + cards.add(new SetCardInfo("Amninatou, the Fateshifter", 37, Rarity.MYTHIC, mage.cards.a.AminatouTheFateShifter.class)); cards.add(new SetCardInfo("Ancient Stone Idol", 53, Rarity.RARE, mage.cards.a.AncientStoneIdol.class)); cards.add(new SetCardInfo("Arcane Sanctum", 232, Rarity.UNCOMMON, mage.cards.a.ArcaneSanctum.class)); cards.add(new SetCardInfo("Archetype of Imagination", 81, Rarity.UNCOMMON, mage.cards.a.ArchetypeOfImagination.class)); diff --git a/Mage/src/main/java/mage/constants/SubType.java b/Mage/src/main/java/mage/constants/SubType.java index 745320babd8..22248b501e1 100644 --- a/Mage/src/main/java/mage/constants/SubType.java +++ b/Mage/src/main/java/mage/constants/SubType.java @@ -1,12 +1,12 @@ package mage.constants; +import mage.util.SubTypeList; + import java.util.Arrays; import java.util.EnumSet; import java.util.Set; import java.util.stream.Collectors; -import mage.util.SubTypeList; - public enum SubType { //205.3k Instants and sorceries share their lists of subtypes; these subtypes are called spell types. @@ -363,6 +363,7 @@ public enum SubType { ZUBERA("Zubera", SubTypeSet.CreatureType), // Planeswalker AJANI("Ajani", SubTypeSet.PlaneswalkerType), + AMINATOU("Aminatou", SubTypeSet.PlaneswalkerType), ANGRATH("Angrath", SubTypeSet.PlaneswalkerType), ARLINN("Arlinn", SubTypeSet.PlaneswalkerType), ASHIOK("Ashiok", SubTypeSet.PlaneswalkerType), @@ -458,8 +459,6 @@ public enum SubType { return null; } - ; - public SubTypeSet getSubTypeSet() { return subTypeSet; }