From f568498cb8ef39a83bb7fea3ec4df90a6ebc9477 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 17:28:30 -0500 Subject: [PATCH 01/20] Implemented Elite Arrester --- Mage.Sets/src/mage/cards/e/EliteArrester.java | 47 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 48 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EliteArrester.java diff --git a/Mage.Sets/src/mage/cards/e/EliteArrester.java b/Mage.Sets/src/mage/cards/e/EliteArrester.java new file mode 100644 index 00000000000..570589d44e1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EliteArrester.java @@ -0,0 +1,47 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EliteArrester extends CardImpl { + + public EliteArrester(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // {1}{U}, {T}: Tap target creature. + Ability ability = new SimpleActivatedAbility( + new TapTargetEffect(), new ManaCostsImpl("{1}{U}") + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private EliteArrester(final EliteArrester card) { + super(card); + } + + @Override + public EliteArrester copy() { + return new EliteArrester(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index bae8e85fb28..d27a4d0cb5c 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -79,6 +79,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Dovin, Grand Arbiter", 167, Rarity.MYTHIC, mage.cards.d.DovinGrandArbiter.class)); cards.add(new SetCardInfo("Drill Bit", 73, Rarity.UNCOMMON, mage.cards.d.DrillBit.class)); cards.add(new SetCardInfo("Electrodominance", 99, Rarity.RARE, mage.cards.e.Electrodominance.class)); + cards.add(new SetCardInfo("Elite Arrester", 266, Rarity.COMMON, mage.cards.e.EliteArrester.class)); cards.add(new SetCardInfo("Emergency Powers", 169, Rarity.MYTHIC, mage.cards.e.EmergencyPowers.class)); cards.add(new SetCardInfo("End-Raze Forerunners", 124, Rarity.RARE, mage.cards.e.EndRazeForerunners.class)); cards.add(new SetCardInfo("Essence Capture", 37, Rarity.UNCOMMON, mage.cards.e.EssenceCapture.class)); From ec8250e129383bdad4894775d47b48894a788824 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 17:32:15 -0500 Subject: [PATCH 02/20] Implemented Ragefire --- Mage.Sets/src/mage/cards/r/Ragefire.java | 32 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 33 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/Ragefire.java diff --git a/Mage.Sets/src/mage/cards/r/Ragefire.java b/Mage.Sets/src/mage/cards/r/Ragefire.java new file mode 100644 index 00000000000..4dbe92e7040 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Ragefire.java @@ -0,0 +1,32 @@ +package mage.cards.r; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Ragefire extends CardImpl { + + public Ragefire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); + + // Ragefire deals 3 damage to target creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private Ragefire(final Ragefire card) { + super(card); + } + + @Override + public Ragefire copy() { + return new Ragefire(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index d27a4d0cb5c..d831faf26fb 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -139,6 +139,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Pteramander", 47, Rarity.UNCOMMON, mage.cards.p.Pteramander.class)); cards.add(new SetCardInfo("Quench", 48, Rarity.COMMON, mage.cards.q.Quench.class)); cards.add(new SetCardInfo("Rafter Demon", 196, Rarity.COMMON, mage.cards.r.RafterDemon.class)); + cards.add(new SetCardInfo("Ragefire", 270, Rarity.COMMON, mage.cards.r.Ragefire.class)); cards.add(new SetCardInfo("Rakdos Firewheeler", 197, Rarity.UNCOMMON, mage.cards.r.RakdosFirewheeler.class)); cards.add(new SetCardInfo("Rakdos Guildgate", 255, Rarity.COMMON, mage.cards.r.RakdosGuildgate.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Rakdos Guildgate", 256, Rarity.COMMON, mage.cards.r.RakdosGuildgate.class, NON_FULL_USE_VARIOUS)); From 0acf5eeac46b003091ecd4efaf096717f9b6be1f Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 17:40:03 -0500 Subject: [PATCH 03/20] Implemented Cindervines --- Mage.Sets/src/mage/cards/c/Cindervines.java | 88 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 89 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/Cindervines.java diff --git a/Mage.Sets/src/mage/cards/c/Cindervines.java b/Mage.Sets/src/mage/cards/c/Cindervines.java new file mode 100644 index 00000000000..baff58a2668 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Cindervines.java @@ -0,0 +1,88 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Cindervines extends CardImpl { + + public Cindervines(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}{G}"); + + // Whenever an opponent casts a noncreature spell, Cindervines deals 1 damage to that player. + this.addAbility(new SpellCastOpponentTriggeredAbility( + Zone.BATTLEFIELD, new DamageTargetEffect(1, false, "that player"), + StaticFilters.FILTER_SPELL_NON_CREATURE, false, SetTargetPointer.PLAYER + )); + + // {1}, Sacrifice Cindervines: Destroy target artifact or enchantment. Cindervines deals 2 damage to that permanent's controller. + Ability ability = new SimpleActivatedAbility( + new CindervinesEffect(), new GenericManaCost(1) + ); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + this.addAbility(ability); + } + + private Cindervines(final Cindervines card) { + super(card); + } + + @Override + public Cindervines copy() { + return new Cindervines(this); + } +} + +class CindervinesEffect extends OneShotEffect { + + CindervinesEffect() { + super(Outcome.Benefit); + staticText = "Destroy target artifact or enchantment. " + + "{this} deals 2 damage to that permanent's controller."; + } + + private CindervinesEffect(final CindervinesEffect effect) { + super(effect); + } + + @Override + public CindervinesEffect copy() { + return new CindervinesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + Player player = game.getPlayer(permanent.getControllerId()); + if (player == null) { + return false; + } + permanent.destroy(source.getSourceId(), game, false); + player.damage(2, source.getSourceId(), game); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index d831faf26fb..baa90e2ec18 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -61,6 +61,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Captive Audience", 160, Rarity.MYTHIC, mage.cards.c.CaptiveAudience.class)); cards.add(new SetCardInfo("Carnival // Carnage", 222, Rarity.UNCOMMON, mage.cards.c.CarnivalCarnage.class)); cards.add(new SetCardInfo("Charging War Boar", 271, Rarity.UNCOMMON, mage.cards.c.ChargingWarBoar.class)); + cards.add(new SetCardInfo("Cindervines", 161, Rarity.RARE, mage.cards.c.Cindervines.class)); cards.add(new SetCardInfo("Clan Guildmage", 162, Rarity.UNCOMMON, mage.cards.c.ClanGuildmage.class)); cards.add(new SetCardInfo("Collision // Colossus", 223, Rarity.UNCOMMON, mage.cards.c.CollisionColossus.class)); cards.add(new SetCardInfo("Combine Guildmage", 163, Rarity.UNCOMMON, mage.cards.c.CombineGuildmage.class)); From acf34f9429a89f75e57e345806e8ea56679de489 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 17:59:47 -0500 Subject: [PATCH 04/20] Implemented Plaza of Harmony --- .../src/mage/cards/p/PlazaOfHarmony.java | 62 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + .../mana/AnyColorLandsProduceManaAbility.java | 27 +++++--- 3 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/p/PlazaOfHarmony.java diff --git a/Mage.Sets/src/mage/cards/p/PlazaOfHarmony.java b/Mage.Sets/src/mage/cards/p/PlazaOfHarmony.java new file mode 100644 index 00000000000..d88d7c09816 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PlazaOfHarmony.java @@ -0,0 +1,62 @@ +package mage.cards.p; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.mana.AnyColorLandsProduceManaAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PlazaOfHarmony extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + private static final FilterPermanent filter2 = new FilterPermanent(SubType.GATE, "Gate"); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + + public PlazaOfHarmony(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // When Plaza of Harmony enters the battlefield, if you control two or more Gates, you gain 3 life. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3)), + condition, "When {this} enters the battlefield, " + + "if you control two or more Gates, you gain 3 life." + )); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Add one mana of any type a Gate you control could produce. + this.addAbility(new AnyColorLandsProduceManaAbility(TargetController.YOU, false, filter2)); + } + + private PlazaOfHarmony(final PlazaOfHarmony card) { + super(card); + } + + @Override + public PlazaOfHarmony copy() { + return new PlazaOfHarmony(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index baa90e2ec18..1560f22c166 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -134,6 +134,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Persistent Petitioners", 44, Rarity.COMMON, mage.cards.p.PersistentPetitioners.class)); cards.add(new SetCardInfo("Pestilent Spirit", 81, Rarity.RARE, mage.cards.p.PestilentSpirit.class)); cards.add(new SetCardInfo("Pitiless Pontiff", 194, Rarity.UNCOMMON, mage.cards.p.PitilessPontiff.class)); + cards.add(new SetCardInfo("Plaza of Harmony", 254, Rarity.RARE, mage.cards.p.PlazaOfHarmony.class)); cards.add(new SetCardInfo("Precognitive Perception", 45, Rarity.RARE, mage.cards.p.PrecognitivePerception.class)); cards.add(new SetCardInfo("Priest of Forgotten Gods", 83, Rarity.RARE, mage.cards.p.PriestOfForgottenGods.class)); cards.add(new SetCardInfo("Prime Speaker Vannifar", 195, Rarity.MYTHIC, mage.cards.p.PrimeSpeakerVannifar.class)); diff --git a/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java b/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java index 086a90ff431..288e48b1952 100644 --- a/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java @@ -1,8 +1,6 @@ package mage.abilities.mana; -import java.util.ArrayList; -import java.util.List; import mage.Mana; import mage.abilities.Abilities; import mage.abilities.Ability; @@ -20,8 +18,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.ArrayList; +import java.util.List; + /** - * * @author LevelX2 */ public class AnyColorLandsProduceManaAbility extends ActivatedManaAbilityImpl { @@ -31,7 +31,11 @@ public class AnyColorLandsProduceManaAbility extends ActivatedManaAbilityImpl { } public AnyColorLandsProduceManaAbility(TargetController targetController, boolean onlyColors) { - super(Zone.BATTLEFIELD, new AnyColorLandsProduceManaEffect(targetController, onlyColors), new TapSourceCost()); + this(targetController, onlyColors, null); + } + + public AnyColorLandsProduceManaAbility(TargetController targetController, boolean onlyColors, FilterPermanent filter) { + super(Zone.BATTLEFIELD, new AnyColorLandsProduceManaEffect(targetController, onlyColors, filter), new TapSourceCost()); } public AnyColorLandsProduceManaAbility(final AnyColorLandsProduceManaAbility ability) { @@ -62,16 +66,21 @@ class AnyColorLandsProduceManaEffect extends ManaEffect { private boolean inManaTypeCalculation = false; - public AnyColorLandsProduceManaEffect(TargetController targetController, boolean onlyColors) { + AnyColorLandsProduceManaEffect(TargetController targetController, boolean onlyColors, FilterPermanent filter) { super(); - filter = new FilterLandPermanent(); + if (filter == null) { + this.filter = new FilterLandPermanent(); + } else { + this.filter = filter.copy(); + } this.onlyColors = onlyColors; - filter.add(new ControllerPredicate(targetController)); + this.filter.add(new ControllerPredicate(targetController)); String text = targetController == TargetController.OPPONENT ? "an opponent controls" : "you control"; - staticText = "Add one mana of any " + (this.onlyColors ? "color" : "type") + " that a land " + text + " could produce"; + staticText = "Add one mana of any " + (this.onlyColors ? "color" : "type") + " that a " + + (filter == null ? "land " : filter.getMessage() + " ") + text + " could produce"; } - public AnyColorLandsProduceManaEffect(final AnyColorLandsProduceManaEffect effect) { + private AnyColorLandsProduceManaEffect(final AnyColorLandsProduceManaEffect effect) { super(effect); this.filter = effect.filter.copy(); this.onlyColors = effect.onlyColors; From 88374751b1fc3b3dfac41a5019f45931b408e738 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 18:08:35 -0500 Subject: [PATCH 05/20] Implemented Forbidding Spirit --- .../src/mage/cards/f/ForbiddingSpirit.java | 47 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + .../CantAttackYouUnlessPayManaAllEffect.java | 3 +- 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/f/ForbiddingSpirit.java diff --git a/Mage.Sets/src/mage/cards/f/ForbiddingSpirit.java b/Mage.Sets/src/mage/cards/f/ForbiddingSpirit.java new file mode 100644 index 00000000000..b96e38211d1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForbiddingSpirit.java @@ -0,0 +1,47 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.common.combat.CantAttackYouUnlessPayManaAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ForbiddingSpirit extends CardImpl { + + public ForbiddingSpirit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + + this.subtype.add(SubType.SPIRIT); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Forbidding Spirit enters the battlefield, until your next turn, creatures can't attack you or a planeswalker you control unless their controller pays {2} for each of those creatures. + ContinuousEffect effect = new CantAttackYouUnlessPayManaAllEffect( + new ManaCostsImpl("{2}"), true + ); + effect.setDuration(Duration.UntilYourNextTurn); + effect.setText("until your next turn, creatures can't attack you or a planeswalker you control " + + "unless their controller pays {2} for each of those creatures."); + this.addAbility(new EntersBattlefieldTriggeredAbility(effect)); + } + + private ForbiddingSpirit(final ForbiddingSpirit card) { + super(card); + } + + @Override + public ForbiddingSpirit copy() { + return new ForbiddingSpirit(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 1560f22c166..a502ae1014b 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -87,6 +87,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Ethereal Absolution", 170, Rarity.RARE, mage.cards.e.EtherealAbsolution.class)); cards.add(new SetCardInfo("Fireblade Artist", 172, Rarity.UNCOMMON, mage.cards.f.FirebladeArtist.class)); cards.add(new SetCardInfo("Font of Agonies", 74, Rarity.RARE, mage.cards.f.FontOfAgonies.class)); + cards.add(new SetCardInfo("Forbidding Spirit", 9, Rarity.UNCOMMON, mage.cards.f.ForbiddingSpirit.class)); cards.add(new SetCardInfo("Frenzied Arynx", 173, Rarity.COMMON, mage.cards.f.FrenziedArynx.class)); cards.add(new SetCardInfo("Frilled Mystic", 174, Rarity.UNCOMMON, mage.cards.f.FrilledMystic.class)); cards.add(new SetCardInfo("Gate Colossus", 232, Rarity.UNCOMMON, mage.cards.g.GateColossus.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java index 0eef90ee664..ca59b004149 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java @@ -12,7 +12,6 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantAttackYouUnlessPayManaAllEffect extends PayCostToAttackBlockEffectImpl { @@ -37,7 +36,7 @@ public class CantAttackYouUnlessPayManaAllEffect extends PayCostToAttackBlockEff + (payAlsoForAttackingPlaneswalker ? "or a planeswalker you control " : "") + "unless their controller pays " + (manaCosts == null ? "" : manaCosts.getText()) - + " for each creature he or she controls that's attacking you"; + + " for each creature they controls that's attacking you"; } public CantAttackYouUnlessPayManaAllEffect(final CantAttackYouUnlessPayManaAllEffect effect) { From 7f1267563b6569b1e149f1c7c53908a03d1d19c1 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 10 Jan 2019 17:10:25 -0600 Subject: [PATCH 06/20] - Fixed #5500. If you note any interactions that I missed testing, do tell. --- Mage.Sets/src/mage/cards/b/BloodMoon.java | 32 +++++-- Mage.Sets/src/mage/cards/c/Conversion.java | 69 ++++++++++---- Mage.Sets/src/mage/cards/g/Glaciers.java | 57 +++++++++--- .../src/mage/cards/i/IllusionaryTerrain.java | 89 +++++++------------ .../src/mage/cards/p/PhantasmalTerrain.java | 3 +- .../LandTypeChangingEffectsTest.java | 19 ++-- 6 files changed, 156 insertions(+), 113 deletions(-) diff --git a/Mage.Sets/src/mage/cards/b/BloodMoon.java b/Mage.Sets/src/mage/cards/b/BloodMoon.java index ca52c9989c7..1eef0357ac4 100644 --- a/Mage.Sets/src/mage/cards/b/BloodMoon.java +++ b/Mage.Sets/src/mage/cards/b/BloodMoon.java @@ -1,11 +1,14 @@ - package mage.cards.b; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; +import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -22,7 +25,7 @@ import mage.game.permanent.Permanent; public final class BloodMoon extends CardImpl { public BloodMoon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); // Nonbasic lands are Mountains. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BloodMoonEffect())); @@ -72,12 +75,28 @@ class BloodMoonEffect extends ContinuousEffectImpl { case TypeChangingEffects_4: // 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects // So the ability removing has to be done before Layer 6 - land.removeAllAbilities(source.getSourceId(), game); - land.getSubtype(game).removeAll(SubType.getLandTypes(false)); + //land.getSubtype(game).removeAll(SubType.getLandTypes(false)); + land.getSubtype(game).clear(); land.getSubtype(game).add(SubType.MOUNTAIN); + land.removeAllAbilities(source.getSourceId(), game); break; case AbilityAddingRemovingEffects_6: - land.addAbility(new RedManaAbility(), source.getSourceId(), game); + land.removeAllAbilities(source.getSourceId(), game); + if (land.getSubtype(game).contains(SubType.FOREST)) { + land.addAbility(new GreenManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.PLAINS)) { + land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.MOUNTAIN)) { + land.addAbility(new RedManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.ISLAND)) { + land.addAbility(new BlueManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.SWAMP)) { + land.addAbility(new BlackManaAbility(), source.getSourceId(), game); + } break; } } @@ -86,6 +105,7 @@ class BloodMoonEffect extends ContinuousEffectImpl { @Override public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; + return layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.TypeChangingEffects_4; } } diff --git a/Mage.Sets/src/mage/cards/c/Conversion.java b/Mage.Sets/src/mage/cards/c/Conversion.java index 24f0ef8d1f5..8731aaba764 100644 --- a/Mage.Sets/src/mage/cards/c/Conversion.java +++ b/Mage.Sets/src/mage/cards/c/Conversion.java @@ -1,4 +1,3 @@ - package mage.cards.c; import java.util.List; @@ -13,11 +12,14 @@ import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -27,13 +29,15 @@ import mage.game.permanent.Permanent; */ public final class Conversion extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent(SubType.MOUNTAIN, "Mountains"); - public Conversion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); // At the beginning of your upkeep, sacrifice Conversion unless you pay {W}{W}. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{W}{W}")), TargetController.YOU, false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new SacrificeSourceUnlessPaysEffect( + new ManaCostsImpl("{W}{W}")), + TargetController.YOU, + false)); // All Mountains are Plains. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConversionEffect())); @@ -72,15 +76,45 @@ public final class Conversion extends CardImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - for (Permanent land : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent land : game.getBattlefield().getAllActivePermanents(CardType.LAND)) { switch (layer) { - case AbilityAddingRemovingEffects_6: - land.removeAllAbilities(source.getSourceId(), game); - land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); - break; case TypeChangingEffects_4: - land.getSubtype(game).clear(); - land.getSubtype(game).add(SubType.PLAINS); + if (land.getSubtype(game).contains(SubType.MOUNTAIN)) { + land.getSubtype(game).clear(); + land.getSubtype(game).add(SubType.PLAINS); + game.getState().setValue("conversion" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game), + "true"); + } + break; + case AbilityAddingRemovingEffects_6: + if (game.getState().getValue("conversion" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game)) != null + && game.getState().getValue("conversion" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game)).equals("true")) { + land.removeAllAbilities(source.getSourceId(), game); + if (land.getSubtype(game).contains(SubType.FOREST)) { + land.addAbility(new GreenManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.PLAINS)) { + land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.MOUNTAIN)) { + land.addAbility(new RedManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.ISLAND)) { + land.addAbility(new BlueManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.SWAMP)) { + land.addAbility(new BlackManaAbility(), source.getSourceId(), game); + } + } break; } } @@ -89,20 +123,17 @@ public final class Conversion extends CardImpl { @Override public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; + return layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.TypeChangingEffects_4; } @Override public Set isDependentTo(List allEffectsInLayer) { - // the dependent classes needs to be an enclosed class for dependent check of continuous effects return allEffectsInLayer .stream() - .filter(effect->effect.getDependencyTypes().contains(DependencyType.BecomeMountain)) + .filter(effect -> effect.getDependencyTypes().contains(DependencyType.BecomePlains)) .map(Effect::getId) .collect(Collectors.toSet()); - } - } - } diff --git a/Mage.Sets/src/mage/cards/g/Glaciers.java b/Mage.Sets/src/mage/cards/g/Glaciers.java index d0c6fa2be8a..6d2ae05de93 100644 --- a/Mage.Sets/src/mage/cards/g/Glaciers.java +++ b/Mage.Sets/src/mage/cards/g/Glaciers.java @@ -12,24 +12,23 @@ import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; - import java.util.List; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; /** * * @author jmharmon */ - public final class Glaciers extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent(SubType.MOUNTAIN, "Mountains"); - public Glaciers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{U}"); @@ -72,15 +71,44 @@ public final class Glaciers extends CardImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - for (Permanent land : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent land : game.getBattlefield().getAllActivePermanents(CardType.LAND)) { switch (layer) { - case AbilityAddingRemovingEffects_6: - land.removeAllAbilities(source.getSourceId(), game); - land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); - break; case TypeChangingEffects_4: - land.getSubtype(game).clear(); - land.getSubtype(game).add(SubType.PLAINS); + if (land.getSubtype(game).contains(SubType.MOUNTAIN)) { + land.getSubtype(game).clear(); + land.getSubtype(game).add(SubType.PLAINS); + game.getState().setValue("glaciers" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game), "true"); + } + break; + case AbilityAddingRemovingEffects_6: + if (game.getState().getValue("glaciers" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game)) != null + && game.getState().getValue("glaciers" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game)).equals("true")) { + land.removeAllAbilities(source.getSourceId(), game); + if (land.getSubtype(game).contains(SubType.FOREST)) { + land.addAbility(new GreenManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.PLAINS)) { + land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.MOUNTAIN)) { + land.addAbility(new RedManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.ISLAND)) { + land.addAbility(new BlueManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.SWAMP)) { + land.addAbility(new BlackManaAbility(), source.getSourceId(), game); + } + } break; } } @@ -89,14 +117,15 @@ public final class Glaciers extends CardImpl { @Override public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; + return layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.TypeChangingEffects_4; } @Override public Set isDependentTo(List allEffectsInLayer) { return allEffectsInLayer .stream() - .filter(effect->effect.getDependencyTypes().contains(DependencyType.BecomeMountain)) + .filter(effect -> effect.getDependencyTypes().contains(DependencyType.BecomePlains)) .map(Effect::getId) .collect(Collectors.toSet()); } diff --git a/Mage.Sets/src/mage/cards/i/IllusionaryTerrain.java b/Mage.Sets/src/mage/cards/i/IllusionaryTerrain.java index 102e49dc619..d61f2916e11 100644 --- a/Mage.Sets/src/mage/cards/i/IllusionaryTerrain.java +++ b/Mage.Sets/src/mage/cards/i/IllusionaryTerrain.java @@ -89,76 +89,46 @@ class IllusionaryTerrainEffect extends ContinuousEffectImpl { && firstChoice != null && secondChoice != null) { for (Permanent land : lands) { - if (land != null - && land.isBasic()) { + if (land.isBasic()) { switch (layer) { case TypeChangingEffects_4: - if (sublayer == SubLayer.NA) { + if (land.getSubtype(game).contains(firstChoice)) { land.getSubtype(game).clear(); land.getSubtype(game).add(secondChoice); + game.getState().setValue("illusionaryTerrain" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game), + "true"); } break; case AbilityAddingRemovingEffects_6: - if (sublayer == SubLayer.NA) { - boolean addAbility = true; - land.getAbilities().clear(); - if (secondChoice.equals(SubType.FOREST)) { - for (Ability existingAbility : land.getAbilities()) { - if (existingAbility instanceof GreenManaAbility) { - addAbility = false; - break; - } - } - if (addAbility) { - land.addAbility(new GreenManaAbility(), source.getSourceId(), game); - } + if (game.getState().getValue("illusionaryTerrain" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game)) != null + && game.getState().getValue("illusionaryTerrain" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game)).equals("true")) { + land.removeAllAbilities(source.getSourceId(), game); + if (land.getSubtype(game).contains(SubType.FOREST)) { + land.addAbility(new GreenManaAbility(), source.getSourceId(), game); } - if (secondChoice.equals(SubType.PLAINS)) { - for (Ability existingAbility : land.getAbilities()) { - if (existingAbility instanceof WhiteManaAbility) { - addAbility = false; - break; - } - } - if (addAbility) { - land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); - } + if (land.getSubtype(game).contains(SubType.PLAINS)) { + land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); } - if (secondChoice.equals(SubType.MOUNTAIN)) { - for (Ability existingAbility : land.getAbilities()) { - if (existingAbility instanceof RedManaAbility) { - addAbility = false; - break; - } - } - if (addAbility) { - land.addAbility(new RedManaAbility(), source.getSourceId(), game); - } + if (land.getSubtype(game).contains(SubType.MOUNTAIN)) { + land.addAbility(new RedManaAbility(), source.getSourceId(), game); } - if (secondChoice.equals(SubType.ISLAND)) { - for (Ability existingAbility : land.getAbilities()) { - if (existingAbility instanceof BlueManaAbility) { - addAbility = false; - break; - } - } - if (addAbility) { - land.addAbility(new BlueManaAbility(), source.getSourceId(), game); - } + if (land.getSubtype(game).contains(SubType.ISLAND)) { + land.addAbility(new BlueManaAbility(), source.getSourceId(), game); } - if (secondChoice.equals(SubType.SWAMP)) { - for (Ability existingAbility : land.getAbilities()) { - if (existingAbility instanceof BlackManaAbility) { - addAbility = false; - break; - } - } - if (addAbility) { - land.addAbility(new BlackManaAbility(), source.getSourceId(), game); - } + if (land.getSubtype(game).contains(SubType.SWAMP)) { + land.addAbility(new BlackManaAbility(), source.getSourceId(), game); } + break; } - break; } } } @@ -174,8 +144,9 @@ class IllusionaryTerrainEffect extends ContinuousEffectImpl { @Override public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6 - || layer == Layer.TypeChangingEffects_4; + return layer == Layer.TypeChangingEffects_4 + || layer == Layer.AbilityAddingRemovingEffects_6; + } } diff --git a/Mage.Sets/src/mage/cards/p/PhantasmalTerrain.java b/Mage.Sets/src/mage/cards/p/PhantasmalTerrain.java index f5bb97875ca..cb425f1d88e 100644 --- a/Mage.Sets/src/mage/cards/p/PhantasmalTerrain.java +++ b/Mage.Sets/src/mage/cards/p/PhantasmalTerrain.java @@ -125,7 +125,8 @@ class PhantasmalTerrainContinuousEffect extends ContinuousEffectImpl { @Override public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; + return layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.TypeChangingEffects_4; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java index 12b594c155b..ce9d973e1bb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.continuous; import mage.abilities.keyword.IndestructibleAbility; @@ -11,7 +10,6 @@ import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.permanent.Permanent; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -114,10 +112,6 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { String bloodmoon = "Blood Moon"; String canopyvista = "Canopy Vista"; - /* - TODO: NOTE: this test is currently failing due to bug in code. See issue #3072 - */ - //@Ignore @Test public void testBloodMoonBeforeUrborg() { // Blood Moon 2R @@ -147,10 +141,6 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { Assert.assertTrue("The mana the land can produce should be [{R}] but it's " + playerB.getManaAvailable(currentGame).toString(), playerB.getManaAvailable(currentGame).toString().equals("[{R}]")); } - /* - TODO: NOTE: this test is currently failing due to bug in code. See issue #3072 - */ - //@Ignore @Test public void testBloodMoonAfterUrborg() { // Blood Moon 2R @@ -186,6 +176,7 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { In terms of time-stamp order, Urborg was down first, then Kormus Bell, then Quicksilver. When I put a flood counter on a basic swamp, it would become a 0/0 instead of a 1/1 and die. */ + @Test public void testCormusBellAfterUrborg() { // Land - Legendary @@ -250,19 +241,19 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Blood Sun"); // all lands lose all abilities except for mana-producing addCard(Zone.BATTLEFIELD, playerA, "Stormtide Leviathan"); // all lands are islands in addition to their other types addCard(Zone.BATTLEFIELD, playerA, "Darksteel Citadel"); // land has indestructible ability - + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); execute(); - + Permanent darksteel = getPermanent("Darksteel Citadel", playerA.getId()); Assert.assertNotNull(darksteel); Assert.assertFalse(darksteel.getAbilities().contains(IndestructibleAbility.getInstance())); // The ability is removed - + /* If a continuous effect has started applying in an earlier layer, it will continue to apply in later layers even if the ability that created that effect has been removed. Urborg ability is applied in the 4th layer. The Blood Sun works in the 6th. So the effect still applies to the lands. - */ + */ assertType(urborgtoy, CardType.LAND, SubType.SWAMP); assertType("Mountain", CardType.LAND, SubType.SWAMP); assertType(urborgtoy, CardType.LAND, SubType.ISLAND); From 00559e3f48ba065d336037521cbdceee7559935d Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 18:11:22 -0500 Subject: [PATCH 07/20] updated RNA spoiler --- Utils/mtg-cards-data.txt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 026aad2e04a..7e1503986c3 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -34583,6 +34583,8 @@ Forbidding Spirit|Ravnica Allegiance|9|U|{1}{W}{W}|Creature - Spirit Cleric|3|3| Hero of Precinct One|Ravnica Allegiance|11|R|{1}{W}|Creature - Human Warrior|2|2|Whenever you cast a multicolored spell, create a 1/1 white Human creature token.| Lumbering Battlement|Ravnica Allegiance|15|R|{4}{W}|Creature - Beast|4|5|Vigilance$When Lumbering Battlement enters the battlefield, exile any number of other nontoken creatures you control until it leaves the battlefield.$Lumbering Battlement gets +2/+2 for each card exiled with it.| Ministrant of Obligation|Ravnica Allegiance|16|U|{2}{W}|Creature - Human Cleric|2|1|Afterlife 2| +Resolute Watchdog|Ravnica Allegiance|19|U|{W}|Creature - Hound|1|3|Defender${1}, Sacrifice Resolute Watchdog: Target creature you control gains indestructible until end of turn.| +Sky Tether|Ravnica Allegiance|21|U|{W}|Enchantment - Aura|||Enchant creature$Enchanted creature has defender and loses flying.| Smothering Tithe|Ravnica Allegiance|22|R|{3}{W}|Enchantment|||Whenever an opponent draws a card, that player may pay {2}. If the player doesn't, you create a colorless Treasure artifact token with "{T}, Sacrifice this artifact: Add one mana of any color."| Spirit of the Spires|Ravnica Allegiance|23|U|{3}{W}|Creature - Spirit|2|4|Flying$Other creatures you control with flying get +0/+1.| Tithe Taker|Ravnica Allegiance|27|R|{1}{W}|Creature - Human Soldier|2|1|During your turn, spells your opponents cast cost {1} more to cast and abilities your opponents activate cost {1} more to activate unless they're mana abilities.$Afterlife 1| @@ -34591,6 +34593,7 @@ Arrester's Admonition|Ravnica Allegiance|31|C|{2}{U}|Instant|||Return target cre Benthic Biomancer|Ravnica Allegiance|32|R|{U}|Creature - Merfolk Wizard Mutant|1|1|{1}{U}: Adapt 1.$Whenever one or more +1/+1 counters are put on Benthic Biomancer, draw a card, then discard a card.| Essence Capture|Ravnica Allegiance|37|U|{U}{U}|Instant|||Counter target creature spell. Put a +1/+1 counter on up to one target creature you control.| Eyes Everywhere|Ravnica Allegiance|38|U|{2}{U}|Enchantment|||At the beginning of your upkeep, scry 1.${5}{U}: Exchange control of Eyes Everywhere and target nonland permanent. Activate this ability only any time you could cast a sorcery.| +Gateway Sneak|Ravnica Allegiance|40|U|{2}{U}|Creature - Vedalken Rogue|1|3|Whenever a Gate enters the battlefield under your control, Gateway Sneak can't be blocked this turn.$Whenever Gateway Sneak deals combat damage to a player, draw a card.| Humongulus|Ravnica Allegiance|41|C|{4}{U}|Creature - Homunculus|2|5|Hexproof| Mass Manipulation|Ravnica Allegiance|42|R|{X}{X}{U}{U}{U}{U}|Sorcery|||Gain control of X target creatures and/or planeswalkers.| Mesmerizing Benthid|Ravnica Allegiance|43|M|{3}{U}{U}|Creature - Octopus|4|5|When Mesmerizing Benthid enters the battlefield, create two 0/2 blue Illusion creature tokens with "Whenever this creature blocks a creature, that creature doesn't untap during its controller's next untap step."$Mesmerizing Benthid has hexproof as long as you control an Illusion.| @@ -34617,6 +34620,8 @@ Spawn of Mayhem|Ravnica Allegiance|85|M|{2}{B}{B}|Creature - Demon|4|4|Spectacle Amplifire|Ravnica Allegiance|92|R|{2}{R}{R}|Creature - Elemental|1|1|At the beginning of your upkeep, reveal cards from the top of your library until you reveal a creature card. Until your next turn, Amplifire's base power becomes twice that card's power and its base toughness becomes twice that card's toughness. Put the revealed cards on the bottom of your library in a random order.| Burn Bright|Ravnica Allegiance|93|C|{2}{R}|Instant|||Creatures you control get +2/+0 until end of turn.| Burning-Tree Vandal|Ravnica Allegiance|94|C|{2}{R}|Creature - Human Rogue|2|1|Riot$Whenever Burning-Tree Vandal attacks, you may discard a card. If you do, draw a card.| +Cavalcade of Calamity|Ravnica Allegiance|95|U|{1}{R}|Enchantment|||Whenever a creature you control with power 1 or less attacks, Cavalcade of Calamity deals 1 damage to the player or planeswalker that creature is attacking.| +Clamor Shaman|Ravnica Allegiance|96|U|{2}{R}|Creature - Goblin Shaman|1|1|Riot$Whenever Clamor Shaman attacks, target creature an opponent controls can't block this turn.| Electrodominance|Ravnica Allegiance|99|R|{X}{R}{R}|Instant|||Electrodominance deals X damage to any target. You may cast a card with converted mana cost X or less from your hand without paying its mana cost.| Gates Ablaze|Ravnica Allegiance|102|U|{2}{R}|Sorcery|||Gates Ablaze deals X damage to each creature, where X is the number of Gates you control.| Immolation Shaman|Ravnica Allegiance|105|R|{1}{R}|Creature - Viashino Shaman|1|3|Whenever an opponent activates an ability of an artifact, creature, or land that isn't a mana ability, Immolation Shaman deals 1 damage to that player.${3}{R}{R}: Immolation Shaman gets +3/+3 and gains menace until end of turn.| @@ -34630,6 +34635,7 @@ Smelt-Ward Ignus|Ravnica Allegiance|116|U|{1}{R}|Creature - Elemental|2|1|{2}{R} Biogenic Ooze|Ravnica Allegiance|122|M|{3}{G}{G}|Creature - Ooze|2|2|When Biogenic Ooze enters the battlefield, create a 2/2 green Ooze creature token.$At the beginning of your end step, put a +1/+1 counter on each Ooze you control.${1}{G}{G}{G}: Create a 2/2 green Ooze creature token.| Biogenic Upgrade|Ravnica Allegiance|123|U|{4}{G}{G}|Sorcery|||Distribute three +1/+1 counters among one, two, or three target creatures, then double the number of +1/+1 counters on each of those creatures.| End-Raze Forerunners|Ravnica Allegiance|124|R|{5}{G}{G}{G}|Creature - Boar|7|7|Vigilance, trample, haste$When End-Raze Forerunners enters the battlefield, other creatures you control get +2/+2 and gain vigilance and trample until end of turn.| +Gatebreaker Ram|Ravnica Allegiance|126|U|{2}{G}|Creature - Sheep|2|2|Gatebreaker Ram gets +1/+1 for each Gate you control.$As long as you control two or more Gates, Gatebreaker Ram has vigilance and trample.| Growth-Chamber Guardian|Ravnica Allegiance|128|R|{1}{G}|Creature - Elf Crab Warrior|2|2|{2}{G}: Adapt 2.$Whenever one or more +1/+1 counters are put on Growth-Chamber Guardian, you may search your library for a card named Growth-Chamber Guardian, reveal it, put it into your hand, then shuffle your library.| Gruul Beastmaster|Ravnica Allegiance|129|U|{3}{G}|Creature - Human Shaman|2|2|Riot$Whenever Gruul Beastmaster attacks, another target creature you control gets +X/+0 until end of turn, where X is Gruul Beastmaster's power.| Guardian Project|Ravnica Allegiance|130|R|{3}{G}|Enchantment|||Whenever a nontoken creature enters the battlefield under your control, if that creature does not have the same name as another creature you control or a creature card in your graveyard, draw a card.| @@ -34674,6 +34680,7 @@ Imperious Oligarch|Ravnica Allegiance|184|C|{W}{B}|Creature - Human Cleric|2|1|V Judith, the Scourge Diva|Ravnica Allegiance|185|R|{1}{B}{R}|Legendary Creature - Human Shaman|2|2|Other creatures you control get +1/+0.$Whenever a nontoken creature you control dies, Judith, the Scourge Diva deals 1 damage to any target.| Kaya, Orzhov Usurper|Ravnica Allegiance|186|M|{1}{W}{B}|Legendary Planeswalker - Kaya|3|+1: Exile up to two target cards from a single graveyard. You gain 2 life if at least one creature card was exiled this way.$-1: Exile target nonland permanent with converted mana cost 1 or less.$-5: Kaya, Orzhov Usurper deals damage to target player equal to the number of cards that player owns in exile and you gain that much life.| Kaya's Wrath|Ravnica Allegiance|187|R|{W}{W}{B}{B}|Sorcery|||Destroy all creatures. You gain life equal to the number of creatures you controlled that were destroyed this way.| +Knight of the Last Breath|Ravnica Allegiance|188|U|{5}{W}{B}|Creature - Giant Knight|4|4|{3}, Sacrifice another nontoken creature: Create a 1/1 white and black spirit creature token with flying.$Afterlife 3| Lavinia, Azorius Renegade|Ravnica Allegiance|189|R|{W}{U}|Legendary Creature - Human Soldier|2|2|Each opponent can't cast noncreature spells with converted mana cost greater than the number of lands that player controls.$Whenever an opponent casts a spell, if no mana was spent to cast it, counter that spell.| Macabre Mockery|Ravnica Allegiance|191|U|{2}{B}{R}|Instant|||Put target creature card from an opponent's graveyard onto the battlefield under your control. It gets +2/+0 and gains haste until end of turn. Sacrifice it at the beginning of the next end step.| Mortify|Ravnica Allegiance|192|U|{1}{W}{B}|Instant|||Destroy target creature or enchantment.| @@ -34727,6 +34734,7 @@ Orzhov Locket|Ravnica Allegiance|236|C|{3}|Artifact|||{T}: Add {W} or {B}.${W/B} Rakdos Locket|Ravnica Allegiance|237|C|{3}|Artifact|||{T}: Add {B} or {R}.${B/R}{B/R}{B/R}{B/R}, {T}, Sacrifice Rakdos Locket: Draw two cards.| Scrabbling Claws|Ravnica Allegiance|238|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.| Simic Locket|Ravnica Allegiance|240|C|{3}|Artifact|||{T}: Add {G} or {U}.${G/U}{G/U}{G/U}{G/U}, {T}, Sacrifice Simic Locket: Draw two cards.| +Sphinx of the Guildpact|Ravnica Allegiance|241|U|{7}|Artifact Creature - Sphinx|5|5|Sphinx of the Guildpact is all colors.$Flying$Hexproof from mono colored| Tome of the Guildpact|Ravnica Allegiance|242|R|{5}|Artifact|||Whenever you cast a multicolored spell, draw a card.${T}: Add one mana of any color.| Azorius Guildgate|Ravnica Allegiance|243|C||Land - Gate|||Azorius Guildgate enters the battlefield tapped.${T}: Add {W} or {U}.| Blood Crypt|Ravnica Allegiance|245|R||Land - Swamp Mountain|||({T}: Add {B} or {R}.)$As Blood Crypt enters the battlefield, you may pay 2 life. If you don't, it enters the battlefield tapped.| @@ -34742,8 +34750,8 @@ Stomping Ground|Ravnica Allegiance|259|R||Land - Mountain Forest|||({T}: Add {R} Dovin, Architect of Law|Ravnica Allegiance|265|M|{4}{W}{U}|Legendary Planeswalker - Dovin|5|+1: You gain 2 life and draw a card.$-1: Tap target creature. It doesn't untap during its controller's next untap step.$-9: Tap all permanents target opponent controls. That player skips their next untap step.| Elite Arrester|Ravnica Allegiance|266|C|{W}|Creature - Human Soldier|0|3|{1}{U}, {T}: Tap target creature.| Dovin's Dismissal|Ravnica Allegiance|267|R|{2}{W}{U}|Instant|||Put up to one target tapped creature on top of its owner's library. You may search your library and/or graveyard for a card named Dovin, Architect of Law, reveal it, and put it into your hand. If you search your library this way, shuffle it.| -Dovin's Automaton|Ravnica Allegiance|268|C|{4}|Artifact Creature - Homunculus|3|3|As long as you control a Dovin planeswalker, Dovin's Automaton gets +2/+2 and has vigilance.| -Domri, City Smasher|Ravnica Allegiance|269|R|{4}{R}{G}|Legendary Planeswalker - Domri|4|+2: Creatures you control get +1/+1 and gain haste until end of turn.$-3: Domri, City Smasher deals 3 damage to any target.$-8: Put three +1/+1 counters on each creature you control. Those creatures gain trample until end of turn.| +Dovin's Automaton|Ravnica Allegiance|268|U|{4}|Artifact Creature - Homunculus|3|3|As long as you control a Dovin planeswalker, Dovin's Automaton gets +2/+2 and has vigilance.| +Domri, City Smasher|Ravnica Allegiance|269|M|{4}{R}{G}|Legendary Planeswalker - Domri|4|+2: Creatures you control get +1/+1 and gain haste until end of turn.$-3: Domri, City Smasher deals 3 damage to any target.$-8: Put three +1/+1 counters on each creature you control. Those creatures gain trample until end of turn.| Ragefire|Ravnica Allegiance|270|C|{1}{R}|Sorcery|||Ragefire deals 3 damage to target creature.| Charging War Boar|Ravnica Allegiance|271|U|{1}{R}{G}|Creature - Boar|3|1|Haste$As long as you control a Domri planeswalker, Charging War Boar gets +1/+1 and has trample.| Domri's Nodorog|Ravnica Allegiance|272|R|{3}{R}{G}|Creature - Beast|5|2|Trample$When Domri's Nodorog enters the battlefield, you may search your library and/or graveyard for a card named Domri, City Smasher, reveal it, and put it into your hand. If you search your library this way, shuffle it.| From d7e68cf932835fe28098a400c0fd282d0b50a674 Mon Sep 17 00:00:00 2001 From: Ingmar Goudt Date: Fri, 11 Jan 2019 01:02:45 +0100 Subject: [PATCH 08/20] clean up cipherEffect --- .../effects/common/CipherEffect.java | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java index 9dd49c7ea60..af625b9c7a2 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java @@ -1,7 +1,6 @@ package mage.abilities.effects.common; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -20,11 +19,13 @@ import mage.players.Player; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** * FAQ 2013/01/11 - * + *

* 702.97. Cipher - * + *

* 702.97a Cipher appears on some instants and sorceries. It represents two * static abilities, one that functions while the spell is on the stack and one * that functions while the card with cipher is in the exile zone. "Cipher" @@ -33,17 +34,17 @@ import mage.target.targetpointer.FixedTarget; * that creature, that creature has 'Whenever this creature deals combat damage * to a player, you may copy this card and you may cast the copy without paying * its mana cost.'" - * + *

* 702.97b The term "encoded" describes the relationship between the card with * cipher while in the exile zone and the creature chosen when the spell * represented by that card resolves. - * + *

* 702.97c The card with cipher remains encoded on the chosen creature as long * as the card with cipher remains exiled and the creature remains on the * battlefield. The card remains encoded on that object even if it changes * controller or stops being a creature, as long as it remains on the * battlefield. - * + *

* TODO: Implement Cipher as two static abilities concerning the rules. * * @author LevelX2 @@ -118,16 +119,9 @@ class CipherStoreEffect extends OneShotEffect { Card copyCard = game.copyCard(cipherCard, source, controller.getId()); SpellAbility ability = copyCard.getSpellAbility(); // remove the cipher effect from the copy - Effect cipherEffect = null; - for (Effect effect : ability.getEffects()) { - if (effect instanceof CipherEffect) { - cipherEffect = effect; - } - } - ability.getEffects().remove(cipherEffect); - if (ability instanceof SpellAbility) { - controller.cast(ability, game, true, new MageObjectReference(source.getSourceObject(game), game)); - } + ability.getEffects().removeIf(effect -> effect instanceof CipherEffect); + controller.cast(ability, game, true, new MageObjectReference(source.getSourceObject(game), game)); + } return false; From d5003a6f8fe3a17cb8f6408a3f02263159d48072 Mon Sep 17 00:00:00 2001 From: Ingmar Goudt Date: Fri, 11 Jan 2019 01:04:34 +0100 Subject: [PATCH 09/20] add null check --- .../main/java/mage/abilities/effects/common/CipherEffect.java | 2 +- Mage/src/main/java/mage/game/permanent/PermanentImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java index af625b9c7a2..72b22fc266e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java @@ -115,7 +115,7 @@ class CipherStoreEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Card cipherCard = game.getCard(cipherCardId); - if (cipherCard != null) { + if (cipherCard != null && controller != null) { Card copyCard = game.copyCard(cipherCard, source, controller.getId()); SpellAbility ability = copyCard.getSpellAbility(); // remove the cipher effect from the copy diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index ed908b5e146..a4d9290b227 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -43,7 +43,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { private static final Logger logger = Logger.getLogger(PermanentImpl.class); - public class MarkedDamageInfo { + static class MarkedDamageInfo { public MarkedDamageInfo(Counter counter, MageObject sourceObject) { this.counter = counter; From 7a89d228801bae01ebb9d0aa7ebd904e92669392 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 18:29:43 -0500 Subject: [PATCH 10/20] Implemented Sphinx of the Guildpact --- .../mage/cards/s/SphinxOfTheGuildpact.java | 51 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + .../HexproofFromMonocoloredAbility.java | 44 ++++++++++++++++ .../mage/game/permanent/PermanentImpl.java | 8 +++ 4 files changed, 104 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SphinxOfTheGuildpact.java create mode 100644 Mage/src/main/java/mage/abilities/keyword/HexproofFromMonocoloredAbility.java diff --git a/Mage.Sets/src/mage/cards/s/SphinxOfTheGuildpact.java b/Mage.Sets/src/mage/cards/s/SphinxOfTheGuildpact.java new file mode 100644 index 00000000000..97c09111cab --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SphinxOfTheGuildpact.java @@ -0,0 +1,51 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HexproofFromMonocoloredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SphinxOfTheGuildpact extends CardImpl { + + public SphinxOfTheGuildpact(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{7}"); + + this.subtype.add(SubType.SPHINX); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Sphinx of the Guildpact is all colors. + this.color.setWhite(true); + this.color.setBlue(true); + this.color.setBlack(true); + this.color.setRed(true); + this.color.setGreen(true); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("{this} is all colors"))); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Hexproof from mono colored + this.addAbility(HexproofFromMonocoloredAbility.getInstance()); + } + + private SphinxOfTheGuildpact(final SphinxOfTheGuildpact card) { + super(card); + } + + @Override + public SphinxOfTheGuildpact copy() { + return new SphinxOfTheGuildpact(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index a502ae1014b..0f27beb1c55 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -176,6 +176,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Spawn of Mayhem", 85, Rarity.MYTHIC, mage.cards.s.SpawnOfMayhem.class)); cards.add(new SetCardInfo("Sphinx of Foresight", 55, Rarity.RARE, mage.cards.s.SphinxOfForesight.class)); cards.add(new SetCardInfo("Sphinx of New Prahv", 208, Rarity.UNCOMMON, mage.cards.s.SphinxOfNewPrahv.class)); + cards.add(new SetCardInfo("Sphinx of the Guildpact", 241, Rarity.UNCOMMON, mage.cards.s.SphinxOfTheGuildpact.class)); cards.add(new SetCardInfo("Sphinx's Insight", 209, Rarity.COMMON, mage.cards.s.SphinxsInsight.class)); cards.add(new SetCardInfo("Spirit of the Spires", 23, Rarity.UNCOMMON, mage.cards.s.SpiritOfTheSpires.class)); cards.add(new SetCardInfo("Stomping Ground", 259, Rarity.RARE, mage.cards.s.StompingGround.class)); diff --git a/Mage/src/main/java/mage/abilities/keyword/HexproofFromMonocoloredAbility.java b/Mage/src/main/java/mage/abilities/keyword/HexproofFromMonocoloredAbility.java new file mode 100644 index 00000000000..88fd558921d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/HexproofFromMonocoloredAbility.java @@ -0,0 +1,44 @@ +package mage.abilities.keyword; + +import mage.abilities.MageSingleton; +import mage.abilities.common.SimpleStaticAbility; +import mage.constants.Zone; + +import java.io.ObjectStreamException; + +/** + * Hexproof from Monocolored (This creature or player can't be the target of monocolored + * spells or abilities your opponents control.) + * + * @author TheElk801 + */ +public class HexproofFromMonocoloredAbility extends SimpleStaticAbility implements MageSingleton { + + private static final HexproofFromMonocoloredAbility instance; + + static { + instance = new HexproofFromMonocoloredAbility(); + } + + private Object readResolve() throws ObjectStreamException { + return instance; + } + + public static HexproofFromMonocoloredAbility getInstance() { + return instance; + } + + private HexproofFromMonocoloredAbility() { + super(Zone.BATTLEFIELD, null); + } + + @Override + public HexproofFromMonocoloredAbility copy() { + return instance; + } + + @Override + public String getRule() { + return "hexproof from monocolored (This creature can't be the target of monocolored spells or abilities your opponents control.)"; + } +} diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index a4d9290b227..0b646f11dc8 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -956,6 +956,14 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } } + if (abilities.containsKey(HexproofFromMonocoloredAbility.getInstance().getId())) { + if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game) + && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) + && !source.getColor(game).isColorless() && !source.getColor(game).isMulticolored()) { + return false; + } + } + if (hasProtectionFrom(source, game)) { return false; } From 19cabfaf444073131632ee7b86f907f712c8e38d Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 18:33:26 -0500 Subject: [PATCH 11/20] Implemented Clamor Shaman --- Mage.Sets/src/mage/cards/c/ClamorShaman.java | 49 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 50 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/ClamorShaman.java diff --git a/Mage.Sets/src/mage/cards/c/ClamorShaman.java b/Mage.Sets/src/mage/cards/c/ClamorShaman.java new file mode 100644 index 00000000000..3d8e5b0fea4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ClamorShaman.java @@ -0,0 +1,49 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +import mage.abilities.keyword.RiotAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ClamorShaman extends CardImpl { + + public ClamorShaman(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Riot + this.addAbility(new RiotAbility()); + + // Whenever Clamor Shaman attacks, target creature an opponent controls can't block this turn. + Ability ability = new AttacksTriggeredAbility( + new CantBlockTargetEffect(Duration.EndOfTurn), false + ); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private ClamorShaman(final ClamorShaman card) { + super(card); + } + + @Override + public ClamorShaman copy() { + return new ClamorShaman(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 0f27beb1c55..41e68a99b7e 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -62,6 +62,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Carnival // Carnage", 222, Rarity.UNCOMMON, mage.cards.c.CarnivalCarnage.class)); cards.add(new SetCardInfo("Charging War Boar", 271, Rarity.UNCOMMON, mage.cards.c.ChargingWarBoar.class)); cards.add(new SetCardInfo("Cindervines", 161, Rarity.RARE, mage.cards.c.Cindervines.class)); + cards.add(new SetCardInfo("Clamor Shaman", 96, Rarity.UNCOMMON, mage.cards.c.ClamorShaman.class)); cards.add(new SetCardInfo("Clan Guildmage", 162, Rarity.UNCOMMON, mage.cards.c.ClanGuildmage.class)); cards.add(new SetCardInfo("Collision // Colossus", 223, Rarity.UNCOMMON, mage.cards.c.CollisionColossus.class)); cards.add(new SetCardInfo("Combine Guildmage", 163, Rarity.UNCOMMON, mage.cards.c.CombineGuildmage.class)); From c058525c49426a90abf0451adb6893ec884933f8 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 18:45:17 -0500 Subject: [PATCH 12/20] Implemented Gatebreaker Ram --- .../src/mage/cards/g/GatebreakerRam.java | 76 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 77 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/g/GatebreakerRam.java diff --git a/Mage.Sets/src/mage/cards/g/GatebreakerRam.java b/Mage.Sets/src/mage/cards/g/GatebreakerRam.java new file mode 100644 index 00000000000..5a9a159ea42 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GatebreakerRam.java @@ -0,0 +1,76 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GatebreakerRam extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + private static final DynamicValue xValue + = new PermanentsOnBattlefieldCount(filter); + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + + public GatebreakerRam(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.SHEEP); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Gatebreaker Ram gets +1/+1 for each Gate you control. + this.addAbility(new SimpleStaticAbility( + new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield) + .setText("{this} gets +1/+1 for each Gate you control.") + )); + + // As long as you control two or more Gates, Gatebreaker Ram has vigilance and trample. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(VigilanceAbility.getInstance()), + condition, "As long as you control two or more Gates, {this} has vigilance" + )); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(TrampleAbility.getInstance()), + condition, "and trample" + )); + this.addAbility(ability); + } + + private GatebreakerRam(final GatebreakerRam card) { + super(card); + } + + @Override + public GatebreakerRam copy() { + return new GatebreakerRam(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 41e68a99b7e..ca7d30e2160 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -92,6 +92,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Frenzied Arynx", 173, Rarity.COMMON, mage.cards.f.FrenziedArynx.class)); cards.add(new SetCardInfo("Frilled Mystic", 174, Rarity.UNCOMMON, mage.cards.f.FrilledMystic.class)); cards.add(new SetCardInfo("Gate Colossus", 232, Rarity.UNCOMMON, mage.cards.g.GateColossus.class)); + cards.add(new SetCardInfo("Gatebreaker Ram", 126, Rarity.UNCOMMON, mage.cards.g.GatebreakerRam.class)); cards.add(new SetCardInfo("Gates Ablaze", 102, Rarity.UNCOMMON, mage.cards.g.GatesAblaze.class)); cards.add(new SetCardInfo("Glass of the Guildpact", 233, Rarity.RARE, mage.cards.g.GlassOfTheGuildpact.class)); cards.add(new SetCardInfo("Godless Shrine", 248, Rarity.RARE, mage.cards.g.GodlessShrine.class)); From c986def3cca662870d31f3f7b28772f18f546cf0 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 18:53:29 -0500 Subject: [PATCH 13/20] Implemented Gateway Sneak --- Mage.Sets/src/mage/cards/g/GatewaySneak.java | 51 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 52 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/g/GatewaySneak.java diff --git a/Mage.Sets/src/mage/cards/g/GatewaySneak.java b/Mage.Sets/src/mage/cards/g/GatewaySneak.java new file mode 100644 index 00000000000..9d0596cb775 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GatewaySneak.java @@ -0,0 +1,51 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GatewaySneak extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.GATE, "a Gate"); + + public GatewaySneak(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.VEDALKEN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Whenever a Gate enters the battlefield under your control, Gateway Sneak can't be blocked this turn. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new CantBeBlockedSourceEffect(Duration.EndOfTurn), filter + )); + + // Whenever Gateway Sneak deals combat damage to a player, draw a card. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + )); + } + + private GatewaySneak(final GatewaySneak card) { + super(card); + } + + @Override + public GatewaySneak copy() { + return new GatewaySneak(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index ca7d30e2160..96c96648203 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -94,6 +94,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Gate Colossus", 232, Rarity.UNCOMMON, mage.cards.g.GateColossus.class)); cards.add(new SetCardInfo("Gatebreaker Ram", 126, Rarity.UNCOMMON, mage.cards.g.GatebreakerRam.class)); cards.add(new SetCardInfo("Gates Ablaze", 102, Rarity.UNCOMMON, mage.cards.g.GatesAblaze.class)); + cards.add(new SetCardInfo("Gateway Sneak", 40, Rarity.UNCOMMON, mage.cards.g.GatewaySneak.class)); cards.add(new SetCardInfo("Glass of the Guildpact", 233, Rarity.RARE, mage.cards.g.GlassOfTheGuildpact.class)); cards.add(new SetCardInfo("Godless Shrine", 248, Rarity.RARE, mage.cards.g.GodlessShrine.class)); cards.add(new SetCardInfo("Grasping Thrull", 177, Rarity.COMMON, mage.cards.g.GraspingThrull.class)); From f00ac1a3c00e672ded0d77d2b78151f2b6bf70b9 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 19:05:02 -0500 Subject: [PATCH 14/20] Implemented Knight of the Last Breath --- .../mage/cards/k/KnightOfTheLastBreath.java | 63 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 64 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/k/KnightOfTheLastBreath.java diff --git a/Mage.Sets/src/mage/cards/k/KnightOfTheLastBreath.java b/Mage.Sets/src/mage/cards/k/KnightOfTheLastBreath.java new file mode 100644 index 00000000000..8233331a889 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnightOfTheLastBreath.java @@ -0,0 +1,63 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.AfterlifeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.WhiteBlackSpiritToken; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KnightOfTheLastBreath extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledCreaturePermanent("another nontoken creature"); + + static { + filter.add(new AnotherPredicate()); + filter.add(Predicates.not(new TokenPredicate())); + } + + public KnightOfTheLastBreath(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{B}"); + + this.subtype.add(SubType.GIANT); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // {3}, Sacrifice another nontoken creature: Create a 1/1 white and black spirit creature token with flying. + Ability ability = new SimpleActivatedAbility( + new CreateTokenEffect(new WhiteBlackSpiritToken()), new GenericManaCost(3) + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + + // Afterlife 3 + this.addAbility(new AfterlifeAbility(3)); + } + + private KnightOfTheLastBreath(final KnightOfTheLastBreath card) { + super(card); + } + + @Override + public KnightOfTheLastBreath copy() { + return new KnightOfTheLastBreath(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 96c96648203..07544722347 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -121,6 +121,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Judith, the Scourge Diva", 185, Rarity.RARE, mage.cards.j.JudithTheScourgeDiva.class)); cards.add(new SetCardInfo("Kaya's Wrath", 187, Rarity.RARE, mage.cards.k.KayasWrath.class)); cards.add(new SetCardInfo("Kaya, Orzhov Usurper", 186, Rarity.MYTHIC, mage.cards.k.KayaOrzhovUsurper.class)); + cards.add(new SetCardInfo("Knight of the Last Breath", 188, Rarity.UNCOMMON, mage.cards.k.KnightOfTheLastBreath.class)); cards.add(new SetCardInfo("Lavinia, Azorius Renegade", 189, Rarity.RARE, mage.cards.l.LaviniaAzoriusRenegade.class)); cards.add(new SetCardInfo("Light Up the Stage", 107, Rarity.UNCOMMON, mage.cards.l.LightUpTheStage.class)); cards.add(new SetCardInfo("Lumbering Battlement", 15, Rarity.RARE, mage.cards.l.LumberingBattlement.class)); From c440663cdc8d128baae32111de05adb4b7e0728f Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 19:09:24 -0500 Subject: [PATCH 15/20] Implemented Resolute Watchdog --- .../src/mage/cards/r/ResoluteWatchdog.java | 55 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 56 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/r/ResoluteWatchdog.java diff --git a/Mage.Sets/src/mage/cards/r/ResoluteWatchdog.java b/Mage.Sets/src/mage/cards/r/ResoluteWatchdog.java new file mode 100644 index 00000000000..80f127f7006 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ResoluteWatchdog.java @@ -0,0 +1,55 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ResoluteWatchdog extends CardImpl { + + public ResoluteWatchdog(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.HOUND); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // {1}, Sacrifice Resolute Watchdog: Target creature you control gains indestructible until end of turn. + Ability ability = new SimpleActivatedAbility( + new GainAbilityTargetEffect( + IndestructibleAbility.getInstance(), + Duration.EndOfTurn + ), new GenericManaCost(1) + ); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private ResoluteWatchdog(final ResoluteWatchdog card) { + super(card); + } + + @Override + public ResoluteWatchdog copy() { + return new ResoluteWatchdog(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 07544722347..95e8e91abc3 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -157,6 +157,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Ravager Wurm", 200, Rarity.MYTHIC, mage.cards.r.RavagerWurm.class)); cards.add(new SetCardInfo("Regenesis", 136, Rarity.UNCOMMON, mage.cards.r.Regenesis.class)); cards.add(new SetCardInfo("Repudiate // Replicate", 227, Rarity.RARE, mage.cards.r.RepudiateReplicate.class)); + cards.add(new SetCardInfo("Resolute Watchdog", 19, Rarity.UNCOMMON, mage.cards.r.ResoluteWatchdog.class)); cards.add(new SetCardInfo("Revival // Revenge", 228, Rarity.RARE, mage.cards.r.RevivalRevenge.class)); cards.add(new SetCardInfo("Rhythm of the Wild", 201, Rarity.UNCOMMON, mage.cards.r.RhythmOfTheWild.class)); cards.add(new SetCardInfo("Rix Maadi Reveler", 109, Rarity.RARE, mage.cards.r.RixMaadiReveler.class)); From 0404be994e7557499165c7258d01c3aeb793e6ac Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 19:13:13 -0500 Subject: [PATCH 16/20] Implemented Sky Tether --- Mage.Sets/src/mage/cards/s/SkyTether.java | 54 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 55 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SkyTether.java diff --git a/Mage.Sets/src/mage/cards/s/SkyTether.java b/Mage.Sets/src/mage/cards/s/SkyTether.java new file mode 100644 index 00000000000..d2f8b850871 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkyTether.java @@ -0,0 +1,54 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.effects.common.continuous.LoseAbilityAttachedEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SkyTether extends CardImpl { + + public SkyTether(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + 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 defender and loses flying. + ability = new SimpleStaticAbility(new GainAbilityAttachedEffect( + DefenderAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield + )); + ability.addEffect(new LoseAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.AURA + ).setText("and loses flying")); + this.addAbility(ability); + } + + private SkyTether(final SkyTether card) { + super(card); + } + + @Override + public SkyTether copy() { + return new SkyTether(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 95e8e91abc3..85e2a023e7e 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -176,6 +176,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Skarrgan Hellkite", 114, Rarity.MYTHIC, mage.cards.s.SkarrganHellkite.class)); cards.add(new SetCardInfo("Skatewing Spy", 52, Rarity.UNCOMMON, mage.cards.s.SkatewingSpy.class)); cards.add(new SetCardInfo("Skewer the Critics", 115, Rarity.COMMON, mage.cards.s.SkewerTheCritics.class)); + cards.add(new SetCardInfo("Sky Tether", 21, Rarity.UNCOMMON, mage.cards.s.SkyTether.class)); cards.add(new SetCardInfo("Smelt-Ward Ignus", 116, Rarity.UNCOMMON, mage.cards.s.SmeltWardIgnus.class)); cards.add(new SetCardInfo("Smothering Tithe", 22, Rarity.RARE, mage.cards.s.SmotheringTithe.class)); cards.add(new SetCardInfo("Spawn of Mayhem", 85, Rarity.MYTHIC, mage.cards.s.SpawnOfMayhem.class)); From e0cb67f4932c3022f99d8d800e77faa7a48d8558 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 19:32:50 -0500 Subject: [PATCH 17/20] Implemented Cavalcade of Calamity --- .../src/mage/cards/c/CavalcadeOfCalamity.java | 72 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 73 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/c/CavalcadeOfCalamity.java diff --git a/Mage.Sets/src/mage/cards/c/CavalcadeOfCalamity.java b/Mage.Sets/src/mage/cards/c/CavalcadeOfCalamity.java new file mode 100644 index 00000000000..eabf9118a8d --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CavalcadeOfCalamity.java @@ -0,0 +1,72 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksAllTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CavalcadeOfCalamity extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creaure you control with power 1 or less"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 2)); + } + + public CavalcadeOfCalamity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + // Whenever a creature you control with power 1 or less attacks, Cavalcade of Calamity deals 1 damage to the player or planeswalker that creature is attacking. + this.addAbility(new AttacksAllTriggeredAbility( + new CavalcadeOfCalamityEffect(), false, filter, + SetTargetPointer.PERMANENT, false, false + )); + } + + private CavalcadeOfCalamity(final CavalcadeOfCalamity card) { + super(card); + } + + @Override + public CavalcadeOfCalamity copy() { + return new CavalcadeOfCalamity(this); + } +} + +class CavalcadeOfCalamityEffect extends OneShotEffect { + + CavalcadeOfCalamityEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 1 damage to the player or planeswalker that creature is attacking."; + } + + private CavalcadeOfCalamityEffect(final CavalcadeOfCalamityEffect effect) { + super(effect); + } + + @Override + public CavalcadeOfCalamityEffect copy() { + return new CavalcadeOfCalamityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return game.damagePlayerOrPlaneswalker( + game.getCombat().getDefenderId(source.getFirstTarget()), 1, + source.getSourceId(), game, false, true + ) > 0; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 85e2a023e7e..2cf0f19432c 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -60,6 +60,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Burning-Tree Vandal", 94, Rarity.COMMON, mage.cards.b.BurningTreeVandal.class)); cards.add(new SetCardInfo("Captive Audience", 160, Rarity.MYTHIC, mage.cards.c.CaptiveAudience.class)); cards.add(new SetCardInfo("Carnival // Carnage", 222, Rarity.UNCOMMON, mage.cards.c.CarnivalCarnage.class)); + cards.add(new SetCardInfo("Cavalcade of Calamity", 95, Rarity.UNCOMMON, mage.cards.c.CavalcadeOfCalamity.class)); cards.add(new SetCardInfo("Charging War Boar", 271, Rarity.UNCOMMON, mage.cards.c.ChargingWarBoar.class)); cards.add(new SetCardInfo("Cindervines", 161, Rarity.RARE, mage.cards.c.Cindervines.class)); cards.add(new SetCardInfo("Clamor Shaman", 96, Rarity.UNCOMMON, mage.cards.c.ClamorShaman.class)); From 8971b937d075deb4496345cbf38367a3ded679f9 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 19:36:24 -0500 Subject: [PATCH 18/20] Implemented Eyes Everywhere --- .../src/mage/cards/e/EyesEverywhere.java | 53 +++++++++++++++++++ .../src/mage/sets/RavnicaAllegiance.java | 1 + 2 files changed, 54 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/e/EyesEverywhere.java diff --git a/Mage.Sets/src/mage/cards/e/EyesEverywhere.java b/Mage.Sets/src/mage/cards/e/EyesEverywhere.java new file mode 100644 index 00000000000..701e6ef5606 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EyesEverywhere.java @@ -0,0 +1,53 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EyesEverywhere extends CardImpl { + + public EyesEverywhere(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + // At the beginning of your upkeep, scry 1. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, new ScryEffect(1), + TargetController.YOU, false + )); + + // {5}{U}: Exchange control of Eyes Everywhere and target nonland permanent. Activate this ability only any time you could cast a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + Zone.BATTLEFIELD, + new ExchangeControlTargetEffect( + Duration.EndOfGame, "Exchange control of {this} " + + "and target nonland permanent", true + ), new ManaCostsImpl("{5}{U}") + ); + ability.addTarget(new TargetNonlandPermanent()); + this.addAbility(ability); + } + + private EyesEverywhere(final EyesEverywhere card) { + super(card); + } + + @Override + public EyesEverywhere copy() { + return new EyesEverywhere(this); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 2cf0f19432c..7eb20fa0cc9 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -87,6 +87,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("End-Raze Forerunners", 124, Rarity.RARE, mage.cards.e.EndRazeForerunners.class)); cards.add(new SetCardInfo("Essence Capture", 37, Rarity.UNCOMMON, mage.cards.e.EssenceCapture.class)); cards.add(new SetCardInfo("Ethereal Absolution", 170, Rarity.RARE, mage.cards.e.EtherealAbsolution.class)); + cards.add(new SetCardInfo("Eyes Everywhere", 38, Rarity.UNCOMMON, mage.cards.e.EyesEverywhere.class)); cards.add(new SetCardInfo("Fireblade Artist", 172, Rarity.UNCOMMON, mage.cards.f.FirebladeArtist.class)); cards.add(new SetCardInfo("Font of Agonies", 74, Rarity.RARE, mage.cards.f.FontOfAgonies.class)); cards.add(new SetCardInfo("Forbidding Spirit", 9, Rarity.UNCOMMON, mage.cards.f.ForbiddingSpirit.class)); From 2d6f07f0c8729dbd6bc12a7d30926abd24827139 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 20:20:48 -0500 Subject: [PATCH 19/20] Implemented Macabre Mockery --- .../src/mage/cards/m/MacabreMockery.java | 92 +++++++++++++++++++ .../src/mage/cards/p/PuppeteerClique.java | 57 +++++------- .../src/mage/sets/RavnicaAllegiance.java | 1 + 3 files changed, 118 insertions(+), 32 deletions(-) create mode 100644 Mage.Sets/src/mage/cards/m/MacabreMockery.java diff --git a/Mage.Sets/src/mage/cards/m/MacabreMockery.java b/Mage.Sets/src/mage/cards/m/MacabreMockery.java new file mode 100644 index 00000000000..519dffff174 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MacabreMockery.java @@ -0,0 +1,92 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInOpponentsGraveyard; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MacabreMockery extends CardImpl { + + public MacabreMockery(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}{R}"); + + // Put target creature card from an opponent's graveyard onto the battlefield under your control. It gets +2/+0 and gains haste until end of turn. Sacrifice it at the beginning of the next end step. + this.getSpellAbility().addEffect(new MacabreMockeryEffect()); + this.getSpellAbility().addTarget(new TargetCardInOpponentsGraveyard(StaticFilters.FILTER_CARD_CREATURE)); + } + + private MacabreMockery(final MacabreMockery card) { + super(card); + } + + @Override + public MacabreMockery copy() { + return new MacabreMockery(this); + } +} + +class MacabreMockeryEffect extends OneShotEffect { + + MacabreMockeryEffect() { + super(Outcome.PutCreatureInPlay); + staticText = "Put target creature card from an opponent's graveyard onto the battlefield under your control. " + + "It gets +2/+0 and gains haste until end of turn. Sacrifice it at the beginning of the next end step."; + } + + private MacabreMockeryEffect(final MacabreMockeryEffect effect) { + super(effect); + } + + @Override + public MacabreMockeryEffect copy() { + return new MacabreMockeryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (card == null) { + return false; + } + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null || !controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + return false; + } + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + return false; + } + ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + effect = new BoostTargetEffect(2, 0, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + Effect sacrificeEffect = new SacrificeTargetEffect("exile " + permanent.getLogName()); + sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + sacrificeEffect, TargetController.YOU + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PuppeteerClique.java b/Mage.Sets/src/mage/cards/p/PuppeteerClique.java index 774fa5d6a56..0216d1093ff 100644 --- a/Mage.Sets/src/mage/cards/p/PuppeteerClique.java +++ b/Mage.Sets/src/mage/cards/p/PuppeteerClique.java @@ -1,7 +1,6 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -17,12 +16,7 @@ import mage.abilities.keyword.PersistAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.permanent.Permanent; @@ -31,15 +25,15 @@ import mage.target.Target; import mage.target.common.TargetCardInOpponentsGraveyard; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth - * */ public final class PuppeteerClique extends CardImpl { public PuppeteerClique(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.FAERIE); this.subtype.add(SubType.WIZARD); @@ -59,7 +53,7 @@ public final class PuppeteerClique extends CardImpl { this.addAbility(new PersistAbility()); } - public PuppeteerClique(final PuppeteerClique card) { + private PuppeteerClique(final PuppeteerClique card) { super(card); } @@ -71,12 +65,12 @@ public final class PuppeteerClique extends CardImpl { class PuppeteerCliqueEffect extends OneShotEffect { - public PuppeteerCliqueEffect() { + PuppeteerCliqueEffect() { super(Outcome.PutCreatureInPlay); staticText = "put target creature card from an opponent's graveyard onto the battlefield under your control. It gains haste. At the beginning of your next end step, exile it"; } - public PuppeteerCliqueEffect(final PuppeteerCliqueEffect effect) { + private PuppeteerCliqueEffect(final PuppeteerCliqueEffect effect) { super(effect); } @@ -87,26 +81,25 @@ class PuppeteerCliqueEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - boolean result = false; Card card = game.getCard(getTargetPointer().getFirst(game, source)); - if (card != null) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); - hasteEffect.setTargetPointer(new FixedTarget(permanent, game)); - game.addEffect(hasteEffect, source); - ExileTargetEffect exileEffect = new ExileTargetEffect("exile " + permanent.getLogName()); - exileEffect.setTargetPointer(new FixedTarget(permanent, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect, TargetController.YOU); - game.addDelayedTriggeredAbility(delayedAbility, source); - result = true; - } - } - } + if (card == null) { + return false; } - return result; + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null || !controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + return false; + } + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + return false; + } + ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); + hasteEffect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(hasteEffect, source); + ExileTargetEffect exileEffect = new ExileTargetEffect("exile " + permanent.getLogName()); + exileEffect.setTargetPointer(new FixedTarget(permanent, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect, TargetController.YOU); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; } } diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java index 7eb20fa0cc9..8cd69754cd6 100644 --- a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -127,6 +127,7 @@ public final class RavnicaAllegiance extends ExpansionSet { cards.add(new SetCardInfo("Lavinia, Azorius Renegade", 189, Rarity.RARE, mage.cards.l.LaviniaAzoriusRenegade.class)); cards.add(new SetCardInfo("Light Up the Stage", 107, Rarity.UNCOMMON, mage.cards.l.LightUpTheStage.class)); cards.add(new SetCardInfo("Lumbering Battlement", 15, Rarity.RARE, mage.cards.l.LumberingBattlement.class)); + cards.add(new SetCardInfo("Macabre Mockery", 191, Rarity.UNCOMMON, mage.cards.m.MacabreMockery.class)); cards.add(new SetCardInfo("Mass Manipulation", 42, Rarity.RARE, mage.cards.m.MassManipulation.class)); cards.add(new SetCardInfo("Mesmerizing Benthid", 43, Rarity.MYTHIC, mage.cards.m.MesmerizingBenthid.class)); cards.add(new SetCardInfo("Ministrant of Obligation", 16, Rarity.UNCOMMON, mage.cards.m.MinistrantOfObligation.class)); From 47625bc84e3fbffa0a6d563bf5884608e016d5db Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Thu, 10 Jan 2019 20:32:39 -0500 Subject: [PATCH 20/20] Update SkyTether.java --- Mage.Sets/src/mage/cards/s/SkyTether.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Sets/src/mage/cards/s/SkyTether.java b/Mage.Sets/src/mage/cards/s/SkyTether.java index d2f8b850871..d24831c3186 100644 --- a/Mage.Sets/src/mage/cards/s/SkyTether.java +++ b/Mage.Sets/src/mage/cards/s/SkyTether.java @@ -39,7 +39,7 @@ public final class SkyTether extends CardImpl { )); ability.addEffect(new LoseAbilityAttachedEffect( FlyingAbility.getInstance(), AttachmentType.AURA - ).setText("and loses flying")); + ).concatBy("and")); this.addAbility(ability); }