diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java index 2d3a925d727..0a763757804 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java @@ -500,6 +500,7 @@ public class ScryfallImageSupportCards { add("STA"); // Strixhaven Mystical Archive add("C21"); // Commander 2021 Edition add("MH2"); // Modern Horizons 2 + add("RMH1"); // Modern Horizons 1 Timeshifts add("AFR"); // Adventures in the Forgotten Realms } }; diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Historic.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Historic.java index 2760405e44e..2e8a5cd1d70 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Historic.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Historic.java @@ -43,6 +43,7 @@ public class Historic extends Constructed { banned.add("Swords to Plowshares"); banned.add("Teferi, Time Raveler"); banned.add("Thassa's Oracle"); + banned.add("Time Warp"); banned.add("Uro, Titan of Nature's Wrath"); banned.add("Veil of Summer"); banned.add("Wilderness Reclamation"); @@ -101,7 +102,6 @@ public class Historic extends Constructed { banned.add("Mausoleum Turnkey"); banned.add("Reanimate"); banned.add("Scourge of Nel Toth"); - banned.add("Sheoldred, Whispering One"); banned.add("Ball Lightning"); banned.add("Chain Lightning"); banned.add("Draconic Roar"); diff --git a/Mage.Sets/src/mage/cards/a/AcademyManufactor.java b/Mage.Sets/src/mage/cards/a/AcademyManufactor.java new file mode 100644 index 00000000000..94d885eb6f6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AcademyManufactor.java @@ -0,0 +1,107 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.events.CreateTokenEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.token.ClueArtifactToken; +import mage.game.permanent.token.FoodToken; +import mage.game.permanent.token.Token; +import mage.game.permanent.token.TreasureToken; + +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; + +/** + * @author weirddan455 + */ +public final class AcademyManufactor extends CardImpl { + + public AcademyManufactor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + + this.subtype.add(SubType.ASSEMBLY_WORKER); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // If you would create a Clue, Food, or Treasure token, instead create one of each. + this.addAbility(new SimpleStaticAbility(new AcademyManufactorEffect())); + } + + private AcademyManufactor(final AcademyManufactor card) { + super(card); + } + + @Override + public AcademyManufactor copy() { + return new AcademyManufactor(this); + } +} + +class AcademyManufactorEffect extends ReplacementEffectImpl { + + public AcademyManufactorEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + this.staticText = "If you would create a Clue, Food, or Treasure token, instead create one of each"; + } + + private AcademyManufactorEffect(final AcademyManufactorEffect effect) { + super(effect); + } + + @Override + public AcademyManufactorEffect copy() { + return new AcademyManufactorEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CREATE_TOKEN; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!(event instanceof CreateTokenEvent) || !event.getPlayerId().equals(source.getControllerId())) { + return false; + } + for (Token token : ((CreateTokenEvent) event).getTokens().keySet()) { + if (token.hasSubtype(SubType.CLUE, game) + || token.hasSubtype(SubType.FOOD, game) + || token.hasSubtype(SubType.TREASURE, game)) { + return true; + } + } + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + int amount = 0; + Map tokens = ((CreateTokenEvent) event).getTokens(); + for (Iterator> iter = tokens.entrySet().iterator(); iter.hasNext(); ) { + Map.Entry entry = iter.next(); + Token token = entry.getKey(); + if (token.hasSubtype(SubType.CLUE, game) + || token.hasSubtype(SubType.FOOD, game) + || token.hasSubtype(SubType.TREASURE, game)) { + amount += entry.getValue(); + iter.remove(); + } + } + + tokens.put(new ClueArtifactToken(), amount); + tokens.put(new FoodToken(), amount); + tokens.put(new TreasureToken(), amount); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AeveProgenitorOoze.java b/Mage.Sets/src/mage/cards/a/AeveProgenitorOoze.java new file mode 100644 index 00000000000..4afd352c443 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AeveProgenitorOoze.java @@ -0,0 +1,90 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.*; +import mage.abilities.keyword.StormAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; + +/** + * + * @author weirddan455 + */ +public final class AeveProgenitorOoze extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.OOZE); + + static { + filter.add(AnotherPredicate.instance); + } + + public AeveProgenitorOoze(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.OOZE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Storm + this.addAbility(new StormAbility()); + + // Aeve, Progenitor Ooze isn't legendary as long as it's a token. + this.addAbility(new SimpleStaticAbility(new AeveProgenitorOozeNonLegendaryEffect())); + + // Aeve enters the battlefield with a +1/+1 counter on it for each other Ooze you control. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( + CounterType.P1P1.createInstance(), new PermanentsOnBattlefieldCount(filter), true + ), "with a +1/+1 counter on it for each other Ooze you control" + )); + } + + private AeveProgenitorOoze(final AeveProgenitorOoze card) { + super(card); + } + + @Override + public AeveProgenitorOoze copy() { + return new AeveProgenitorOoze(this); + } +} + +class AeveProgenitorOozeNonLegendaryEffect extends ContinuousEffectImpl { + + public AeveProgenitorOozeNonLegendaryEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); + this.staticText = "{this} isn't legendary as long as it's a token"; + } + + private AeveProgenitorOozeNonLegendaryEffect(final AeveProgenitorOozeNonLegendaryEffect effect) { + super(effect); + } + + @Override + public AeveProgenitorOozeNonLegendaryEffect copy() { + return new AeveProgenitorOozeNonLegendaryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent instanceof PermanentToken) { + permanent.getSuperType().remove(SuperType.LEGENDARY); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArcboundJavelineer.java b/Mage.Sets/src/mage/cards/a/ArcboundJavelineer.java new file mode 100644 index 00000000000..9ee1d8e3bb8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArcboundJavelineer.java @@ -0,0 +1,50 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.RemoveVariableCountersSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.ModularAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.target.common.TargetAttackingOrBlockingCreature; + +/** + * + * @author weirddan455 + */ +public final class ArcboundJavelineer extends CardImpl { + + public ArcboundJavelineer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // {T}, Remove X +1/+1 counters from Arcbound Javelineer: It deals X damage to target attacking or blocking creature. + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(GetXValue.instance, "It"), new TapSourceCost()); + ability.addCost(new RemoveVariableCountersSourceCost(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetAttackingOrBlockingCreature()); + this.addAbility(ability); + + // Modular 1 + this.addAbility(new ModularAbility(this, 1)); + } + + private ArcboundJavelineer(final ArcboundJavelineer card) { + super(card); + } + + @Override + public ArcboundJavelineer copy() { + return new ArcboundJavelineer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArcboundPrototype.java b/Mage.Sets/src/mage/cards/a/ArcboundPrototype.java new file mode 100644 index 00000000000..468ac2b1e00 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArcboundPrototype.java @@ -0,0 +1,36 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.keyword.ModularAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArcboundPrototype extends CardImpl { + + public ArcboundPrototype(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.ASSEMBLY_WORKER); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Modular 2 + this.addAbility(new ModularAbility(this, 2)); + } + + private ArcboundPrototype(final ArcboundPrototype card) { + super(card); + } + + @Override + public ArcboundPrototype copy() { + return new ArcboundPrototype(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArcboundSlasher.java b/Mage.Sets/src/mage/cards/a/ArcboundSlasher.java new file mode 100644 index 00000000000..f7e46f4da31 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArcboundSlasher.java @@ -0,0 +1,40 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.keyword.ModularAbility; +import mage.abilities.keyword.RiotAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArcboundSlasher extends CardImpl { + + public ArcboundSlasher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Modular 4 + this.addAbility(new ModularAbility(this, 4)); + + // Riot + this.addAbility(new RiotAbility()); + } + + private ArcboundSlasher(final ArcboundSlasher card) { + super(card); + } + + @Override + public ArcboundSlasher copy() { + return new ArcboundSlasher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArcboundTracker.java b/Mage.Sets/src/mage/cards/a/ArcboundTracker.java new file mode 100644 index 00000000000..bf4ae60c689 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArcboundTracker.java @@ -0,0 +1,85 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.keyword.ModularAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.common.SpellsCastWatcher; + +/** + * + * @author weirddan455 + */ +public final class ArcboundTracker extends CardImpl { + + public ArcboundTracker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.DOG); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Menace + this.addAbility(new MenaceAbility()); + + // Modular 2 + this.addAbility(new ModularAbility(this, 2)); + + // Whenever you cast a spell other than your first spell each turn, put a +1/+1 counter on Arcbound Tracker. + this.addAbility(new ArcboundTrackerTriggeredAbility(), new SpellsCastWatcher()); + } + + private ArcboundTracker(final ArcboundTracker card) { + super(card); + } + + @Override + public ArcboundTracker copy() { + return new ArcboundTracker(this); + } +} + +class ArcboundTrackerTriggeredAbility extends TriggeredAbilityImpl { + + public ArcboundTrackerTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + } + + private ArcboundTrackerTriggeredAbility(final ArcboundTrackerTriggeredAbility ability) { + super(ability); + } + + @Override + public ArcboundTrackerTriggeredAbility copy() { + return new ArcboundTrackerTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getPlayerId().equals(this.getControllerId())) { + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); + return watcher != null && watcher.getSpellsCastThisTurn(event.getPlayerId()).size() > 1; + } + return false; + } + + @Override + public String getRule() { + return "Whenever you cast a spell other than your first spell each turn, " + super.getRule(); + } +} diff --git a/Mage.Sets/src/mage/cards/a/Archaeomancer.java b/Mage.Sets/src/mage/cards/a/Archaeomancer.java index e94afc39c54..7fa14cb6798 100644 --- a/Mage.Sets/src/mage/cards/a/Archaeomancer.java +++ b/Mage.Sets/src/mage/cards/a/Archaeomancer.java @@ -1,25 +1,23 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterInstantOrSorceryCard; -import mage.target.Target; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author North */ public final class Archaeomancer extends CardImpl { - private static final FilterInstantOrSorceryCard filter = new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard"); - public Archaeomancer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); this.subtype.add(SubType.HUMAN); @@ -29,11 +27,8 @@ public final class Archaeomancer extends CardImpl { this.toughness = new MageInt(2); // When Archaeomancer enters the battlefield, return target instant or sorcery card from your graveyard to your hand. - EntersBattlefieldTriggeredAbility ability = new EntersBattlefieldTriggeredAbility( - new ReturnToHandTargetEffect() - .setText("return target instant or sorcery card from your graveyard to your hand"), false); - Target target = new TargetCardInYourGraveyard(filter); - ability.addTarget(target); + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ArchonOfCruelty.java b/Mage.Sets/src/mage/cards/a/ArchonOfCruelty.java new file mode 100644 index 00000000000..e6268c86697 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArchonOfCruelty.java @@ -0,0 +1,56 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArchonOfCruelty extends CardImpl { + + public ArchonOfCruelty(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{B}{B}"); + + this.subtype.add(SubType.ARCHON); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Archon of Cruelty enters the battlefield or attacks, target opponent sacrifices a creature or planeswalker, discards a card, and loses 3 life. You draw a card and gain 3 life. + Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new SacrificeEffect( + StaticFilters.FILTER_PERMANENT_CREATURE_OR_PLANESWALKER_A, 1, "target opponent" + )); + ability.addTarget(new TargetOpponent()); + ability.addEffect(new DiscardTargetEffect(1, false).setText(", discards a card")); + ability.addEffect(new LoseLifeTargetEffect(3).setText(", and loses 3 life.")); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("You")); + ability.addEffect(new GainLifeEffect(3).setText("and gain 3 life")); + this.addAbility(ability); + } + + private ArchonOfCruelty(final ArchonOfCruelty card) { + super(card); + } + + @Override + public ArchonOfCruelty copy() { + return new ArchonOfCruelty(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArcusAcolyte.java b/Mage.Sets/src/mage/cards/a/ArcusAcolyte.java new file mode 100644 index 00000000000..0ae973f2d09 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArcusAcolyte.java @@ -0,0 +1,66 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.OutlastAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArcusAcolyte extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("creature you control without a +1/+1 counter on it"); + + static { + filter.add(CounterType.P1P1.getPredicate()); + } + + public ArcusAcolyte(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.subtype.add(SubType.ARCHER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Outlast {G/W} + this.addAbility(new OutlastAbility(new ManaCostsImpl<>("{G/W}"))); + + // Each other creature you control without a +1/+1 counter on it has outlast {G/W}. + this.addAbility(new SimpleStaticAbility(new GainAbilityAllEffect( + new OutlastAbility(new ManaCostsImpl<>("{G/W}")), + Duration.WhileOnBattlefield, filter, true + ))); + } + + private ArcusAcolyte(final ArcusAcolyte card) { + super(card); + } + + @Override + public ArcusAcolyte copy() { + return new ArcusAcolyte(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AscendantEvincar.java b/Mage.Sets/src/mage/cards/a/AscendantEvincar.java index 6b96ef15b5b..f46913cde98 100644 --- a/Mage.Sets/src/mage/cards/a/AscendantEvincar.java +++ b/Mage.Sets/src/mage/cards/a/AscendantEvincar.java @@ -31,6 +31,7 @@ public final class AscendantEvincar extends CardImpl { public AscendantEvincar(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.VAMPIRE); this.subtype.add(SubType.NOBLE); diff --git a/Mage.Sets/src/mage/cards/a/Asmoranomardicadaistinaculdacar.java b/Mage.Sets/src/mage/cards/a/Asmoranomardicadaistinaculdacar.java index 633d44dec74..def750d9b3c 100644 --- a/Mage.Sets/src/mage/cards/a/Asmoranomardicadaistinaculdacar.java +++ b/Mage.Sets/src/mage/cards/a/Asmoranomardicadaistinaculdacar.java @@ -4,28 +4,29 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.condition.Condition; +import mage.abilities.condition.common.ControllerDiscardedThisTurnCondition; import mage.abilities.costs.AlternativeCostSourceAbility; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.hint.common.ControllerDiscardedHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterCard; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; -import mage.watchers.Watcher; +import mage.watchers.common.DiscardedCardWatcher; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; /** @@ -53,9 +54,9 @@ public final class Asmoranomardicadaistinaculdacar extends CardImpl { // As long as you've discarded a card this turn, you may pay {B/R} to cast this spell. this.addAbility(new AlternativeCostSourceAbility( - new ManaCostsImpl<>("{B/R}"), AsmoranomardicadaistinaculdacarCondition.instance, + new ManaCostsImpl<>("{B/R}"), ControllerDiscardedThisTurnCondition.instance, "as long as you've discarded a card this turn, you may pay {B/R} to cast this spell" - ), new AsmoranomardicadaistinaculdacarWatcher()); + ).addHint(ControllerDiscardedHint.instance), new DiscardedCardWatcher()); // When Asmoranomardicadaistinaculdacar enters the battlefield, you may search your library for a card named The Underworld Cookbook, reveal it, put it into your hand, then shuffle. this.addAbility(new EntersBattlefieldTriggeredAbility( @@ -81,15 +82,6 @@ public final class Asmoranomardicadaistinaculdacar extends CardImpl { } } -enum AsmoranomardicadaistinaculdacarCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - return AsmoranomardicadaistinaculdacarWatcher.checkPlayer(source.getControllerId(), game); - } -} - class AsmoranomardicadaistinaculdacarEffect extends OneShotEffect { AsmoranomardicadaistinaculdacarEffect() { @@ -115,32 +107,4 @@ class AsmoranomardicadaistinaculdacarEffect extends OneShotEffect { return permanent.damage(6, permanent.getId(), source, game) > 0; } } - -class AsmoranomardicadaistinaculdacarWatcher extends Watcher { - - private final Set playerSet = new HashSet<>(); - - AsmoranomardicadaistinaculdacarWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.DISCARDED_CARD) { - playerSet.add(event.getPlayerId()); - } - } - - @Override - public void reset() { - playerSet.clear(); - super.reset(); - } - - static boolean checkPlayer(UUID playerId, Game game) { - AsmoranomardicadaistinaculdacarWatcher watcher - = game.getState().getWatcher(AsmoranomardicadaistinaculdacarWatcher.class); - return watcher != null && watcher.playerSet.contains(playerId); - } -} // it's easier to pronounce if you break it into separate words: asmorano mardica daistina culdacar diff --git a/Mage.Sets/src/mage/cards/a/AtraxaPraetorsVoice.java b/Mage.Sets/src/mage/cards/a/AtraxaPraetorsVoice.java index 25630ea70c3..ac56e824285 100644 --- a/Mage.Sets/src/mage/cards/a/AtraxaPraetorsVoice.java +++ b/Mage.Sets/src/mage/cards/a/AtraxaPraetorsVoice.java @@ -26,6 +26,7 @@ public final class AtraxaPraetorsVoice extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}{U}{B}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ANGEL); this.subtype.add(SubType.HORROR); this.power = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/b/BannerhideKrushok.java b/Mage.Sets/src/mage/cards/b/BannerhideKrushok.java new file mode 100644 index 00000000000..4ef5cba1cdb --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BannerhideKrushok.java @@ -0,0 +1,45 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.keyword.ReinforceAbility; +import mage.abilities.keyword.ScavengeAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BannerhideKrushok extends CardImpl { + + public BannerhideKrushok(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Reinforce 2—{1}{G} + this.addAbility(new ReinforceAbility(2, new ManaCostsImpl<>("{1}{G}"))); + + // Scavenge {5}{G}{G} + this.addAbility(new ScavengeAbility(new ManaCostsImpl<>("{5}{G}{G}"))); + } + + private BannerhideKrushok(final BannerhideKrushok card) { + super(card); + } + + @Override + public BannerhideKrushok copy() { + return new BannerhideKrushok(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BarbedSpike.java b/Mage.Sets/src/mage/cards/b/BarbedSpike.java new file mode 100644 index 00000000000..dd91d3419d2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BarbedSpike.java @@ -0,0 +1,46 @@ +package mage.cards.b; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenAttachSourceEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.ThopterColorlessToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BarbedSpike extends CardImpl { + + public BarbedSpike(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}"); + + this.subtype.add(SubType.EQUIPMENT); + + // When Barbed Spike enters the battlefield, create a 1/1 colorless Thopter artifact creature token with flying and attach Barbed Spike to it. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenAttachSourceEffect(new ThopterColorlessToken()) + )); + + // Equipped creature gets +1/+0. + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect(1, 0))); + + // Equip {2} + this.addAbility(new EquipAbility(1)); + } + + private BarbedSpike(final BarbedSpike card) { + super(card); + } + + @Override + public BarbedSpike copy() { + return new BarbedSpike(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/Batterbone.java b/Mage.Sets/src/mage/cards/b/Batterbone.java new file mode 100644 index 00000000000..a0c982d36a5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/Batterbone.java @@ -0,0 +1,54 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.LivingWeaponAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Batterbone extends CardImpl { + + public Batterbone(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Living weapon + this.addAbility(new LivingWeaponAbility()); + + // Equipped creature gets +1/+1 and has vigilance and lifelink. + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(1, 1)); + ability.addEffect(new GainAbilityAttachedEffect( + VigilanceAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has vigilance")); + ability.addEffect(new GainAbilityAttachedEffect( + LifelinkAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and lifelink")); + this.addAbility(ability); + + // Equip {5} + this.addAbility(new EquipAbility(5)); + } + + private Batterbone(final Batterbone card) { + super(card); + } + + @Override + public Batterbone copy() { + return new Batterbone(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BelbeCorruptedObserver.java b/Mage.Sets/src/mage/cards/b/BelbeCorruptedObserver.java index cc9397a6a84..d64c9f5b040 100644 --- a/Mage.Sets/src/mage/cards/b/BelbeCorruptedObserver.java +++ b/Mage.Sets/src/mage/cards/b/BelbeCorruptedObserver.java @@ -30,6 +30,7 @@ public final class BelbeCorruptedObserver extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{G}"); this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.ELF); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/b/BlackcleaveGoblin.java b/Mage.Sets/src/mage/cards/b/BlackcleaveGoblin.java index 2a082859599..7d14dbaeeb0 100644 --- a/Mage.Sets/src/mage/cards/b/BlackcleaveGoblin.java +++ b/Mage.Sets/src/mage/cards/b/BlackcleaveGoblin.java @@ -19,7 +19,7 @@ public final class BlackcleaveGoblin extends CardImpl { public BlackcleaveGoblin (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); - this.subtype.add(SubType.GOBLIN, SubType.ZOMBIE); + this.subtype.add(SubType.PHYREXIAN, SubType.GOBLIN, SubType.ZOMBIE); this.power = new MageInt(2); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/b/BlacksmithsSkill.java b/Mage.Sets/src/mage/cards/b/BlacksmithsSkill.java new file mode 100644 index 00000000000..ad83eeceacd --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlacksmithsSkill.java @@ -0,0 +1,74 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BlacksmithsSkill extends CardImpl { + + public BlacksmithsSkill(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + // Target permanent gains hexproof and indestructible until end of turn. If it's an artifact creature, it gets +2/+2 until end of turn. + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + HexproofAbility.getInstance(), Duration.EndOfTurn + ).setText("target permanent gains hexproof")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn + ).setText("and indestructible until end of turn.")); + this.getSpellAbility().addEffect(new BlacksmithsSkillEffect()); + this.getSpellAbility().addTarget(new TargetPermanent()); + } + + private BlacksmithsSkill(final BlacksmithsSkill card) { + super(card); + } + + @Override + public BlacksmithsSkill copy() { + return new BlacksmithsSkill(this); + } +} + +class BlacksmithsSkillEffect extends OneShotEffect { + + BlacksmithsSkillEffect() { + super(Outcome.Benefit); + staticText = "If it's an artifact creature, it gets +2/+2 until end of turn"; + } + + private BlacksmithsSkillEffect(final BlacksmithsSkillEffect effect) { + super(effect); + } + + @Override + public BlacksmithsSkillEffect copy() { + return new BlacksmithsSkillEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null && permanent.isArtifact() && permanent.isCreature()) { + game.addEffect(new BoostTargetEffect(2, 2), source); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BladeSplicer.java b/Mage.Sets/src/mage/cards/b/BladeSplicer.java index 6f4e3f02bf2..3fd48e080cf 100644 --- a/Mage.Sets/src/mage/cards/b/BladeSplicer.java +++ b/Mage.Sets/src/mage/cards/b/BladeSplicer.java @@ -13,7 +13,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.game.permanent.token.GolemToken; +import mage.game.permanent.token.PhyrexianGolemToken; import java.util.UUID; @@ -30,13 +30,13 @@ public final class BladeSplicer extends CardImpl { public BladeSplicer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); - this.subtype.add(SubType.HUMAN, SubType.ARTIFICER); + this.subtype.add(SubType.PHYREXIAN, SubType.HUMAN, SubType.ARTIFICER); this.power = new MageInt(1); this.toughness = new MageInt(1); // When Blade Splicer enters the battlefield, create a 3/3 colorless Golem artifact creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GolemToken()))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new PhyrexianGolemToken()))); // Golem creatures you control have first strike. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield, filter))); diff --git a/Mage.Sets/src/mage/cards/b/BlessedRespite.java b/Mage.Sets/src/mage/cards/b/BlessedRespite.java new file mode 100644 index 00000000000..a34c207eb7b --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlessedRespite.java @@ -0,0 +1,69 @@ +package mage.cards.b; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.PreventAllDamageByAllPermanentsEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author weirddan455 + */ +public final class BlessedRespite extends CardImpl { + + public BlessedRespite(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // Target player shuffles their graveyard into their library. Prevent all combat damage that would be dealt this turn. + this.getSpellAbility().addEffect(new BlessedRespiteEffect()); + this.getSpellAbility().addEffect(new PreventAllDamageByAllPermanentsEffect(Duration.EndOfTurn, true)); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + private BlessedRespite(final BlessedRespite card) { + super(card); + } + + @Override + public BlessedRespite copy() { + return new BlessedRespite(this); + } +} + +class BlessedRespiteEffect extends OneShotEffect { + + public BlessedRespiteEffect() { + super(Outcome.Detriment); + this.staticText = "Target player shuffles their graveyard into their library"; + } + + private BlessedRespiteEffect(final BlessedRespiteEffect effect) { + super(effect); + } + + @Override + public BlessedRespiteEffect copy() { + return new BlessedRespiteEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (targetPlayer != null) { + targetPlayer.moveCards(targetPlayer.getGraveyard(), Zone.LIBRARY, source, game); + targetPlayer.shuffleLibrary(source, game); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BlightMamba.java b/Mage.Sets/src/mage/cards/b/BlightMamba.java index 964a14c77fa..cf38c80e717 100644 --- a/Mage.Sets/src/mage/cards/b/BlightMamba.java +++ b/Mage.Sets/src/mage/cards/b/BlightMamba.java @@ -22,6 +22,7 @@ public final class BlightMamba extends CardImpl { public BlightMamba (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SNAKE); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/b/BlightedAgent.java b/Mage.Sets/src/mage/cards/b/BlightedAgent.java index 6cd007c0039..5b464c142e6 100644 --- a/Mage.Sets/src/mage/cards/b/BlightedAgent.java +++ b/Mage.Sets/src/mage/cards/b/BlightedAgent.java @@ -18,7 +18,7 @@ public final class BlightedAgent extends CardImpl { public BlightedAgent(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); - this.subtype.add(SubType.HUMAN, SubType.ROGUE); + this.subtype.add(SubType.PHYREXIAN, SubType.HUMAN, SubType.ROGUE); this.power = new MageInt(1); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/b/BlightsteelColossus.java b/Mage.Sets/src/mage/cards/b/BlightsteelColossus.java index 63116f1032b..b7aa7b2d4b1 100644 --- a/Mage.Sets/src/mage/cards/b/BlightsteelColossus.java +++ b/Mage.Sets/src/mage/cards/b/BlightsteelColossus.java @@ -21,6 +21,7 @@ public final class BlightsteelColossus extends CardImpl { public BlightsteelColossus(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{12}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.GOLEM); this.power = new MageInt(11); this.toughness = new MageInt(11); diff --git a/Mage.Sets/src/mage/cards/b/Blightwidow.java b/Mage.Sets/src/mage/cards/b/Blightwidow.java index c7080e60473..613b4ad8371 100644 --- a/Mage.Sets/src/mage/cards/b/Blightwidow.java +++ b/Mage.Sets/src/mage/cards/b/Blightwidow.java @@ -19,6 +19,7 @@ public final class Blightwidow extends CardImpl { public Blightwidow (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SPIDER); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/b/BlindZealot.java b/Mage.Sets/src/mage/cards/b/BlindZealot.java index 9125da73273..0ea2d5210c5 100644 --- a/Mage.Sets/src/mage/cards/b/BlindZealot.java +++ b/Mage.Sets/src/mage/cards/b/BlindZealot.java @@ -30,7 +30,7 @@ public final class BlindZealot extends CardImpl { public BlindZealot(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); - this.subtype.add(SubType.HUMAN, SubType.CLERIC); + this.subtype.add(SubType.PHYREXIAN, SubType.HUMAN, SubType.CLERIC); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/b/BlindingSouleater.java b/Mage.Sets/src/mage/cards/b/BlindingSouleater.java index 2f3eced177d..b2e51005868 100644 --- a/Mage.Sets/src/mage/cards/b/BlindingSouleater.java +++ b/Mage.Sets/src/mage/cards/b/BlindingSouleater.java @@ -23,6 +23,7 @@ public final class BlindingSouleater extends CardImpl { public BlindingSouleater(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/b/Blistergrub.java b/Mage.Sets/src/mage/cards/b/Blistergrub.java index 198b9e0537a..99b4069cff3 100644 --- a/Mage.Sets/src/mage/cards/b/Blistergrub.java +++ b/Mage.Sets/src/mage/cards/b/Blistergrub.java @@ -20,6 +20,7 @@ public final class Blistergrub extends CardImpl { public Blistergrub (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/b/BloodbraidMarauder.java b/Mage.Sets/src/mage/cards/b/BloodbraidMarauder.java new file mode 100644 index 00000000000..60fbd087b47 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BloodbraidMarauder.java @@ -0,0 +1,59 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.CantBlockAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.DeliriumCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.CardTypesInGraveyardHint; +import mage.abilities.keyword.CascadeAbility; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +/** + * + * @author weirddan455 + */ +public final class BloodbraidMarauder extends CardImpl { + + private static final String REMINDER_TEXT = " (When you cast this spell, " + + "exile cards from the top of your library until you exile a " + + "nonland card whose mana value is less than this spell's mana value. " + + "You may cast that spell without paying its mana cost " + + "if its mana value is less than this spell's mana value. " + + "Then put all cards exiled this way that weren't cast on the bottom of your library in a random order.)"; + + public BloodbraidMarauder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.BERSERKER); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Bloodbraid Marauder can't block. + this.addAbility(new CantBlockAbility()); + + // Delirium — This spell has cascade as long as there are four or more card types among cards in your graveyard. + this.addAbility(new SimpleStaticAbility(Zone.STACK, new ConditionalContinuousEffect( + new GainAbilitySourceEffect(new CascadeAbility(), Duration.WhileOnStack, true), + DeliriumCondition.instance, + "Delirium — This spell has cascade as long as there are four or more card types among cards in your graveyard." + REMINDER_TEXT + )).addHint(CardTypesInGraveyardHint.YOU)); + } + + private BloodbraidMarauder(final BloodbraidMarauder card) { + super(card); + } + + @Override + public BloodbraidMarauder copy() { + return new BloodbraidMarauder(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BlossomingCalm.java b/Mage.Sets/src/mage/cards/b/BlossomingCalm.java new file mode 100644 index 00000000000..dbdfc171051 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlossomingCalm.java @@ -0,0 +1,40 @@ +package mage.cards.b; + +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.ReboundAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BlossomingCalm extends CardImpl { + + public BlossomingCalm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + // You gain hexproof until your next turn. You gain 2 life. + this.getSpellAbility().addEffect(new GainAbilityControllerEffect( + HexproofAbility.getInstance(), Duration.UntilYourNextTurn + ).setText("you gain hexproof until your next turn.")); + this.getSpellAbility().addEffect(new GainLifeEffect(2)); + + // Rebound + this.addAbility(new ReboundAbility()); + } + + private BlossomingCalm(final BlossomingCalm card) { + super(card); + } + + @Override + public BlossomingCalm copy() { + return new BlossomingCalm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BodySnatcher.java b/Mage.Sets/src/mage/cards/b/BodySnatcher.java index d1ed5b3402c..d8cbdaa1022 100644 --- a/Mage.Sets/src/mage/cards/b/BodySnatcher.java +++ b/Mage.Sets/src/mage/cards/b/BodySnatcher.java @@ -28,6 +28,7 @@ public final class BodySnatcher extends CardImpl { public BodySnatcher(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.MINION); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/b/BoneShredder.java b/Mage.Sets/src/mage/cards/b/BoneShredder.java index c475fcfd148..cbbc3795c26 100644 --- a/Mage.Sets/src/mage/cards/b/BoneShredder.java +++ b/Mage.Sets/src/mage/cards/b/BoneShredder.java @@ -34,6 +34,7 @@ public final class BoneShredder extends CardImpl { public BoneShredder(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.MINION); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/b/BottledCloister.java b/Mage.Sets/src/mage/cards/b/BottledCloister.java index c031230a58d..d64cea6e22f 100644 --- a/Mage.Sets/src/mage/cards/b/BottledCloister.java +++ b/Mage.Sets/src/mage/cards/b/BottledCloister.java @@ -12,7 +12,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.TargetController; import mage.constants.Zone; -import mage.game.ExileZone; import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; @@ -103,12 +102,12 @@ class BottledCloisterReturnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); - Cards cards = new CardsImpl(exileZone); - cards.removeIf(uuid -> !player.getId().equals(game.getOwnerId(uuid))); - if (!cards.isEmpty()) { - player.moveCards(cards, Zone.HAND, source, game); + if (player == null) { + return false; } + Cards cards = new CardsImpl(game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)).getCards(game)); + cards.removeIf(uuid -> !player.getId().equals(game.getOwnerId(uuid))); + player.moveCards(cards, Zone.HAND, source, game); player.drawCards(1, source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/b/BreakTheIce.java b/Mage.Sets/src/mage/cards/b/BreakTheIce.java new file mode 100644 index 00000000000..172b63c99da --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BreakTheIce.java @@ -0,0 +1,66 @@ +package mage.cards.b; + +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.OverloadAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ManaType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BreakTheIce extends CardImpl { + + private static final FilterPermanent filter + = new FilterLandPermanent("land that is snow or could produce {C}"); + + static { + filter.add(BreakTheIcePredicate.instance); + } + + public BreakTheIce(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}{B}"); + + // Destroy target land that is snow or could produce {C}. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + + // Overload {4}{B}{B} + this.addAbility(new OverloadAbility(this, new DestroyAllEffect(filter), new ManaCostsImpl<>("{4}{B}{B}"))); + } + + private BreakTheIce(final BreakTheIce card) { + super(card); + } + + @Override + public BreakTheIce copy() { + return new BreakTheIce(this); + } +} + +enum BreakTheIcePredicate implements Predicate { + instance; + + @Override + public boolean apply(Permanent input, Game game) { + return input.isSnow() + || input + .getAbilities() + .getActivatedManaAbilities(Zone.BATTLEFIELD) + .stream() + .anyMatch(ability -> ability.getProducableManaTypes(game).contains(ManaType.COLORLESS)); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BreathlessKnight.java b/Mage.Sets/src/mage/cards/b/BreathlessKnight.java new file mode 100644 index 00000000000..50c3dca10bc --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BreathlessKnight.java @@ -0,0 +1,96 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.common.CastFromGraveyardWatcher; + +/** + * + * @author weirddan455 + */ +public final class BreathlessKnight extends CardImpl { + + public BreathlessKnight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{B}"); + + this.subtype.add(SubType.SPIRIT); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Whenever Breathless Knight or another creature enters the battlefield under your control, if that creature entered from a graveyard or you cast it from a graveyard, put a +1/+1 counter on Breathless Knight. + this.addAbility(new BreathlessKnightTriggeredAbility(), new CastFromGraveyardWatcher()); + } + + private BreathlessKnight(final BreathlessKnight card) { + super(card); + } + + @Override + public BreathlessKnight copy() { + return new BreathlessKnight(this); + } +} + +class BreathlessKnightTriggeredAbility extends TriggeredAbilityImpl { + + public BreathlessKnightTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + } + + private BreathlessKnightTriggeredAbility(final BreathlessKnightTriggeredAbility ability) { + super(ability); + } + + @Override + public BreathlessKnightTriggeredAbility copy() { + return new BreathlessKnightTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event instanceof EntersTheBattlefieldEvent) { + EntersTheBattlefieldEvent entersEvent = (EntersTheBattlefieldEvent) event; + Permanent permanent = entersEvent.getTarget(); + if (permanent != null && permanent.isCreature() && permanent.isControlledBy(this.getControllerId())) { + if (entersEvent.getFromZone() == Zone.GRAVEYARD) { + return true; + } + CastFromGraveyardWatcher watcher = game.getState().getWatcher(CastFromGraveyardWatcher.class); + int zcc = game.getState().getZoneChangeCounter(entersEvent.getSourceId()); + return watcher != null && watcher.spellWasCastFromGraveyard(entersEvent.getSourceId(), zcc - 1); + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever {this} or another creature enters the battlefield under your control, if that creature entered from a graveyard or you cast it from a graveyard, " + super.getRule(); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java b/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java index 1e5f6d5a707..dfff1b8ab04 100644 --- a/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java +++ b/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java @@ -38,6 +38,7 @@ public final class BrudicladTelchorEngineer extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{U}{R}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ARTIFICER); this.power = new MageInt(4); this.toughness = new MageInt(4); @@ -69,7 +70,7 @@ class BrudicladTelchorEngineerEffect extends OneShotEffect { public BrudicladTelchorEngineerEffect() { super(Outcome.Sacrifice); - this.staticText = " create a 2/1 blue Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token"; + this.staticText = " create a 2/1 blue Phyrexian Myr artifact creature token. Then you may choose a token you control. If you do, each other token you control becomes a copy of that token"; } public BrudicladTelchorEngineerEffect(final BrudicladTelchorEngineerEffect effect) { diff --git a/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java b/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java index 9c35e700144..c5e1ef23a76 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java +++ b/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java @@ -36,6 +36,7 @@ public final class BrutalizerExarch extends CardImpl { public BrutalizerExarch(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/b/BurdenedAerialist.java b/Mage.Sets/src/mage/cards/b/BurdenedAerialist.java new file mode 100644 index 00000000000..70d3101c25d --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BurdenedAerialist.java @@ -0,0 +1,54 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SacrificePermanentTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.TreasureToken; + +/** + * + * @author weirddan455 + */ +public final class BurdenedAerialist extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("a token"); + + static { + filter.add(TokenPredicate.instance); + } + + public BurdenedAerialist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PIRATE); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // When Burdened Aerialist enters the battlefield, create a Treasure token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new TreasureToken()))); + + // Whenever you sacrifice a token, Burdened Aerialist gains flying until end of turn. + this.addAbility(new SacrificePermanentTriggeredAbility(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), filter)); + } + + private BurdenedAerialist(final BurdenedAerialist card) { + super(card); + } + + @Override + public BurdenedAerialist copy() { + return new BurdenedAerialist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CabalInitiate.java b/Mage.Sets/src/mage/cards/c/CabalInitiate.java new file mode 100644 index 00000000000..d227202ae31 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CabalInitiate.java @@ -0,0 +1,53 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.CardsInControllerGraveyardCondition; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.constants.AbilityWord; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author weirddan455 + */ +public final class CabalInitiate extends CardImpl { + + public CabalInitiate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARLOCK); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Discard a card: Cabal Initiate gains lifelink until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn), new DiscardCardCost())); + + // Threshold — Cabal Initiate gets +1/+2 as long as seven or more cards are in your graveyard. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(1, 2, Duration.WhileOnBattlefield), + new CardsInControllerGraveyardCondition(7), + "{this} gets +1/+2 as long as seven or more cards are in your graveyard" + )).setAbilityWord(AbilityWord.THRESHOLD)); + } + + private CabalInitiate(final CabalInitiate card) { + super(card); + } + + @Override + public CabalInitiate copy() { + return new CabalInitiate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CallToMind.java b/Mage.Sets/src/mage/cards/c/CallToMind.java index f253ed5412d..70f254a9447 100644 --- a/Mage.Sets/src/mage/cards/c/CallToMind.java +++ b/Mage.Sets/src/mage/cards/c/CallToMind.java @@ -1,27 +1,25 @@ - - package mage.cards.c; -import java.util.UUID; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class CallToMind extends CardImpl { public CallToMind(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}"); // Return target instant or sorcery card from your graveyard to your hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); } private CallToMind(final CallToMind card) { diff --git a/Mage.Sets/src/mage/cards/c/CaptainRipleyVance.java b/Mage.Sets/src/mage/cards/c/CaptainRipleyVance.java new file mode 100644 index 00000000000..aff5da06d64 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CaptainRipleyVance.java @@ -0,0 +1,85 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetAnyTarget; +import mage.watchers.common.SpellsCastWatcher; + +/** + * + * @author weirddan455 + */ +public final class CaptainRipleyVance extends CardImpl { + + public CaptainRipleyVance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.PIRATE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever you cast your third spell each turn, put a +1/+1 counter on Captain Ripley Vance, then it deals damage equal to its power to any target. + this.addAbility(new CaptainRipleyVanceTriggeredAbility(), new SpellsCastWatcher()); + } + + private CaptainRipleyVance(final CaptainRipleyVance card) { + super(card); + } + + @Override + public CaptainRipleyVance copy() { + return new CaptainRipleyVance(this); + } +} + +class CaptainRipleyVanceTriggeredAbility extends TriggeredAbilityImpl { + + public CaptainRipleyVanceTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + addEffect(new DamageTargetEffect(new SourcePermanentPowerCount()).setText("it deals damage equal to its power to any target").concatBy(", then")); + addTarget(new TargetAnyTarget()); + } + + private CaptainRipleyVanceTriggeredAbility(final CaptainRipleyVanceTriggeredAbility ability) { + super(ability); + } + + @Override + public CaptainRipleyVanceTriggeredAbility copy() { + return new CaptainRipleyVanceTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getPlayerId().equals(this.getControllerId())) { + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); + return watcher != null && watcher.getSpellsCastThisTurn(this.getControllerId()).size() == 3; + } + return false; + } + + @Override + public String getRule() { + return "Whenever you cast your third spell each turn, " + super.getRule(); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CapturedByLagacs.java b/Mage.Sets/src/mage/cards/c/CapturedByLagacs.java new file mode 100644 index 00000000000..e0b0c66e398 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CapturedByLagacs.java @@ -0,0 +1,52 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.combat.CantAttackBlockAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.SupportAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CapturedByLagacs extends CardImpl { + + public CapturedByLagacs(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}{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 can't attack or block. + this.addAbility(new SimpleStaticAbility(new CantAttackBlockAttachedEffect(AttachmentType.AURA))); + + // When Captured by Lagacs enters the battlefield, support 2. + this.addAbility(new SupportAbility(this, 2, false)); + } + + private CapturedByLagacs(final CapturedByLagacs card) { + super(card); + } + + @Override + public CapturedByLagacs copy() { + return new CapturedByLagacs(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CarnifexDemon.java b/Mage.Sets/src/mage/cards/c/CarnifexDemon.java index 93b6260494c..54c845eb5b1 100644 --- a/Mage.Sets/src/mage/cards/c/CarnifexDemon.java +++ b/Mage.Sets/src/mage/cards/c/CarnifexDemon.java @@ -33,6 +33,7 @@ public final class CarnifexDemon extends CardImpl { public CarnifexDemon(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DEMON); this.power = new MageInt(6); diff --git a/Mage.Sets/src/mage/cards/c/CathedralMembrane.java b/Mage.Sets/src/mage/cards/c/CathedralMembrane.java index 5eefc5d5c80..65c6e374de8 100644 --- a/Mage.Sets/src/mage/cards/c/CathedralMembrane.java +++ b/Mage.Sets/src/mage/cards/c/CathedralMembrane.java @@ -25,6 +25,7 @@ public final class CathedralMembrane extends CardImpl { public CathedralMembrane(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{W/P}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.WALL); this.power = new MageInt(0); diff --git a/Mage.Sets/src/mage/cards/c/CausticHound.java b/Mage.Sets/src/mage/cards/c/CausticHound.java index f01e20fae40..d714aa07df4 100644 --- a/Mage.Sets/src/mage/cards/c/CausticHound.java +++ b/Mage.Sets/src/mage/cards/c/CausticHound.java @@ -19,6 +19,7 @@ public final class CausticHound extends CardImpl { public CausticHound (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DOG); this.power = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/c/ChainedThroatseeker.java b/Mage.Sets/src/mage/cards/c/ChainedThroatseeker.java index ded5fb991e6..9b7e2601297 100644 --- a/Mage.Sets/src/mage/cards/c/ChainedThroatseeker.java +++ b/Mage.Sets/src/mage/cards/c/ChainedThroatseeker.java @@ -24,6 +24,7 @@ public final class ChainedThroatseeker extends CardImpl { public ChainedThroatseeker(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/c/ChancellorOfTheAnnex.java b/Mage.Sets/src/mage/cards/c/ChancellorOfTheAnnex.java index 7b73033e2cd..4996e9b3651 100644 --- a/Mage.Sets/src/mage/cards/c/ChancellorOfTheAnnex.java +++ b/Mage.Sets/src/mage/cards/c/ChancellorOfTheAnnex.java @@ -32,6 +32,7 @@ public final class ChancellorOfTheAnnex extends CardImpl { public ChancellorOfTheAnnex(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}{W}{W}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ANGEL); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/c/ChancellorOfTheDross.java b/Mage.Sets/src/mage/cards/c/ChancellorOfTheDross.java index bc9632fef5a..b7e0e726090 100644 --- a/Mage.Sets/src/mage/cards/c/ChancellorOfTheDross.java +++ b/Mage.Sets/src/mage/cards/c/ChancellorOfTheDross.java @@ -28,6 +28,7 @@ public final class ChancellorOfTheDross extends CardImpl { public ChancellorOfTheDross(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.VAMPIRE); this.power = new MageInt(6); diff --git a/Mage.Sets/src/mage/cards/c/ChancellorOfTheForge.java b/Mage.Sets/src/mage/cards/c/ChancellorOfTheForge.java index a32905f5ef6..c735aa1cacc 100644 --- a/Mage.Sets/src/mage/cards/c/ChancellorOfTheForge.java +++ b/Mage.Sets/src/mage/cards/c/ChancellorOfTheForge.java @@ -16,8 +16,7 @@ import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.token.GoblinToken; +import mage.game.permanent.token.PhyrexianGoblinToken; import java.util.UUID; @@ -35,6 +34,7 @@ public final class ChancellorOfTheForge extends CardImpl { public ChancellorOfTheForge(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}{R}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.GIANT); this.power = new MageInt(5); @@ -45,7 +45,7 @@ public final class ChancellorOfTheForge extends CardImpl { // When Chancellor of the Forge enters the battlefield, create X 1/1 red Goblin creature tokens with haste, where X is the number of creatures you control. DynamicValue value = new PermanentsOnBattlefieldCount(filter); - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GoblinToken(true), value), false) + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new PhyrexianGoblinToken(), value), false) .addHint(CreaturesYouControlHint.instance)); } @@ -62,7 +62,7 @@ public final class ChancellorOfTheForge extends CardImpl { class ChancellorOfTheForgeDelayedTriggeredAbility extends DelayedTriggeredAbility { ChancellorOfTheForgeDelayedTriggeredAbility() { - super(new CreateTokenEffect(new GoblinToken(true))); + super(new CreateTokenEffect(new PhyrexianGoblinToken())); } ChancellorOfTheForgeDelayedTriggeredAbility(ChancellorOfTheForgeDelayedTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/c/ChancellorOfTheSpires.java b/Mage.Sets/src/mage/cards/c/ChancellorOfTheSpires.java index 75644b9222e..4dad811921b 100644 --- a/Mage.Sets/src/mage/cards/c/ChancellorOfTheSpires.java +++ b/Mage.Sets/src/mage/cards/c/ChancellorOfTheSpires.java @@ -39,6 +39,7 @@ public final class ChancellorOfTheSpires extends CardImpl { public ChancellorOfTheSpires(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SPHINX); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/c/ChancellorOfTheTangle.java b/Mage.Sets/src/mage/cards/c/ChancellorOfTheTangle.java index f925e067cf7..539cb46c070 100644 --- a/Mage.Sets/src/mage/cards/c/ChancellorOfTheTangle.java +++ b/Mage.Sets/src/mage/cards/c/ChancellorOfTheTangle.java @@ -27,6 +27,7 @@ public final class ChancellorOfTheTangle extends CardImpl { public ChancellorOfTheTangle(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}{G}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BEAST); this.color.setGreen(true); diff --git a/Mage.Sets/src/mage/cards/c/ChatterfangSquirrelGeneral.java b/Mage.Sets/src/mage/cards/c/ChatterfangSquirrelGeneral.java new file mode 100644 index 00000000000..519ad331df6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChatterfangSquirrelGeneral.java @@ -0,0 +1,116 @@ +package mage.cards.c; + +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeXTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.constants.*; +import mage.abilities.keyword.ForestwalkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.common.FilterControlledPermanent; +import mage.game.Game; +import mage.game.events.CreateTokenEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.token.SquirrelToken; +import mage.game.permanent.token.Token; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class ChatterfangSquirrelGeneral extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.SQUIRREL, "Squirrels"); + + public ChatterfangSquirrelGeneral(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SQUIRREL); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Forestwalk + this.addAbility(new ForestwalkAbility()); + + // If one or more tokens would be created under your control, those tokens plus that many 1/1 green Squirrel creature tokens are created instead. + this.addAbility(new SimpleStaticAbility(new ChatterfangSquirrelGeneralReplacementEffect())); + + // {B}, Sacrifice X Squirrels: Target creature gets +X/-X until end of turn. + Ability ability = new SimpleActivatedAbility(new BoostTargetEffect( + GetXValue.instance, new SignInversionDynamicValue(GetXValue.instance), Duration.EndOfTurn), + new ManaCostsImpl<>("{B}") + ); + ability.addCost(new SacrificeXTargetCost(filter)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private ChatterfangSquirrelGeneral(final ChatterfangSquirrelGeneral card) { + super(card); + } + + @Override + public ChatterfangSquirrelGeneral copy() { + return new ChatterfangSquirrelGeneral(this); + } +} + +class ChatterfangSquirrelGeneralReplacementEffect extends ReplacementEffectImpl { + + public ChatterfangSquirrelGeneralReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + this.staticText = "If one or more tokens would be created under your control, those tokens plus that many 1/1 green Squirrel creature tokens are created instead"; + } + + private ChatterfangSquirrelGeneralReplacementEffect(final ChatterfangSquirrelGeneralReplacementEffect effect) { + super(effect); + } + + @Override + public ChatterfangSquirrelGeneralReplacementEffect copy() { + return new ChatterfangSquirrelGeneralReplacementEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CREATE_TOKEN; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + if (event instanceof CreateTokenEvent) { + CreateTokenEvent tokenEvent = (CreateTokenEvent) event; + SquirrelToken squirrelToken = null; + int amount = 0; + Map tokens = tokenEvent.getTokens(); + for (Map.Entry entry : tokens.entrySet()) { + amount += entry.getValue(); + if (entry.getKey() instanceof SquirrelToken) { + squirrelToken = (SquirrelToken) entry.getKey(); + } + } + if (squirrelToken == null) { + squirrelToken = new SquirrelToken(); + } + tokens.put(squirrelToken, tokens.getOrDefault(squirrelToken, 0) + amount); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/c/Chitterspitter.java b/Mage.Sets/src/mage/cards/c/Chitterspitter.java new file mode 100644 index 00000000000..1fb9aeca25d --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Chitterspitter.java @@ -0,0 +1,76 @@ +package mage.cards.c; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.SquirrelToken; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author weirddan455 + */ +public final class Chitterspitter extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a token"); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent(SubType.SQUIRREL, "Squirrels"); + + static { + filter.add(TokenPredicate.instance); + } + + public Chitterspitter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{G}"); + + // At the beginning of your upkeep, you may sacrifice a token. If you do, put an acorn counter on Chitterspitter. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new DoIfCostPaid( + new AddCountersSourceEffect(CounterType.ACORN.createInstance()), + new SacrificeTargetCost(new TargetControlledPermanent(filter)) + ), + TargetController.YOU, + false + )); + + // Squirrels you control get +1/+1 for each acorn counter on Chitterspitter. + CountersSourceCount counterValue = new CountersSourceCount(CounterType.ACORN); + this.addAbility(new SimpleStaticAbility( + new BoostControlledEffect(counterValue, counterValue, Duration.WhileOnBattlefield, filter2, false) + )); + + // {G}, {T}: Create a 1/1 green Squirrel creature token. + Ability ability = new SimpleActivatedAbility(new CreateTokenEffect(new SquirrelToken()), new ManaCostsImpl<>("{G}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private Chitterspitter(final Chitterspitter card) { + super(card); + } + + @Override + public Chitterspitter copy() { + return new Chitterspitter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChromeCourier.java b/Mage.Sets/src/mage/cards/c/ChromeCourier.java new file mode 100644 index 00000000000..7ce54a0867e --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChromeCourier.java @@ -0,0 +1,97 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChromeCourier extends CardImpl { + + public ChromeCourier(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{W}{U}"); + + this.subtype.add(SubType.THOPTER); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Chrome Courier enters the battlefield, reveal the top two cards of your library. Put one of them into your hand and the other into your graveyard. If you put an artifact card into your hand this way, you gain 3 life. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ChromeCourierEffect())); + } + + private ChromeCourier(final ChromeCourier card) { + super(card); + } + + @Override + public ChromeCourier copy() { + return new ChromeCourier(this); + } +} + +class ChromeCourierEffect extends OneShotEffect { + + ChromeCourierEffect() { + super(Outcome.Benefit); + staticText = "reveal the top two cards of your library. " + + "Put one of them into your hand and the other into your graveyard. " + + "If you put an artifact card into your hand this way, you gain 3 life"; + } + + private ChromeCourierEffect(final ChromeCourierEffect effect) { + super(effect); + } + + @Override + public ChromeCourierEffect copy() { + return new ChromeCourierEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 2)); + player.revealCards(source, cards, game); + Card card; + switch (cards.size()) { + case 0: + card = null; + break; + case 1: + card = cards.getRandom(game); + break; + default: + TargetCard target = new TargetCardInLibrary(); + target.withChooseHint("to hand"); + player.choose(outcome, cards, target, game); + card = cards.get(target.getFirstTarget(), game); + } + player.moveCards(card, Zone.HAND, source, game); + cards.remove(card); + player.moveCards(cards, Zone.GRAVEYARD, source, game); + if (card != null && card.isArtifact()) { + player.gainLife(3, game, source); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CombineChrysalis.java b/Mage.Sets/src/mage/cards/c/CombineChrysalis.java new file mode 100644 index 00000000000..8885528e5d5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CombineChrysalis.java @@ -0,0 +1,60 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.BeastToken2; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CombineChrysalis extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a token"); + + static { + filter.add(TokenPredicate.instance); + } + + public CombineChrysalis(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{G}{U}"); + + // Creature tokens you control have flying. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + FlyingAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_CREATURE_TOKENS + ))); + + // {2}{G}{U}, {T}, Sacrifice a token: Create a 4/4 green Beast creature token. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + new CreateTokenEffect(new BeastToken2()), new ManaCostsImpl<>("{2}{G}{U}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + this.addAbility(ability); + } + + private CombineChrysalis(final CombineChrysalis card) { + super(card); + } + + @Override + public CombineChrysalis copy() { + return new CombineChrysalis(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CommanderGrevenIlVec.java b/Mage.Sets/src/mage/cards/c/CommanderGrevenIlVec.java index 029fa0b6ea6..e45b2594b01 100644 --- a/Mage.Sets/src/mage/cards/c/CommanderGrevenIlVec.java +++ b/Mage.Sets/src/mage/cards/c/CommanderGrevenIlVec.java @@ -22,6 +22,7 @@ public final class CommanderGrevenIlVec extends CardImpl { public CommanderGrevenIlVec(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}{B}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WARRIOR); diff --git a/Mage.Sets/src/mage/cards/c/ContagiousNim.java b/Mage.Sets/src/mage/cards/c/ContagiousNim.java index 55aefee4dc3..7a1fd057f74 100644 --- a/Mage.Sets/src/mage/cards/c/ContagiousNim.java +++ b/Mage.Sets/src/mage/cards/c/ContagiousNim.java @@ -18,6 +18,7 @@ public final class ContagiousNim extends CardImpl { public ContagiousNim (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/c/ConversionChamber.java b/Mage.Sets/src/mage/cards/c/ConversionChamber.java index 3a3a148c576..2664ecbd125 100644 --- a/Mage.Sets/src/mage/cards/c/ConversionChamber.java +++ b/Mage.Sets/src/mage/cards/c/ConversionChamber.java @@ -14,7 +14,7 @@ import mage.constants.CardType; import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterArtifactCard; -import mage.game.permanent.token.GolemToken; +import mage.game.permanent.token.PhyrexianGolemToken; import mage.target.common.TargetCardInGraveyard; import java.util.UUID; @@ -33,7 +33,7 @@ public final class ConversionChamber extends CardImpl { ability.addCost(new TapSourceCost()); this.addAbility(ability); // {2}, {T}, Remove a charge counter from Conversion Chamber: Create a 3/3 colorless Golem artifact creature token. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new GolemToken()), new GenericManaCost(2)); + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new PhyrexianGolemToken()), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); ability.addCost(new RemoveCountersSourceCost(CounterType.CHARGE.createInstance())); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/c/CoreProwler.java b/Mage.Sets/src/mage/cards/c/CoreProwler.java index 86c1e003a9a..cc6dd6d7140 100644 --- a/Mage.Sets/src/mage/cards/c/CoreProwler.java +++ b/Mage.Sets/src/mage/cards/c/CoreProwler.java @@ -18,6 +18,7 @@ public final class CoreProwler extends CardImpl { public CoreProwler(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/c/CorpseCur.java b/Mage.Sets/src/mage/cards/c/CorpseCur.java index 79144ef43c0..b41f588765f 100644 --- a/Mage.Sets/src/mage/cards/c/CorpseCur.java +++ b/Mage.Sets/src/mage/cards/c/CorpseCur.java @@ -30,6 +30,7 @@ public final class CorpseCur extends CardImpl { public CorpseCur (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DOG); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/c/CorruptedHarvester.java b/Mage.Sets/src/mage/cards/c/CorruptedHarvester.java index 6f52b9eb0a0..41051ae17a3 100644 --- a/Mage.Sets/src/mage/cards/c/CorruptedHarvester.java +++ b/Mage.Sets/src/mage/cards/c/CorruptedHarvester.java @@ -24,6 +24,7 @@ public final class CorruptedHarvester extends CardImpl { public CorruptedHarvester(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(6); diff --git a/Mage.Sets/src/mage/cards/c/CrackOpen.java b/Mage.Sets/src/mage/cards/c/CrackOpen.java new file mode 100644 index 00000000000..fc2afcfb4c6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrackOpen.java @@ -0,0 +1,36 @@ +package mage.cards.c; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.TreasureToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CrackOpen extends CardImpl { + + public CrackOpen(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + // Destroy target artifact or enchantment. Create a Treasure token. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new TreasureToken())); + } + + private CrackOpen(final CrackOpen card) { + super(card); + } + + @Override + public CrackOpen copy() { + return new CrackOpen(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CrazedSkirge.java b/Mage.Sets/src/mage/cards/c/CrazedSkirge.java index a9e63116d89..fa8d1548690 100644 --- a/Mage.Sets/src/mage/cards/c/CrazedSkirge.java +++ b/Mage.Sets/src/mage/cards/c/CrazedSkirge.java @@ -19,6 +19,7 @@ public final class CrazedSkirge extends CardImpl { public CrazedSkirge (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.IMP); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/c/Cystbearer.java b/Mage.Sets/src/mage/cards/c/Cystbearer.java index 1d3efdd69f7..819613649ca 100644 --- a/Mage.Sets/src/mage/cards/c/Cystbearer.java +++ b/Mage.Sets/src/mage/cards/c/Cystbearer.java @@ -19,6 +19,7 @@ public final class Cystbearer extends CardImpl { public Cystbearer(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BEAST); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/d/DarkslickDrake.java b/Mage.Sets/src/mage/cards/d/DarkslickDrake.java index a47db43bfc6..8330fa63a55 100644 --- a/Mage.Sets/src/mage/cards/d/DarkslickDrake.java +++ b/Mage.Sets/src/mage/cards/d/DarkslickDrake.java @@ -20,6 +20,7 @@ public final class DarkslickDrake extends CardImpl { public DarkslickDrake (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DRAKE); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/d/DauthiVoidwalker.java b/Mage.Sets/src/mage/cards/d/DauthiVoidwalker.java new file mode 100644 index 00000000000..22e5531ab44 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DauthiVoidwalker.java @@ -0,0 +1,148 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +import mage.abilities.keyword.ShadowAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.players.Player; +import mage.target.common.TargetCardInExile; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DauthiVoidwalker extends CardImpl { + + public DauthiVoidwalker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}"); + + this.subtype.add(SubType.DAUTHI); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Shadow + this.addAbility(ShadowAbility.getInstance()); + + // If a card would be put into an opponent's graveyard from anywhere, instead exile it with a void counter on it. + this.addAbility(new SimpleStaticAbility(new DauthiVoidwalkerReplacementEffect())); + + // {T}, Sacrifice Dauthi Voidwalker: Choose an exiled card an opponent owns with a void counter on it. You may play it this turn without paying its mana cost. + Ability ability = new SimpleActivatedAbility(new DauthiVoidwalkerPlayEffect(), new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private DauthiVoidwalker(final DauthiVoidwalker card) { + super(card); + } + + @Override + public DauthiVoidwalker copy() { + return new DauthiVoidwalker(this); + } +} + +class DauthiVoidwalkerReplacementEffect extends ReplacementEffectImpl { + + DauthiVoidwalkerReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Exile); + staticText = "if a card would be put into an opponent's graveyard from anywhere, " + + "instead exile it with a void counter on it"; + } + + private DauthiVoidwalkerReplacementEffect(final DauthiVoidwalkerReplacementEffect effect) { + super(effect); + } + + @Override + public DauthiVoidwalkerReplacementEffect copy() { + return new DauthiVoidwalkerReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(event.getTargetId()); + if (player == null || card == null) { + return false; + } + player.moveCards(card, Zone.EXILED, source, game); + card.addCounters(CounterType.VOID.createInstance(), source.getControllerId(), source, game); + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD + && game.getOpponents(source.getControllerId()).contains(game.getOwnerId(event.getTargetId())); + } +} + +class DauthiVoidwalkerPlayEffect extends OneShotEffect { + + private static final FilterCard filter + = new FilterCard("exiled card an opponent owns with a void counter on it"); + + static { + filter.add(CounterType.VOID.getPredicate()); + filter.add(TargetController.OPPONENT.getOwnerPredicate()); + } + + DauthiVoidwalkerPlayEffect() { + super(Outcome.Benefit); + staticText = "choose an exiled card an opponent owns with a void counter on it. " + + "You may play it this turn without paying its mana cost"; + } + + private DauthiVoidwalkerPlayEffect(final DauthiVoidwalkerPlayEffect effect) { + super(effect); + } + + @Override + public DauthiVoidwalkerPlayEffect copy() { + return new DauthiVoidwalkerPlayEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetCardInExile target = new TargetCardInExile( + 0, 1, filter, null, true + ); + player.choose(outcome, target, source.getSourceId(), game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + game.addEffect(new PlayFromNotOwnHandZoneTargetEffect( + Zone.EXILED, TargetController.YOU, Duration.EndOfTurn, true, false + ).setTargetPointer(new FixedTarget(card, game)), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DeathHoodCobra.java b/Mage.Sets/src/mage/cards/d/DeathHoodCobra.java index fac884a547a..20cb20fc812 100644 --- a/Mage.Sets/src/mage/cards/d/DeathHoodCobra.java +++ b/Mage.Sets/src/mage/cards/d/DeathHoodCobra.java @@ -23,6 +23,7 @@ public final class DeathHoodCobra extends CardImpl { public DeathHoodCobra(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SNAKE); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/d/DeceiverExarch.java b/Mage.Sets/src/mage/cards/d/DeceiverExarch.java index 8df40e2715a..17746f20aa9 100644 --- a/Mage.Sets/src/mage/cards/d/DeceiverExarch.java +++ b/Mage.Sets/src/mage/cards/d/DeceiverExarch.java @@ -32,6 +32,7 @@ public final class DeceiverExarch extends CardImpl { public DeceiverExarch(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/d/DeepwoodDenizen.java b/Mage.Sets/src/mage/cards/d/DeepwoodDenizen.java new file mode 100644 index 00000000000..bf94d9fe8d8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeepwoodDenizen.java @@ -0,0 +1,98 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.CostAdjuster; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.hint.ValueHint; +import mage.constants.SubType; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +/** + * + * @author weirddan455 + */ +public final class DeepwoodDenizen extends CardImpl { + + public DeepwoodDenizen(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // {5}{G}, {T}: Draw a card. This ability costs {1} less to activate for each +1/+1 counter on creatures you control. + Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{5}{G}")); + ability.addCost(new TapSourceCost()); + ability.addEffect(new InfoEffect("This ability costs {1} less to activate for each +1/+1 counter on creatures you control")); + ability.setCostAdjuster(DeepwoodDenizenAdjuster.instance); + ability.addHint(new ValueHint("+1/+1 counters on creatures you control", DeepwoodDenizenValue.instance)); + this.addAbility(ability); + } + + private DeepwoodDenizen(final DeepwoodDenizen card) { + super(card); + } + + @Override + public DeepwoodDenizen copy() { + return new DeepwoodDenizen(this); + } +} + +enum DeepwoodDenizenAdjuster implements CostAdjuster { + instance; + + @Override + public void adjustCosts(Ability ability, Game game) { + CardUtil.reduceCost(ability, DeepwoodDenizenValue.instance.calculate(game, ability, null)); + } +} + +enum DeepwoodDenizenValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int counters = 0; + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(sourceAbility.getControllerId())) { + if (permanent.isCreature()) { + counters += permanent.getCounters(game).getCount(CounterType.P1P1); + } + } + return counters; + } + + @Override + public DynamicValue copy() { + return instance; + } + + @Override + public String getMessage() { + return "+1/+1 counter on creatures you control"; + } + + @Override + public String toString() { + return "X"; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DementiaBat.java b/Mage.Sets/src/mage/cards/d/DementiaBat.java index 26868d3de8d..1c5e09a9ff0 100644 --- a/Mage.Sets/src/mage/cards/d/DementiaBat.java +++ b/Mage.Sets/src/mage/cards/d/DementiaBat.java @@ -23,6 +23,7 @@ public final class DementiaBat extends CardImpl { public DementiaBat(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BAT); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/d/DevouringStrossus.java b/Mage.Sets/src/mage/cards/d/DevouringStrossus.java index 48aabae6397..b43ed0486ec 100644 --- a/Mage.Sets/src/mage/cards/d/DevouringStrossus.java +++ b/Mage.Sets/src/mage/cards/d/DevouringStrossus.java @@ -29,6 +29,7 @@ public final class DevouringStrossus extends CardImpl { public DevouringStrossus(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(9); this.toughness = new MageInt(9); diff --git a/Mage.Sets/src/mage/cards/d/DihadasPloy.java b/Mage.Sets/src/mage/cards/d/DihadasPloy.java new file mode 100644 index 00000000000..8c680cad0ea --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DihadasPloy.java @@ -0,0 +1,71 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.JumpStartAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; +import mage.watchers.common.DiscardedCardWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DihadasPloy extends CardImpl { + + private static final Hint hint = new ValueHint("Cards you've discarded this turn", DihadasPloyValue.instance); + + public DihadasPloy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{B}"); + + // Draw two cards, then discard a card. You gain life equal to the number of cards you've discarded this turn. + this.getSpellAbility().addEffect(new DrawDiscardControllerEffect(2, 1)); + this.getSpellAbility().addEffect(new GainLifeEffect(DihadasPloyValue.instance)); + this.getSpellAbility().addHint(hint); + this.getSpellAbility().addWatcher(new DiscardedCardWatcher()); + + // Jump-start + this.addAbility(new JumpStartAbility(this)); + } + + private DihadasPloy(final DihadasPloy card) { + super(card); + } + + @Override + public DihadasPloy copy() { + return new DihadasPloy(this); + } +} + +enum DihadasPloyValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return DiscardedCardWatcher.getDiscarded(sourceAbility.getControllerId(), game); + } + + @Override + public DihadasPloyValue copy() { + return instance; + } + + @Override + public String getMessage() { + return "1"; + } + + @Override + public String toString() { + return "cards you've discarded this turn"; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DiscipleOfTheSun.java b/Mage.Sets/src/mage/cards/d/DiscipleOfTheSun.java new file mode 100644 index 00000000000..9a36d055345 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DiscipleOfTheSun.java @@ -0,0 +1,56 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DiscipleOfTheSun extends CardImpl { + + private static final FilterCard filter = new FilterPermanentCard("permanent card with mana value 3 or less"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + + public DiscipleOfTheSun(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // When Disciple of the Sun enters the battlefield, return target permanent card with mana value 3 or less from your graveyard to your hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + } + + private DiscipleOfTheSun(final DiscipleOfTheSun card) { + super(card); + } + + @Override + public DiscipleOfTheSun copy() { + return new DiscipleOfTheSun(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DivineVisitation.java b/Mage.Sets/src/mage/cards/d/DivineVisitation.java index d1689f614a7..3d35c6366da 100644 --- a/Mage.Sets/src/mage/cards/d/DivineVisitation.java +++ b/Mage.Sets/src/mage/cards/d/DivineVisitation.java @@ -1,5 +1,7 @@ package mage.cards.d; +import java.util.Iterator; +import java.util.Map; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -14,6 +16,7 @@ import mage.game.Game; import mage.game.events.CreateTokenEvent; import mage.game.events.GameEvent; import mage.game.permanent.token.AngelVigilanceToken; +import mage.game.permanent.token.Token; /** * @@ -62,13 +65,34 @@ class DivineVisitationEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - return event.getPlayerId().equals(source.getControllerId()) - && ((CreateTokenEvent) event).getToken().isCreature(); + if (event instanceof CreateTokenEvent && event.getPlayerId().equals(source.getControllerId())) { + CreateTokenEvent tokenEvent = (CreateTokenEvent) event; + for (Token token : tokenEvent.getTokens().keySet()) { + if (token.isCreature()) { + return true; + } + } + } + return false; } @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - ((CreateTokenEvent) event).setToken(new AngelVigilanceToken()); + if (event instanceof CreateTokenEvent) { + int amount = 0; + CreateTokenEvent tokenEvent = (CreateTokenEvent) event; + Iterator> it = tokenEvent.getTokens().entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + if (entry.getKey().isCreature()) { + amount += entry.getValue(); + it.remove(); + } + } + if (amount > 0) { + tokenEvent.getTokens().put(new AngelVigilanceToken(), amount); + } + } return false; } diff --git a/Mage.Sets/src/mage/cards/d/DoublingSeason.java b/Mage.Sets/src/mage/cards/d/DoublingSeason.java index 471950ef73e..432ea08502d 100644 --- a/Mage.Sets/src/mage/cards/d/DoublingSeason.java +++ b/Mage.Sets/src/mage/cards/d/DoublingSeason.java @@ -9,6 +9,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.game.Game; +import mage.game.events.CreateTokenEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -69,7 +70,9 @@ class DoublingSeasonTokenEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() * 2); + if (event instanceof CreateTokenEvent) { + ((CreateTokenEvent) event).doubleTokens(); + } return false; } diff --git a/Mage.Sets/src/mage/cards/d/DrossHopper.java b/Mage.Sets/src/mage/cards/d/DrossHopper.java index 038ed13d6aa..e6e7436661f 100644 --- a/Mage.Sets/src/mage/cards/d/DrossHopper.java +++ b/Mage.Sets/src/mage/cards/d/DrossHopper.java @@ -24,6 +24,7 @@ public final class DrossHopper extends CardImpl { public DrossHopper(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.INSECT); this.subtype.add(SubType.HORROR); diff --git a/Mage.Sets/src/mage/cards/d/DrossRipper.java b/Mage.Sets/src/mage/cards/d/DrossRipper.java index 836f431631d..76108b2e645 100644 --- a/Mage.Sets/src/mage/cards/d/DrossRipper.java +++ b/Mage.Sets/src/mage/cards/d/DrossRipper.java @@ -22,6 +22,7 @@ public final class DrossRipper extends CardImpl { public DrossRipper (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DOG); this.power = new MageInt(3); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/d/DuskshellCrawler.java b/Mage.Sets/src/mage/cards/d/DuskshellCrawler.java new file mode 100644 index 00000000000..25a79751481 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DuskshellCrawler.java @@ -0,0 +1,59 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author weirddan455 + */ +public final class DuskshellCrawler extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(CounterType.P1P1.getPredicate()); + } + + public DuskshellCrawler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.INSECT); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // When Duskshell Crawler enters the battlefield, put a +1/+1 counter on target creature. + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // Each creature you control with a +1/+1 counter on it has trample. + this.addAbility(new SimpleStaticAbility( + new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter) + .setText("Each creature you control with a +1/+1 counter on it has trample") + )); + } + + private DuskshellCrawler(final DuskshellCrawler card) { + super(card); + } + + @Override + public DuskshellCrawler copy() { + return new DuskshellCrawler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EasternPaladin.java b/Mage.Sets/src/mage/cards/e/EasternPaladin.java index ab42d68cd7e..3175c576afa 100644 --- a/Mage.Sets/src/mage/cards/e/EasternPaladin.java +++ b/Mage.Sets/src/mage/cards/e/EasternPaladin.java @@ -34,6 +34,7 @@ public final class EasternPaladin extends CardImpl { public EasternPaladin(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.KNIGHT); diff --git a/Mage.Sets/src/mage/cards/e/EchoingReturn.java b/Mage.Sets/src/mage/cards/e/EchoingReturn.java new file mode 100644 index 00000000000..3b70cf1ae35 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EchoingReturn.java @@ -0,0 +1,72 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EchoingReturn extends CardImpl { + + public EchoingReturn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); + + // Return target creature card and all other cards with the same name as that card from your graveyard to your hand. + this.getSpellAbility().addEffect(new EchoingReturnEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + } + + private EchoingReturn(final EchoingReturn card) { + super(card); + } + + @Override + public EchoingReturn copy() { + return new EchoingReturn(this); + } +} + +class EchoingReturnEffect extends OneShotEffect { + + EchoingReturnEffect() { + super(Outcome.Benefit); + staticText = "return target creature card and all other cards " + + "with the same name as that card from your graveyard to your hand"; + } + + private EchoingReturnEffect(final EchoingReturnEffect effect) { + super(effect); + } + + @Override + public EchoingReturnEffect copy() { + return new EchoingReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(source.getFirstTarget()); + if (player == null || card == null) { + return false; + } + Cards cards = new CardsImpl(card); + player.getGraveyard() + .getCards(game) + .stream() + .filter(c -> CardUtil.haveSameNames(c.getName(), card.getName())) + .forEach(cards::add); + return player.moveCards(cards, Zone.HAND, source, game); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EleshNornGrandCenobite.java b/Mage.Sets/src/mage/cards/e/EleshNornGrandCenobite.java index ad81a30bfcc..de4a49bb3eb 100644 --- a/Mage.Sets/src/mage/cards/e/EleshNornGrandCenobite.java +++ b/Mage.Sets/src/mage/cards/e/EleshNornGrandCenobite.java @@ -25,6 +25,7 @@ public final class EleshNornGrandCenobite extends CardImpl { public EleshNornGrandCenobite (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{W}{W}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.PRAETOR); this.power = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/e/Endurance.java b/Mage.Sets/src/mage/cards/e/Endurance.java new file mode 100644 index 00000000000..146ea4a203c --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/Endurance.java @@ -0,0 +1,91 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.ExileFromHandCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.EvokeAbility; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInHand; + +/** + * + * @author weirddan455 + */ +public final class Endurance extends CardImpl { + + private static final FilterCard filter = new FilterCard("a green card from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + } + + public Endurance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{G}"); + + this.subtype.add(SubType.ELEMENTAL); + this.subtype.add(SubType.INCARNATION); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // When Endurance enters the battlefield, up to one target player puts all the cards from their graveyard on the bottom of their library in a random order. + Ability ability = new EntersBattlefieldTriggeredAbility(new EnduranceEffect()); + ability.addTarget(new TargetPlayer(0, 1, false)); + this.addAbility(ability); + + // Evoke—Exile a green card from your hand. + this.addAbility(new EvokeAbility(new ExileFromHandCost(new TargetCardInHand(filter)))); + } + + private Endurance(final Endurance card) { + super(card); + } + + @Override + public Endurance copy() { + return new Endurance(this); + } +} + +class EnduranceEffect extends OneShotEffect { + + public EnduranceEffect() { + super(Outcome.Detriment); + this.staticText = "up to one target player puts all the cards from their graveyard on the bottom of their library in a random order"; + } + + private EnduranceEffect(final EnduranceEffect effect) { + super(effect); + } + + @Override + public EnduranceEffect copy() { + return new EnduranceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); + return targetPlayer != null && targetPlayer.putCardsOnBottomOfLibrary(targetPlayer.getGraveyard(), game, source, false); + } +} diff --git a/Mage.Sets/src/mage/cards/e/Entomb.java b/Mage.Sets/src/mage/cards/e/Entomb.java index f7a8bf8f59c..aeff5ad3242 100644 --- a/Mage.Sets/src/mage/cards/e/Entomb.java +++ b/Mage.Sets/src/mage/cards/e/Entomb.java @@ -1,30 +1,22 @@ - package mage.cards.e; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.effects.SearchEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInGraveyardEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; /** - * * @author Plopman */ public final class Entomb extends CardImpl { public Entomb(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); // Search your library for a card and put that card into your graveyard. Then shuffle your library. - this.getSpellAbility().addEffect(new SearchLibraryPutInGraveyard()); + this.getSpellAbility().addEffect(new SearchLibraryPutInGraveyardEffect()); } private Entomb(final Entomb card) { @@ -36,35 +28,3 @@ public final class Entomb extends CardImpl { return new Entomb(this); } } - - -class SearchLibraryPutInGraveyard extends SearchEffect { - - public SearchLibraryPutInGraveyard() { - super(new TargetCardInLibrary(new FilterCard()), Outcome.Neutral); - staticText = "search your library for a card, put that card into your graveyard, then shuffle"; - } - - public SearchLibraryPutInGraveyard(final SearchLibraryPutInGraveyard effect) { - super(effect); - } - - @Override - public SearchLibraryPutInGraveyard copy() { - return new SearchLibraryPutInGraveyard(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - if (controller.searchLibrary(target, source, game)) { - controller.moveCards(game.getCard(target.getFirstTarget()), Zone.GRAVEYARD, source, game); - } - controller.shuffleLibrary(source, game); - return true; - } - -} diff --git a/Mage.Sets/src/mage/cards/e/EntomberExarch.java b/Mage.Sets/src/mage/cards/e/EntomberExarch.java index 47e20164587..e7cec5acdfa 100644 --- a/Mage.Sets/src/mage/cards/e/EntomberExarch.java +++ b/Mage.Sets/src/mage/cards/e/EntomberExarch.java @@ -30,6 +30,7 @@ public final class EntomberExarch extends CardImpl { public EntomberExarch(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/e/ErtaiTheCorrupted.java b/Mage.Sets/src/mage/cards/e/ErtaiTheCorrupted.java index ee0b64a4713..6dbcf1eb89a 100644 --- a/Mage.Sets/src/mage/cards/e/ErtaiTheCorrupted.java +++ b/Mage.Sets/src/mage/cards/e/ErtaiTheCorrupted.java @@ -35,6 +35,7 @@ public final class ErtaiTheCorrupted extends CardImpl { public ErtaiTheCorrupted(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}{U}{B}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/e/EsixFractalBloom.java b/Mage.Sets/src/mage/cards/e/EsixFractalBloom.java index 6f332535606..ccfacd565e1 100644 --- a/Mage.Sets/src/mage/cards/e/EsixFractalBloom.java +++ b/Mage.Sets/src/mage/cards/e/EsixFractalBloom.java @@ -107,7 +107,12 @@ class EsixFractalBloomEffect extends ReplacementEffectImpl { if (permanent == null) { return false; } - ((CreateTokenEvent) event).setToken(copyPermanentToToken(permanent, game, source)); + if (event instanceof CreateTokenEvent) { + CreateTokenEvent tokenEvent = (CreateTokenEvent) event; + int amount = tokenEvent.getAmount(); + tokenEvent.getTokens().clear(); + tokenEvent.getTokens().put(copyPermanentToToken(permanent, game, source), amount); + } return false; } diff --git a/Mage.Sets/src/mage/cards/e/EsperSentinel.java b/Mage.Sets/src/mage/cards/e/EsperSentinel.java new file mode 100644 index 00000000000..2bb832a3331 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EsperSentinel.java @@ -0,0 +1,131 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.costs.Cost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.util.ManaUtil; +import mage.watchers.common.SpellsCastWatcher; + +/** + * + * @author weirddan455 + */ +public final class EsperSentinel extends CardImpl { + + public EsperSentinel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever an opponent casts their first noncreature spell each turn, draw a card unless that player pays {X}, where X is Esper Sentinel's power. + this.addAbility(new EsperSentinelTriggeredAbility(), new SpellsCastWatcher()); + } + + private EsperSentinel(final EsperSentinel card) { + super(card); + } + + @Override + public EsperSentinel copy() { + return new EsperSentinel(this); + } +} + +class EsperSentinelTriggeredAbility extends TriggeredAbilityImpl { + + public EsperSentinelTriggeredAbility() { + super(Zone.BATTLEFIELD, new EsperSentinelEffect()); + } + + private EsperSentinelTriggeredAbility(final EsperSentinelTriggeredAbility ability) { + super(ability); + } + + @Override + public EsperSentinelTriggeredAbility copy() { + return new EsperSentinelTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Player controller = game.getPlayer(getControllerId()); + Spell spell = game.getSpell(event.getTargetId()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); + if (controller != null && spell != null && watcher != null && !spell.isCreature() && controller.hasOpponent(spell.getControllerId(), game)) { + int nonCreatureSpells = 0; + for (Spell spellCastThisTurn : watcher.getSpellsCastThisTurn(spell.getControllerId())) { + if (!spellCastThisTurn.isCreature() && ++nonCreatureSpells > 1) { + break; + } + } + if (nonCreatureSpells == 1) { + for (Effect effect : getEffects()) { + effect.setTargetPointer(new FixedTarget(spell.getControllerId())); + } + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever an opponent casts their first noncreature spell each turn, draw a card unless that player pays {X}, where X is Esper Sentinel's power."; + } +} + +class EsperSentinelEffect extends OneShotEffect { + + public EsperSentinelEffect() { + super(Outcome.DrawCard); + } + + private EsperSentinelEffect(final EsperSentinelEffect effect) { + super(effect); + } + + @Override + public EsperSentinelEffect copy() { + return new EsperSentinelEffect(this); + } + + @Override + public boolean apply (Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); + Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (controller != null && opponent != null && permanent != null) { + Cost cost = ManaUtil.createManaCost(permanent.getPower().getValue(), false); + if (!opponent.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + "?", source, game) + || !cost.pay(source, game, source, opponent.getId(), false)) { + controller.drawCards(1, source, game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EtchedMonstrosity.java b/Mage.Sets/src/mage/cards/e/EtchedMonstrosity.java index 4ff300ff018..d3fd98c5434 100644 --- a/Mage.Sets/src/mage/cards/e/EtchedMonstrosity.java +++ b/Mage.Sets/src/mage/cards/e/EtchedMonstrosity.java @@ -26,6 +26,7 @@ public final class EtchedMonstrosity extends CardImpl { public EtchedMonstrosity(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.GOLEM); this.power = new MageInt(10); this.toughness = new MageInt(10); diff --git a/Mage.Sets/src/mage/cards/e/EtheriumSpinner.java b/Mage.Sets/src/mage/cards/e/EtheriumSpinner.java new file mode 100644 index 00000000000..ab7e8e32652 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EtheriumSpinner.java @@ -0,0 +1,50 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.permanent.token.ThopterColorlessToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EtheriumSpinner extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a spell with mana value 4 or greater"); + + static { + filter.add(new ManaValuePredicate(ComparisonType.MORE_THAN, 3)); + } + + public EtheriumSpinner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Whenever you cast a spell with mana value 4 or greater, create a 1/1 colorless Thopter artifact creature token with flying. + this.addAbility(new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new ThopterColorlessToken()), filter, false + )); + } + + private EtheriumSpinner(final EtheriumSpinner card) { + super(card); + } + + @Override + public EtheriumSpinner copy() { + return new EtheriumSpinner(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EtherswornSphinx.java b/Mage.Sets/src/mage/cards/e/EtherswornSphinx.java new file mode 100644 index 00000000000..e3d1cd94d6f --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EtherswornSphinx.java @@ -0,0 +1,44 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.keyword.AffinityForArtifactsAbility; +import mage.abilities.keyword.CascadeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EtherswornSphinx extends CardImpl { + + public EtherswornSphinx(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{7}{W}{U}"); + + this.subtype.add(SubType.SPHINX); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Affinity for artifacts + this.addAbility(new AffinityForArtifactsAbility()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Cascade + this.addAbility(new CascadeAbility()); + } + + private EtherswornSphinx(final EtherswornSphinx card) { + super(card); + } + + @Override + public EtherswornSphinx copy() { + return new EtherswornSphinx(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/Eviscerator.java b/Mage.Sets/src/mage/cards/e/Eviscerator.java index bd3f38fa161..409c1b25427 100644 --- a/Mage.Sets/src/mage/cards/e/Eviscerator.java +++ b/Mage.Sets/src/mage/cards/e/Eviscerator.java @@ -20,6 +20,7 @@ public final class Eviscerator extends CardImpl { public Eviscerator(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java b/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java index ca7fcb1ec3b..edd8234b6f3 100644 --- a/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java +++ b/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java @@ -39,6 +39,7 @@ public final class EzuriClawOfProgress extends CardImpl { public EzuriClawOfProgress(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ELF); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/e/EzurisPredation.java b/Mage.Sets/src/mage/cards/e/EzurisPredation.java index fd82097d512..3c2b5556728 100644 --- a/Mage.Sets/src/mage/cards/e/EzurisPredation.java +++ b/Mage.Sets/src/mage/cards/e/EzurisPredation.java @@ -14,7 +14,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.game.permanent.token.BeastToken2; +import mage.game.permanent.token.PhyrexianBeastToken; import mage.players.Player; import java.util.HashSet; @@ -48,7 +48,7 @@ class EzurisPredationEffect extends OneShotEffect { public EzurisPredationEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "For each creature your opponents control, create a 4/4 green Beast creature token. Each of those Beasts fights a different one of those creatures"; + this.staticText = "For each creature your opponents control, create a 4/4 green Phyrexian Beast creature token. Each of those Beasts fights a different one of those creatures"; } public EzurisPredationEffect(final EzurisPredationEffect effect) { @@ -81,7 +81,7 @@ class EzurisPredationEffect extends OneShotEffect { List creaturesOfOpponents = game.getBattlefield().getActivePermanents(filterCreature, source.getControllerId(), source.getSourceId(), game); Set morSet = new HashSet<>(); if (!creaturesOfOpponents.isEmpty()) { - CreateTokenEffect effect = new CreateTokenEffect(new BeastToken2(), creaturesOfOpponents.size()); + CreateTokenEffect effect = new CreateTokenEffect(new PhyrexianBeastToken(), creaturesOfOpponents.size()); effect.apply(game, source); for (UUID tokenId : effect.getLastAddedTokenIds()) { Permanent token = game.getPermanent(tokenId); diff --git a/Mage.Sets/src/mage/cards/f/FaeOffering.java b/Mage.Sets/src/mage/cards/f/FaeOffering.java new file mode 100644 index 00000000000..b9941d402ad --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FaeOffering.java @@ -0,0 +1,107 @@ +package mage.cards.f; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.Hint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.game.Game; +import mage.game.permanent.token.ClueArtifactToken; +import mage.game.permanent.token.FoodToken; +import mage.game.permanent.token.TreasureToken; +import mage.game.stack.Spell; +import mage.watchers.common.SpellsCastWatcher; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class FaeOffering extends CardImpl { + + public FaeOffering(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + // At the beginning of each end step, if you've cast both a creature spell and a noncreature spell this turn, create a Clue token, a Food token, and a Treasure token. + Ability ability = new ConditionalInterveningIfTriggeredAbility( + new BeginningOfEndStepTriggeredAbility( + new CreateTokenEffect(new ClueArtifactToken()), TargetController.ANY, false + ), FaeOfferingCondition.instance, "At the beginning of each end step, " + + "if you've cast both a creature spell and a noncreature spell this turn, " + + "create a Clue token, a Food token, and a Treasure token." + ); + ability.addEffect(new CreateTokenEffect(new FoodToken())); + ability.addEffect(new CreateTokenEffect(new TreasureToken())); + this.addAbility(ability.addHint(FaeOfferingHint.instance), new SpellsCastWatcher()); + } + + private FaeOffering(final FaeOffering card) { + super(card); + } + + @Override + public FaeOffering copy() { + return new FaeOffering(this); + } +} + +enum FaeOfferingCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); + if (watcher == null) { + return false; + } + List spells = watcher.getSpellsCastThisTurn(source.getControllerId()); + return spells != null && spells + .stream() + .filter(Objects::nonNull) + .map(MageObject::isCreature) + .distinct() + .count() == 2; + } +} + +enum FaeOfferingHint implements Hint { + instance; + + @Override + public String getText(Game game, Ability ability) { + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); + if (watcher == null) { + return null; + } + List spells = watcher.getSpellsCastThisTurn(ability.getControllerId()); + if (spells == null) { + return null; + } + List messages = spells + .stream() + .filter(Objects::nonNull) + .map(MageObject::isCreature) + .distinct() + .map(b -> b ? "Creature spell" : "Noncreature spell") + .sorted() + .collect(Collectors.toList()); + if (messages.size() == 0) { + return "You have not cast any spells this turn"; + } + return "You have cast a " + String.join(" and a ", messages) + " this turn"; + } + + @Override + public FaeOfferingHint copy() { + return instance; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FairgroundsPatrol.java b/Mage.Sets/src/mage/cards/f/FairgroundsPatrol.java new file mode 100644 index 00000000000..78e01ef20ae --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FairgroundsPatrol.java @@ -0,0 +1,47 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.common.ExileSourceFromGraveCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.permanent.token.ThopterColorlessToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FairgroundsPatrol extends CardImpl { + + public FairgroundsPatrol(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {1}{W}, Exile Fairgrounds Patrol from your graveyard: Create a 1/1 colorless Thopter creature token with flying. Activate only as a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + Zone.GRAVEYARD, new CreateTokenEffect(new ThopterColorlessToken()), new ManaCostsImpl<>("{1}{W}") + ); + ability.addCost(new ExileSourceFromGraveCost()); + this.addAbility(ability); + } + + private FairgroundsPatrol(final FairgroundsPatrol card) { + super(card); + } + + @Override + public FairgroundsPatrol copy() { + return new FairgroundsPatrol(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FaithlessSalvaging.java b/Mage.Sets/src/mage/cards/f/FaithlessSalvaging.java new file mode 100644 index 00000000000..eabbdf161bc --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FaithlessSalvaging.java @@ -0,0 +1,36 @@ +package mage.cards.f; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.keyword.ReboundAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FaithlessSalvaging extends CardImpl { + + public FaithlessSalvaging(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // Discard a card, then draw a card. + this.getSpellAbility().addEffect(new DiscardControllerEffect(1)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy(", then")); + + // Rebound + this.addAbility(new ReboundAbility()); + } + + private FaithlessSalvaging(final FaithlessSalvaging card) { + super(card); + } + + @Override + public FaithlessSalvaging copy() { + return new FaithlessSalvaging(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FallenFerromancer.java b/Mage.Sets/src/mage/cards/f/FallenFerromancer.java index 09e3454a1ef..c60a8807ae1 100644 --- a/Mage.Sets/src/mage/cards/f/FallenFerromancer.java +++ b/Mage.Sets/src/mage/cards/f/FallenFerromancer.java @@ -23,6 +23,7 @@ public final class FallenFerromancer extends CardImpl { public FallenFerromancer(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SHAMAN); diff --git a/Mage.Sets/src/mage/cards/f/FastFurious.java b/Mage.Sets/src/mage/cards/f/FastFurious.java new file mode 100644 index 00000000000..fb5eba6aff3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FastFurious.java @@ -0,0 +1,56 @@ +package mage.cards.f; + +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FastFurious extends SplitCard { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature without flying"); + + static { + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } + + public FastFurious(UUID ownerId, CardSetInfo setInfo) { + super( + ownerId, setInfo, + new CardType[]{CardType.INSTANT}, new CardType[]{CardType.SORCERY}, + "{2}{R}", "{3}{R}{R}", SpellAbilityType.SPLIT + ); + + // Fast + // Discard a card, then draw two cards. + this.getLeftHalfCard().getSpellAbility().addEffect(new DiscardControllerEffect(1)); + this.getLeftHalfCard().getSpellAbility().addEffect( + new DrawCardSourceControllerEffect(2).concatBy(", then") + ); + + // Furious + // Furious deals 3 damage to each creature without flying. + this.getRightHalfCard().getSpellAbility().addEffect(new DamageAllEffect(3, filter)); + } + + private FastFurious(final FastFurious card) { + super(card); + } + + @Override + public FastFurious copy() { + return new FastFurious(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FeastOfSanity.java b/Mage.Sets/src/mage/cards/f/FeastOfSanity.java new file mode 100644 index 00000000000..42374ecda5c --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FeastOfSanity.java @@ -0,0 +1,37 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DiscardCardControllerTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FeastOfSanity extends CardImpl { + + public FeastOfSanity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); + + // Whenever you discard a card, Feast of Sanity deals 1 damage to any target and you gain 1 life. + Ability ability = new DiscardCardControllerTriggeredAbility(new DamageTargetEffect(1), false); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private FeastOfSanity(final FeastOfSanity card) { + super(card); + } + + @Override + public FeastOfSanity copy() { + return new FeastOfSanity(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FiligreeAttendant.java b/Mage.Sets/src/mage/cards/f/FiligreeAttendant.java new file mode 100644 index 00000000000..a6cebf16be1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FiligreeAttendant.java @@ -0,0 +1,43 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.ArtifactYouControlCount; +import mage.abilities.effects.common.continuous.SetPowerSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FiligreeAttendant extends CardImpl { + + public FiligreeAttendant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{U}{U}"); + + this.subtype.add(SubType.HOMUNCULUS); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Filigree Attendant's power is equal to the number of artifacts you control. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerSourceEffect( + ArtifactYouControlCount.instance, Duration.EndOfGame, SubLayer.CharacteristicDefining_7a + ))); + } + + private FiligreeAttendant(final FiligreeAttendant card) { + super(card); + } + + @Override + public FiligreeAttendant copy() { + return new FiligreeAttendant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FirstSphereGargantua.java b/Mage.Sets/src/mage/cards/f/FirstSphereGargantua.java index 5b3a6a47700..9d38483cf70 100644 --- a/Mage.Sets/src/mage/cards/f/FirstSphereGargantua.java +++ b/Mage.Sets/src/mage/cards/f/FirstSphereGargantua.java @@ -22,6 +22,7 @@ public final class FirstSphereGargantua extends CardImpl { public FirstSphereGargantua(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(5); this.toughness = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/f/FlameBlitz.java b/Mage.Sets/src/mage/cards/f/FlameBlitz.java new file mode 100644 index 00000000000..8a1fc3bd7e0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FlameBlitz.java @@ -0,0 +1,40 @@ +package mage.cards.f; + +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FlameBlitz extends CardImpl { + + public FlameBlitz(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + + // At the beginning of your end step, Flame Blitz deals 5 damage to each planeswalker. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new DamageAllEffect( + 5, StaticFilters.FILTER_PERMANENT_PLANESWALKER + ), TargetController.YOU, false)); + + // Cycling {2} + this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}"))); + } + + private FlameBlitz(final FlameBlitz card) { + super(card); + } + + @Override + public FlameBlitz copy() { + return new FlameBlitz(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FlamebornViron.java b/Mage.Sets/src/mage/cards/f/FlamebornViron.java index 27c3c1d4642..15f258b7893 100644 --- a/Mage.Sets/src/mage/cards/f/FlamebornViron.java +++ b/Mage.Sets/src/mage/cards/f/FlamebornViron.java @@ -16,6 +16,7 @@ public final class FlamebornViron extends CardImpl { public FlamebornViron(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{R}{R}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.INSECT); this.power = new MageInt(6); diff --git a/Mage.Sets/src/mage/cards/f/Flensermite.java b/Mage.Sets/src/mage/cards/f/Flensermite.java index 27d514e28d7..7f85be3f471 100644 --- a/Mage.Sets/src/mage/cards/f/Flensermite.java +++ b/Mage.Sets/src/mage/cards/f/Flensermite.java @@ -19,6 +19,7 @@ public final class Flensermite extends CardImpl { public Flensermite (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.GREMLIN); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/f/FleshEaterImp.java b/Mage.Sets/src/mage/cards/f/FleshEaterImp.java index e4b25d8f784..2471dcd75b2 100644 --- a/Mage.Sets/src/mage/cards/f/FleshEaterImp.java +++ b/Mage.Sets/src/mage/cards/f/FleshEaterImp.java @@ -25,6 +25,7 @@ public final class FleshEaterImp extends CardImpl { public FleshEaterImp(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.IMP); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/f/FleshReaver.java b/Mage.Sets/src/mage/cards/f/FleshReaver.java index 9ae154836ab..4009bc9b55c 100644 --- a/Mage.Sets/src/mage/cards/f/FleshReaver.java +++ b/Mage.Sets/src/mage/cards/f/FleshReaver.java @@ -25,6 +25,7 @@ public final class FleshReaver extends CardImpl { public FleshReaver(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(4); this.toughness = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/f/Floodhound.java b/Mage.Sets/src/mage/cards/f/Floodhound.java new file mode 100644 index 00000000000..33a078f594e --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/Floodhound.java @@ -0,0 +1,43 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.keyword.InvestigateEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Floodhound extends CardImpl { + + public Floodhound(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.subtype.add(SubType.ELEMENTAL); + this.subtype.add(SubType.DOG); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {3}, {T}: Investigate. + Ability ability = new SimpleActivatedAbility(new InvestigateEffect(), new GenericManaCost(3)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private Floodhound(final Floodhound card) { + super(card); + } + + @Override + public Floodhound copy() { + return new Floodhound(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FlourishingStrike.java b/Mage.Sets/src/mage/cards/f/FlourishingStrike.java new file mode 100644 index 00000000000..fa4d511a980 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FlourishingStrike.java @@ -0,0 +1,56 @@ +package mage.cards.f; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.EntwineAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FlourishingStrike extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public FlourishingStrike(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + + // Choose one — + // • Flourishing Strike deals 5 damage to target creature with flying. + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + + // • Target creature gets +3/+3 until end of turn. + Mode mode = new Mode(new BoostTargetEffect(3, 3, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addMode(mode); + + // Entwine {2}{G} + this.addAbility(new EntwineAbility("{2}{G}")); + } + + private FlourishingStrike(final FlourishingStrike card) { + super(card); + } + + @Override + public FlourishingStrike copy() { + return new FlourishingStrike(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FodderTosser.java b/Mage.Sets/src/mage/cards/f/FodderTosser.java new file mode 100644 index 00000000000..074c3c37be2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FodderTosser.java @@ -0,0 +1,38 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetPlayerOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FodderTosser extends CardImpl { + + public FodderTosser(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + // {T}, Discard a card: Fodder Tosser deals 2 damage to target player or planeswalker. + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); + ability.addCost(new DiscardCardCost()); + ability.addTarget(new TargetPlayerOrPlaneswalker()); + this.addAbility(ability); + } + + private FodderTosser(final FodderTosser card) { + super(card); + } + + @Override + public FodderTosser copy() { + return new FodderTosser(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FoulWatcher.java b/Mage.Sets/src/mage/cards/f/FoulWatcher.java new file mode 100644 index 00000000000..51959963cc3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FoulWatcher.java @@ -0,0 +1,55 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.DeliriumCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.abilities.hint.common.CardTypesInGraveyardHint; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FoulWatcher extends CardImpl { + + public FoulWatcher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.NIGHTMARE); + this.subtype.add(SubType.BIRD); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Foul Watcher enters the battlefield, surveil 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SurveilEffect(1))); + + // Delirium — Foul Watcher gets +1/+0 as long as there are four more card types among cards in your graveyard. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(1, 0, Duration.WhileOnBattlefield), DeliriumCondition.instance, + "{this} gets +1/+0 as long as there are four more card types among cards in your graveyard" + )).setAbilityWord(AbilityWord.DELIRIUM).addHint(CardTypesInGraveyardHint.YOU)); + } + + private FoulWatcher(final FoulWatcher card) { + super(card); + } + + @Override + public FoulWatcher copy() { + return new FoulWatcher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FoundationBreaker.java b/Mage.Sets/src/mage/cards/f/FoundationBreaker.java new file mode 100644 index 00000000000..719cd5bd64d --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FoundationBreaker.java @@ -0,0 +1,46 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.EvokeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FoundationBreaker extends CardImpl { + + public FoundationBreaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Foundation Breaker enters the battlefield, you may destroy target artifact or enchantment. + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect(), true); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + this.addAbility(ability); + + // Evoke {1}{G} + this.addAbility(new EvokeAbility("{1}{G}")); + } + + private FoundationBreaker(final FoundationBreaker card) { + super(card); + } + + @Override + public FoundationBreaker copy() { + return new FoundationBreaker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FoundryHelix.java b/Mage.Sets/src/mage/cards/f/FoundryHelix.java new file mode 100644 index 00000000000..6460d9aadfa --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FoundryHelix.java @@ -0,0 +1,69 @@ +package mage.cards.f; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author weirddan455 + */ +public final class FoundryHelix extends CardImpl { + + public FoundryHelix(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}{W}"); + + // As an additional cost to cast this spell, sacrifice a permanent. + this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent())); + + // Foundry Helix deals 4 damage to any target. If the sacrificed permanent was an artifact, you gain 4 life. + this.getSpellAbility().addEffect(new DamageTargetEffect(4)); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new GainLifeEffect(4), FoundryHelixCondition.instance)); + this.getSpellAbility().addTarget(new TargetAnyTarget()); + } + + private FoundryHelix(final FoundryHelix card) { + super(card); + } + + @Override + public FoundryHelix copy() { + return new FoundryHelix(this); + } +} + +enum FoundryHelixCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + for (Cost cost : source.getCosts()) { + if (cost instanceof SacrificeTargetCost) { + for (Permanent permanent : ((SacrificeTargetCost) cost).getPermanents()) { + if (permanent.isArtifact()) { + return true; + } + } + } + } + return false; + } + + @Override + public String toString() { + return "the sacrificed permanent was an artifact"; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FumeSpitter.java b/Mage.Sets/src/mage/cards/f/FumeSpitter.java index 951aa294229..e798ede933c 100644 --- a/Mage.Sets/src/mage/cards/f/FumeSpitter.java +++ b/Mage.Sets/src/mage/cards/f/FumeSpitter.java @@ -24,6 +24,7 @@ public final class FumeSpitter extends CardImpl { public FumeSpitter (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/f/FunnelWebRecluse.java b/Mage.Sets/src/mage/cards/f/FunnelWebRecluse.java new file mode 100644 index 00000000000..226041ff3d0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FunnelWebRecluse.java @@ -0,0 +1,48 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.MorbidCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.keyword.InvestigateEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FunnelWebRecluse extends CardImpl { + + public FunnelWebRecluse(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.SPIDER); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Morbid — When Funnel-Web Recluse enters the battlefield, if a creature died this turn, investigate. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new InvestigateEffect()), + MorbidCondition.instance, "Morbid — When {this} enters the battlefield, " + + "if a creature died this turn, investigate. (Create a colorless Clue artifact token " + + "with \"{2}, Sacrifice this artifact: Draw a card.\")" + )); + } + + private FunnelWebRecluse(final FunnelWebRecluse card) { + super(card); + } + + @Override + public FunnelWebRecluse copy() { + return new FunnelWebRecluse(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FurnaceScamp.java b/Mage.Sets/src/mage/cards/f/FurnaceScamp.java index d9795473611..25619403d9f 100644 --- a/Mage.Sets/src/mage/cards/f/FurnaceScamp.java +++ b/Mage.Sets/src/mage/cards/f/FurnaceScamp.java @@ -20,6 +20,7 @@ public final class FurnaceScamp extends CardImpl { public FurnaceScamp(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BEAST); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/f/Fury.java b/Mage.Sets/src/mage/cards/f/Fury.java new file mode 100644 index 00000000000..03c3ef9a723 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/Fury.java @@ -0,0 +1,63 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.ExileFromHandCost; +import mage.abilities.effects.common.DamageMultiEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.abilities.keyword.EvokeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCreatureOrPlaneswalkerAmount; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Fury extends CardImpl { + + private static final FilterCard filter = new FilterCard("a red card from your hand"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + + public Fury(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.subtype.add(SubType.ELEMENTAL); + this.subtype.add(SubType.INCARNATION); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Double strike + this.addAbility(DoubleStrikeAbility.getInstance()); + + // When Fury enters the battlefield, it deals 4 damage divided as you choose among any number of target creatures and/or planeswalkers. + Ability ability = new EntersBattlefieldTriggeredAbility( + new DamageMultiEffect(4, "it") + ); + ability.addTarget(new TargetCreatureOrPlaneswalkerAmount(4)); + this.addAbility(ability); + + // Evoke—Exile a red card from your hand. + this.addAbility(new EvokeAbility(new ExileFromHandCost(new TargetCardInHand(filter)))); + } + + private Fury(final Fury card) { + super(card); + } + + @Override + public Fury copy() { + return new Fury(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/Gallowbraid.java b/Mage.Sets/src/mage/cards/g/Gallowbraid.java index 9702ad68c4c..a075db6c244 100644 --- a/Mage.Sets/src/mage/cards/g/Gallowbraid.java +++ b/Mage.Sets/src/mage/cards/g/Gallowbraid.java @@ -21,6 +21,7 @@ public final class Gallowbraid extends CardImpl { public Gallowbraid(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(5); this.toughness = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/g/GalvanicRelay.java b/Mage.Sets/src/mage/cards/g/GalvanicRelay.java new file mode 100644 index 00000000000..e2bf3f82e6b --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GalvanicRelay.java @@ -0,0 +1,126 @@ +package mage.cards.g; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.StormAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +/** + * + * @author weirddan455 + */ +public final class GalvanicRelay extends CardImpl { + + public GalvanicRelay(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Exile the top card of your library. During your next turn, you may play that card. + this.getSpellAbility().addEffect(new GalvanicRelayEffect()); + + // Storm + this.addAbility(new StormAbility()); + } + + private GalvanicRelay(final GalvanicRelay card) { + super(card); + } + + @Override + public GalvanicRelay copy() { + return new GalvanicRelay(this); + } +} + +class GalvanicRelayEffect extends OneShotEffect { + + public GalvanicRelayEffect() { + super(Outcome.Benefit); + this.staticText = "Exile the top card of your library. During your next turn, you may play that card"; + } + + private GalvanicRelayEffect(final GalvanicRelayEffect effect) { + super(effect); + } + + @Override + public GalvanicRelayEffect copy() { + return new GalvanicRelayEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Card topCard = controller.getLibrary().getFromTop(game); + if (topCard != null) { + Card sourceCard = game.getCard(source.getSourceId()); + controller.moveCardsToExile(topCard, source, game, true, CardUtil.getCardExileZoneId(game, source), sourceCard != null ? sourceCard.getIdName() : ""); + ContinuousEffect effect = new GalvanicRelayMayPlayEffect(); + effect.setTargetPointer(new FixedTarget(topCard.getId())); + game.addEffect(effect, source); + return true; + } + } + return false; + } +} + +class GalvanicRelayMayPlayEffect extends AsThoughEffectImpl { + + private int castOnTurn = 0; + + public GalvanicRelayMayPlayEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); + this.staticText = "During your next turn, you may play that card"; + } + + private GalvanicRelayMayPlayEffect(final GalvanicRelayMayPlayEffect effect) { + super(effect); + this.castOnTurn = effect.castOnTurn; + } + + @Override + public GalvanicRelayMayPlayEffect copy() { + return new GalvanicRelayMayPlayEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + this.castOnTurn = game.getTurnNum(); + } + + @Override + public boolean isInactive(Ability source, Game game) { + // Keep effect active until cleanup step of the controller's next turn. Turn will be checked again in applies method below. + if (castOnTurn != game.getTurnNum() && game.getPhase().getStep().getType() == PhaseStep.CLEANUP) { + return game.isActivePlayer(source.getControllerId()); + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + UUID mainCardId = CardUtil.getMainCardId(game, sourceId); + return source.isControlledBy(affectedControllerId) + && castOnTurn != game.getTurnNum() + && game.isActivePlayer(affectedControllerId) + && getTargetPointer().getTargets(game, source).contains(mainCardId); + } +} diff --git a/Mage.Sets/src/mage/cards/g/Gargadon.java b/Mage.Sets/src/mage/cards/g/Gargadon.java new file mode 100644 index 00000000000..5c7c82d720e --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/Gargadon.java @@ -0,0 +1,41 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.keyword.SuspendAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Gargadon extends CardImpl { + + public Gargadon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(7); + this.toughness = new MageInt(5); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Suspend 4—{1}{R} + this.addAbility(new SuspendAbility(4, new ManaCostsImpl<>("{1}{R}"), this)); + } + + private Gargadon(final Gargadon card) { + super(card); + } + + @Override + public Gargadon copy() { + return new Gargadon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GarthOneEye.java b/Mage.Sets/src/mage/cards/g/GarthOneEye.java new file mode 100644 index 00000000000..9fe9dd77c81 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GarthOneEye.java @@ -0,0 +1,166 @@ +package mage.cards.g; + +import mage.ApprovingObject; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.hint.Hint; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public final class GarthOneEye extends CardImpl { + + public GarthOneEye(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // {T}: Choose a card name that hasn't been chosen from among Disenchant, Braingeyser, Terror, Shivan Dragon, Regrowth, and Black Lotus. Create a copy of the card with the chosen name. You may cast the copy. + this.addAbility(new SimpleActivatedAbility( + new GarthOneEyeEffect(), new TapSourceCost() + ).addHint(GarthOneEyeHint.instance)); + } + + private GarthOneEye(final GarthOneEye card) { + super(card); + } + + @Override + public GarthOneEye copy() { + return new GarthOneEye(this); + } +} + +class GarthOneEyeEffect extends OneShotEffect { + + private static final List names = Arrays.asList( + "Disenchant", "Braingeyser", "Terror", "Shivan Dragon", "Regrowth", "Black Lotus" + ); + private static final Map cardMap = new HashMap<>(); + + private static final void initMap() { + if (!cardMap.isEmpty()) { + return; + } + cardMap.putAll(CardRepository + .instance + .findCards(new CardCriteria().setCodes("LEA")) + .stream() + .filter(cardInfo -> names.contains(cardInfo.getName())) + .collect(Collectors.toMap(CardInfo::getName, CardInfo::getCard))); + } + + GarthOneEyeEffect() { + super(Outcome.Benefit); + staticText = "choose a card name that hasn't been chosen from among " + + "Disenchant, Braingeyser, Terror, Shivan Dragon, Regrowth, and Black Lotus. " + + "Create a copy of the card with the chosen name. You may cast the copy"; + } + + private GarthOneEyeEffect(final GarthOneEyeEffect effect) { + super(effect); + } + + @Override + public GarthOneEyeEffect copy() { + return new GarthOneEyeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + initMap(); + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Set alreadyChosen = getAlreadyChosen(game, source); + Set choices = new HashSet<>(names); + choices.removeAll(alreadyChosen); + String chosen; + switch (choices.size()) { + case 0: + return false; + case 1: + chosen = choices.stream().findAny().orElse(null); + break; + default: + Choice choice = new ChoiceImpl(true); + choice.setChoices(choices); + player.choose(outcome, choice, game); + chosen = choice.getChoice(); + } + alreadyChosen.add(chosen); + Card card = cardMap.get(chosen); + if (card == null || !player.chooseUse(outcome, "Cast " + card.getName() + '?', source, game)) { + return false; + } + Card copiedCard = game.copyCard(card, source, source.getControllerId()); + copiedCard.setZone(Zone.OUTSIDE, game); + game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE); + player.cast( + player.chooseAbilityForCast(copiedCard, game, false), + game, false, new ApprovingObject(source, game) + ); + game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null); + return true; + } + + private static final Set getAlreadyChosen(Game game, Ability source) { + String key = getKey(source); + Object value = game.getState().getValue(key); + if (value instanceof Set) { + return (Set) value; + } + Set alreadyChosen = new HashSet<>(); + game.getState().setValue(key, alreadyChosen); + return alreadyChosen; + } + + static final String getKey(Ability source) { + return source.getSourceId() + "_" + + source.getSourceObjectZoneChangeCounter() + "_" + + source.getOriginalId() + "_garth"; + } +} + +enum GarthOneEyeHint implements Hint { + instance; + + @Override + public String getText(Game game, Ability ability) { + if (ability.getSourcePermanentIfItStillExists(game) == null) { + return null; + } + Set chosen = (Set) game.getState().getValue(GarthOneEyeEffect.getKey(ability)); + if (chosen == null || chosen.isEmpty()) { + return "Chosen names: None"; + } + return "Chosen names: " + String.join(", ", chosen); + } + + @Override + public GarthOneEyeHint copy() { + return instance; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GatherSpecimens.java b/Mage.Sets/src/mage/cards/g/GatherSpecimens.java index 20eeab20d88..0c0ae278dc3 100644 --- a/Mage.Sets/src/mage/cards/g/GatherSpecimens.java +++ b/Mage.Sets/src/mage/cards/g/GatherSpecimens.java @@ -13,6 +13,7 @@ import mage.game.Game; import mage.game.events.CreateTokenEvent; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.token.Token; import mage.players.Player; import java.util.UUID; @@ -77,9 +78,15 @@ class GatherSpecimensReplacementEffect extends ReplacementEffectImpl { } } } - if (event.getType() == GameEvent.EventType.CREATE_TOKEN && ((CreateTokenEvent) event).getToken().isCreature()) { + if (event.getType() == GameEvent.EventType.CREATE_TOKEN) { Player controller = game.getPlayer(source.getControllerId()); - return controller != null && controller.hasOpponent(event.getPlayerId(), game); + if (controller != null && controller.hasOpponent(event.getPlayerId(), game)) { + for (Token token : ((CreateTokenEvent) event).getTokens().keySet()) { + if (token.isCreature()) { + return true; + } + } + } } return false; } diff --git a/Mage.Sets/src/mage/cards/g/GeneralFerrousRokiric.java b/Mage.Sets/src/mage/cards/g/GeneralFerrousRokiric.java new file mode 100644 index 00000000000..73d3c14582a --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GeneralFerrousRokiric.java @@ -0,0 +1,53 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.HexproofFromMonocoloredAbility; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.MulticoloredPredicate; +import mage.game.permanent.token.RedWhiteGolemToken; + +/** + * + * @author weirddan455 + */ +public final class GeneralFerrousRokiric extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a multicolored spell"); + + static { + filter.add(MulticoloredPredicate.instance); + } + + public GeneralFerrousRokiric(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Hexproof from monocolored + this.addAbility(HexproofFromMonocoloredAbility.getInstance()); + + // Whenever you cast a multicolored spell, create a 4/4 red and white Golem artifact creature token. + this.addAbility(new SpellCastControllerTriggeredAbility(new CreateTokenEffect(new RedWhiteGolemToken()), filter, false)); + } + + private GeneralFerrousRokiric(final GeneralFerrousRokiric card) { + super(card); + } + + @Override + public GeneralFerrousRokiric copy() { + return new GeneralFerrousRokiric(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GethLordOfTheVault.java b/Mage.Sets/src/mage/cards/g/GethLordOfTheVault.java index ce4b6e749ba..ee740491e08 100644 --- a/Mage.Sets/src/mage/cards/g/GethLordOfTheVault.java +++ b/Mage.Sets/src/mage/cards/g/GethLordOfTheVault.java @@ -36,6 +36,7 @@ public final class GethLordOfTheVault extends CardImpl { public GethLordOfTheVault(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/g/GeyadroneDihada.java b/Mage.Sets/src/mage/cards/g/GeyadroneDihada.java new file mode 100644 index 00000000000..67bc26f82ce --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GeyadroneDihada.java @@ -0,0 +1,92 @@ +package mage.cards.g; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.continuous.GainControlAllEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreatureOrPlaneswalker; + +/** + * + * @author weirddan455 + */ +public final class GeyadroneDihada extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("permanents with corruption counters on them"); + private static final FilterCreatureOrPlaneswalkerPermanent filter2 = new FilterCreatureOrPlaneswalkerPermanent("other creature or planeswalker"); + private static final FilterPermanent filter3 = new FilterPermanent("each permanent with a corruption counter on it"); + + static { + filter.add(CorruptionCounterPredicate.instance); + filter2.add(AnotherPredicate.instance); + filter3.add(CorruptionCounterPredicate.instance); + } + + public GeyadroneDihada(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{U}{B}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DIHADA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // Protection from permanents with corruption counters on them + this.addAbility(new ProtectionAbility(filter)); + + // +1: Each opponent loses 2 life and you gain 2 life. Put a corruption counter on up to one other target creature or planeswalker. + Ability ability = new LoyaltyAbility(new LoseLifeOpponentsEffect(2), 1); + ability.addEffect(new GainLifeEffect(2).concatBy("and")); + ability.addEffect(new AddCountersTargetEffect(CounterType.CORRUPTION.createInstance(), Outcome.Detriment) + .setText("Put a corruption counter on up to one other target creature or planeswalker")); + ability.addTarget(new TargetCreatureOrPlaneswalker(0, 1, filter2, false)); + this.addAbility(ability); + + // −3: Gain control of target creature or planeswalker until end of tun. Untap it and put a corruption counter on it. It gains haste until end of turn. + ability = new LoyaltyAbility(new GainControlTargetEffect(Duration.EndOfTurn), -3); + ability.addEffect(new UntapTargetEffect().setText("Untap it")); + ability.addEffect(new AddCountersTargetEffect(CounterType.CORRUPTION.createInstance(), Outcome.Detriment).setText("and put a corruption counter on it")); + ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn).setText("It gains haste until end of turn")); + ability.addTarget(new TargetCreatureOrPlaneswalker()); + this.addAbility(ability); + + // −7: Gain control of each permanent with a corruption counter on it. + this.addAbility(new LoyaltyAbility(new GainControlAllEffect(Duration.Custom, filter3), -7)); + } + + private GeyadroneDihada(final GeyadroneDihada card) { + super(card); + } + + @Override + public GeyadroneDihada copy() { + return new GeyadroneDihada(this); + } +} + +enum CorruptionCounterPredicate implements Predicate { + instance; + + @Override + public boolean apply(Permanent input, Game game) { + return input.getCounters(game).getCount(CounterType.CORRUPTION) > 0; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GhostLitDrifter.java b/Mage.Sets/src/mage/cards/g/GhostLitDrifter.java new file mode 100644 index 00000000000..cd740e80522 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GhostLitDrifter.java @@ -0,0 +1,81 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.ChannelAbility; +import mage.abilities.keyword.FlyingAbility; +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 mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GhostLitDrifter extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); + + static { + filter.add(AnotherPredicate.instance); + } + + public GhostLitDrifter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {2}{U}: Another target creature gains flying until end of turn. + Ability ability = new SimpleActivatedAbility(new GainAbilityTargetEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn, + "another target creature gains flying until end of turn" + ), new ManaCostsImpl<>("{2}{U}")); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // Channel — {X}{U}, Discard Ghost-Lit Drifter: X target creatures gain flying until end of turn. + ability = new ChannelAbility("{X}{U}", new GainAbilityTargetEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn, + "X target creatures gain flying until end of turn" + )); + ability.setTargetAdjuster(GhostLitDrifterAdjuster.instance); + this.addAbility(ability); + } + + private GhostLitDrifter(final GhostLitDrifter card) { + super(card); + } + + @Override + public GhostLitDrifter copy() { + return new GhostLitDrifter(this); + } +} + +enum GhostLitDrifterAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GiltBladeProwler.java b/Mage.Sets/src/mage/cards/g/GiltBladeProwler.java new file mode 100644 index 00000000000..d6e26165c25 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GiltBladeProwler.java @@ -0,0 +1,52 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.condition.common.ControllerDiscardedThisTurnCondition; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.hint.common.ControllerDiscardedHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.watchers.common.DiscardedCardWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GiltBladeProwler extends CardImpl { + + public GiltBladeProwler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // {1}, {T}, Pay 1 life: Draw a card. Activate only if you've discarded a card this turn. + Ability ability = new ActivateIfConditionActivatedAbility( + Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), + new GenericManaCost(1), ControllerDiscardedThisTurnCondition.instance + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new PayLifeCost(1)); + this.addAbility(ability.addHint(ControllerDiscardedHint.instance), new DiscardedCardWatcher()); + } + + private GiltBladeProwler(final GiltBladeProwler card) { + super(card); + } + + @Override + public GiltBladeProwler copy() { + return new GiltBladeProwler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlimmerBairn.java b/Mage.Sets/src/mage/cards/g/GlimmerBairn.java new file mode 100644 index 00000000000..8985d02afc7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlimmerBairn.java @@ -0,0 +1,51 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GlimmerBairn extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a token"); + + static { + filter.add(TokenPredicate.instance); + } + + public GlimmerBairn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + + this.subtype.add(SubType.OUPHE); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Sacrifice a token: Glimmer Bairn gets +2/+2 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(2, 2, Duration.EndOfTurn), + new SacrificeTargetCost(new TargetControlledPermanent(filter)) + )); + } + + private GlimmerBairn(final GlimmerBairn card) { + super(card); + } + + @Override + public GlimmerBairn copy() { + return new GlimmerBairn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlimpseOfTomorrow.java b/Mage.Sets/src/mage/cards/g/GlimpseOfTomorrow.java new file mode 100644 index 00000000000..aafcd2a15ea --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlimpseOfTomorrow.java @@ -0,0 +1,101 @@ +package mage.cards.g; + +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.SuspendAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GlimpseOfTomorrow extends CardImpl { + + public GlimpseOfTomorrow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, ""); + + this.color.setRed(true); + + // Suspend 3—{R}{R} + this.addAbility(new SuspendAbility(3, new ManaCostsImpl<>("{R}{R}"), this)); + + // Shuffle all permanents you own into your library, then reveal that many cards from the top of your library. Put all non-Aura permanent cards revealed this way onto the battlefield, then do the same for Aura cards, then put the rest on the bottom of your library in a random order. + this.getSpellAbility().addEffect(new GlimpseOfTomorrowEffect()); + } + + private GlimpseOfTomorrow(final GlimpseOfTomorrow card) { + super(card); + } + + @Override + public GlimpseOfTomorrow copy() { + return new GlimpseOfTomorrow(this); + } +} + +class GlimpseOfTomorrowEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(TargetController.YOU.getOwnerPredicate()); + } + + GlimpseOfTomorrowEffect() { + super(Outcome.Benefit); + staticText = "shuffle all permanents you own into your library, then reveal " + + "that many cards from the top of your library. Put all non-Aura permanent cards " + + "revealed this way onto the battlefield, then do the same for Aura cards, " + + "then put the rest on the bottom of your library in a random order"; + } + + private GlimpseOfTomorrowEffect(final GlimpseOfTomorrowEffect effect) { + super(effect); + } + + @Override + public GlimpseOfTomorrowEffect copy() { + return new GlimpseOfTomorrowEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + List permanents = game.getBattlefield().getActivePermanents( + filter, source.getControllerId(), source.getSourceId(), game + ); + int count = permanents.size(); + player.shuffleCardsToLibrary(new CardsImpl(permanents), game, source); + + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, count)); + player.revealCards(source, cards, game); + + Cards toBattlefield = new CardsImpl(cards.getCards(StaticFilters.FILTER_CARD_PERMANENT, game)); + toBattlefield.removeIf(uuid -> game.getCard(uuid).hasSubtype(SubType.AURA, game)); + player.moveCards(toBattlefield, Zone.BATTLEFIELD, source, game); + toBattlefield.clear(); + cards.retainZone(Zone.LIBRARY, game); + + toBattlefield.addAll(cards.getCards(StaticFilters.FILTER_CARD_PERMANENT, game)); + toBattlefield.removeIf(uuid -> !game.getCard(uuid).hasSubtype(SubType.AURA, game)); + player.moveCards(toBattlefield, Zone.BATTLEFIELD, source, game); + cards.retainZone(Zone.LIBRARY, game); + player.putCardsOnBottomOfLibrary(cards, game, source, false); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlintingCreeper.java b/Mage.Sets/src/mage/cards/g/GlintingCreeper.java new file mode 100644 index 00000000000..bef75a80569 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlintingCreeper.java @@ -0,0 +1,50 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.MultipliedValue; +import mage.abilities.dynamicvalue.common.ColorsOfManaSpentToCastCount; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.DauntAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GlintingCreeper extends CardImpl { + + private static final DynamicValue xValue = new MultipliedValue(ColorsOfManaSpentToCastCount.getInstance(), 2); + + public GlintingCreeper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.PLANT); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Converge — Glinting Creeper enters the battlefield with two +1/+1 counters on it for each color of mana spent to cast it. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( + CounterType.P1P1.createInstance(), xValue, true + ), null, "Converge — {this} enters the battlefield " + + "with two +1/+1 counters on it for each color of mana spent to cast it.", null)); + + // Glinting Creeper can't be blocked by creatures with power 2 or less. + this.addAbility(new DauntAbility()); + } + + private GlintingCreeper(final GlintingCreeper card) { + super(card); + } + + @Override + public GlintingCreeper copy() { + return new GlintingCreeper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlissaTheTraitor.java b/Mage.Sets/src/mage/cards/g/GlissaTheTraitor.java index 30cd49b5b11..0a6d9f23efb 100644 --- a/Mage.Sets/src/mage/cards/g/GlissaTheTraitor.java +++ b/Mage.Sets/src/mage/cards/g/GlissaTheTraitor.java @@ -30,6 +30,7 @@ public final class GlissaTheTraitor extends CardImpl { public GlissaTheTraitor (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{G}{G}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.ELF); diff --git a/Mage.Sets/src/mage/cards/g/GlissasCourier.java b/Mage.Sets/src/mage/cards/g/GlissasCourier.java index 1b0aa00446d..e48b19e29f1 100644 --- a/Mage.Sets/src/mage/cards/g/GlissasCourier.java +++ b/Mage.Sets/src/mage/cards/g/GlissasCourier.java @@ -18,6 +18,7 @@ public final class GlissasCourier extends CardImpl { public GlissasCourier (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/g/GlistenerElf.java b/Mage.Sets/src/mage/cards/g/GlistenerElf.java index 85e1ccabd0c..b6a4ef0e46e 100644 --- a/Mage.Sets/src/mage/cards/g/GlistenerElf.java +++ b/Mage.Sets/src/mage/cards/g/GlistenerElf.java @@ -17,6 +17,7 @@ public final class GlistenerElf extends CardImpl { public GlistenerElf(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ELF); this.subtype.add(SubType.WARRIOR); diff --git a/Mage.Sets/src/mage/cards/g/GoblinAnarchomancer.java b/Mage.Sets/src/mage/cards/g/GoblinAnarchomancer.java new file mode 100644 index 00000000000..9786d11815d --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinAnarchomancer.java @@ -0,0 +1,52 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GoblinAnarchomancer extends CardImpl { + + private static final FilterCard filter = new FilterCard(); + + static { + filter.add(Predicates.or( + new ColorPredicate(ObjectColor.RED), + new ColorPredicate(ObjectColor.GREEN) + )); + } + + public GoblinAnarchomancer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Each spell you cast that's red or green costs {1} less to cast. + this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1) + .setText("each spell you cast that's red or green costs {1} less to cast"))); + } + + private GoblinAnarchomancer(final GoblinAnarchomancer card) { + super(card); + } + + @Override + public GoblinAnarchomancer copy() { + return new GoblinAnarchomancer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinTraprunner.java b/Mage.Sets/src/mage/cards/g/GoblinTraprunner.java new file mode 100644 index 00000000000..dceeef319b6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinTraprunner.java @@ -0,0 +1,75 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.token.GoblinToken; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GoblinTraprunner extends CardImpl { + + public GoblinTraprunner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Whenever Goblin Traprunner attacks, flip three coins. For each flip you win, create a 1/1 red Goblin creature token that's tapped and attacking. + this.addAbility(new AttacksTriggeredAbility(new CreateTokenEffect( + new GoblinToken(), GoblinTraprunnerValue.instance, true, true + ).setText("flip three coins. For each flip you win, " + + "create a 1/1 red Goblin creature token that's tapped and attacking"), false)); + } + + private GoblinTraprunner(final GoblinTraprunner card) { + super(card); + } + + @Override + public GoblinTraprunner copy() { + return new GoblinTraprunner(this); + } +} + +enum GoblinTraprunnerValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Player player = game.getPlayer(sourceAbility.getControllerId()); + if (player == null) { + return 0; + } + int count = 0; + for (int i = 0; i < 3; i++) { + if (player.flipCoin(sourceAbility, game, true)) { + count++; + } + } + return count; + } + + @Override + public GoblinTraprunnerValue copy() { + return instance; + } + + @Override + public String getMessage() { + return ""; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoreVassal.java b/Mage.Sets/src/mage/cards/g/GoreVassal.java index 3ee2ca92668..5832065e26e 100644 --- a/Mage.Sets/src/mage/cards/g/GoreVassal.java +++ b/Mage.Sets/src/mage/cards/g/GoreVassal.java @@ -23,6 +23,7 @@ public final class GoreVassal extends CardImpl { public GoreVassal(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DOG); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/g/GougedZealot.java b/Mage.Sets/src/mage/cards/g/GougedZealot.java new file mode 100644 index 00000000000..c0e129a4087 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GougedZealot.java @@ -0,0 +1,81 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.common.DeliriumCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.hint.common.CardTypesInGraveyardHint; +import mage.constants.*; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author weirddan455 + */ +public final class GougedZealot extends CardImpl { + + public GougedZealot(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.CYCLOPS); + this.subtype.add(SubType.BERSERKER); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Delirium — Whenever Gouged Zealot attacks, if there are four or more card types among cards in your graveyard, Gouged Zealot deals 1 damage to each creature defending player controls. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new AttacksTriggeredAbility(new GougedZealotEffect(), false, null, SetTargetPointer.PLAYER), + DeliriumCondition.instance, + "Delirium — Whenever {this} attacks, if there are four or more card types among cards in your graveyard, {this} deals 1 damage to each creature defending player controls." + ).addHint(CardTypesInGraveyardHint.YOU)); + } + + private GougedZealot(final GougedZealot card) { + super(card); + } + + @Override + public GougedZealot copy() { + return new GougedZealot(this); + } +} + +class GougedZealotEffect extends OneShotEffect { + + public GougedZealotEffect() { + super(Outcome.Damage); + this.staticText = "{this} deals 1 damage to each creature defending player controls"; + } + + private GougedZealotEffect(final GougedZealotEffect effect) { + super(effect); + } + + @Override + public GougedZealotEffect copy() { + return new GougedZealotEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID defendingPlayerId = getTargetPointer().getFirst(game, source); + if (defendingPlayerId != null) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, defendingPlayerId, game)) { + permanent.damage(1, source.getSourceId(), source, game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GracefulRestoration.java b/Mage.Sets/src/mage/cards/g/GracefulRestoration.java new file mode 100644 index 00000000000..fed8e25db2f --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GracefulRestoration.java @@ -0,0 +1,52 @@ +package mage.cards.g; + +import java.util.UUID; + +import mage.abilities.Mode; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldWithCounterTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author weirddan455 + */ +public final class GracefulRestoration extends CardImpl { + + private static final FilterCreatureCard filter = new FilterCreatureCard("creature cards with power 2 or less from your graveyard"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public GracefulRestoration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}{B}"); + + // Choose one — + // • Return target creature card from your graveyard to the battlefield with an additional +1/+1 counter on it. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(CounterType.P1P1.createInstance(), true)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + + // • Return up to two target creature cards with power 2 or less from your graveyard to the battlefield. + Mode mode = new Mode(new ReturnFromGraveyardToBattlefieldTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(0, 2, filter)); + this.getSpellAbility().addMode(mode); + } + + private GracefulRestoration(final GracefulRestoration card) { + super(card); + } + + @Override + public GracefulRestoration copy() { + return new GracefulRestoration(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GravebreakerLamia.java b/Mage.Sets/src/mage/cards/g/GravebreakerLamia.java index 3e4e1350852..f000c0d51eb 100644 --- a/Mage.Sets/src/mage/cards/g/GravebreakerLamia.java +++ b/Mage.Sets/src/mage/cards/g/GravebreakerLamia.java @@ -1,23 +1,18 @@ package mage.cards.g; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.SearchEffect; import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInGraveyardEffect; import mage.abilities.keyword.LifelinkAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.card.CastFromZonePredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -45,7 +40,7 @@ public final class GravebreakerLamia extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // When Gravebreaker Lamia enters the battlefield, search your library for a card, put it into your graveyard, then shuffle your library. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GravebreakerLamiaSearchEffect(), false)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInGraveyardEffect(), false)); // Spells you cast from your graveyard cost {1} less to cast. this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1) @@ -61,33 +56,3 @@ public final class GravebreakerLamia extends CardImpl { return new GravebreakerLamia(this); } } - -class GravebreakerLamiaSearchEffect extends SearchEffect { - - GravebreakerLamiaSearchEffect() { - super(new TargetCardInLibrary(), Outcome.Neutral); - staticText = "search your library for a card, put it into your graveyard, then shuffle"; - } - - private GravebreakerLamiaSearchEffect(final GravebreakerLamiaSearchEffect effect) { - super(effect); - } - - @Override - public GravebreakerLamiaSearchEffect copy() { - return new GravebreakerLamiaSearchEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - if (controller.searchLibrary(target, source, game)) { - controller.moveCards(game.getCard(target.getFirstTarget()), Zone.GRAVEYARD, source, game); - } - controller.shuffleLibrary(source, game); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/g/GrevenPredatorCaptain.java b/Mage.Sets/src/mage/cards/g/GrevenPredatorCaptain.java index 97572ef20d9..1d3da75d417 100644 --- a/Mage.Sets/src/mage/cards/g/GrevenPredatorCaptain.java +++ b/Mage.Sets/src/mage/cards/g/GrevenPredatorCaptain.java @@ -31,6 +31,7 @@ public final class GrevenPredatorCaptain extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{R}"); this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/g/GuardianKirin.java b/Mage.Sets/src/mage/cards/g/GuardianKirin.java new file mode 100644 index 00000000000..9e911784531 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GuardianKirin.java @@ -0,0 +1,54 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GuardianKirin extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("another creature you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + public GuardianKirin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.KIRIN); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever another creature you control dies, put a +1/+1 counter on Guardian Kirin. + this.addAbility(new DiesCreatureTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, filter + )); + } + + private GuardianKirin(final GuardianKirin card) { + super(card); + } + + @Override + public GuardianKirin copy() { + return new GuardianKirin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HandOfThePraetors.java b/Mage.Sets/src/mage/cards/h/HandOfThePraetors.java index 4d7f7854bb8..6787226fb5e 100644 --- a/Mage.Sets/src/mage/cards/h/HandOfThePraetors.java +++ b/Mage.Sets/src/mage/cards/h/HandOfThePraetors.java @@ -37,6 +37,7 @@ public final class HandOfThePraetors extends CardImpl { public HandOfThePraetors (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/h/HardEvidence.java b/Mage.Sets/src/mage/cards/h/HardEvidence.java new file mode 100644 index 00000000000..bfeecec1af6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HardEvidence.java @@ -0,0 +1,35 @@ +package mage.cards.h; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.keyword.InvestigateEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.permanent.token.CrabToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HardEvidence extends CardImpl { + + public HardEvidence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); + + // Create a 0/3 blue Crab creature token. + this.getSpellAbility().addEffect(new CreateTokenEffect(new CrabToken())); + + // Investigate. + this.getSpellAbility().addEffect(new InvestigateEffect().concatBy("
")); + } + + private HardEvidence(final HardEvidence card) { + super(card); + } + + @Override + public HardEvidence copy() { + return new HardEvidence(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HarmonicProdigy.java b/Mage.Sets/src/mage/cards/h/HarmonicProdigy.java new file mode 100644 index 00000000000..4dd99d3a18a --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HarmonicProdigy.java @@ -0,0 +1,91 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.keyword.ProwessAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.NumberOfTriggersEvent; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HarmonicProdigy extends CardImpl { + + public HarmonicProdigy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Prowess + this.addAbility(new ProwessAbility()); + + // If an ability of a Shaman or another Wizard you control triggers, that ability triggers an additional time. + this.addAbility(new SimpleStaticAbility(new HarmonicProdigyEffect())); + } + + private HarmonicProdigy(final HarmonicProdigy card) { + super(card); + } + + @Override + public HarmonicProdigy copy() { + return new HarmonicProdigy(this); + } +} + +class HarmonicProdigyEffect extends ReplacementEffectImpl { + + HarmonicProdigyEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "if an ability of a Shaman or another Wizard you control triggers, " + + "that ability triggers an additional time"; + } + + HarmonicProdigyEffect(final HarmonicProdigyEffect effect) { + super(effect); + } + + @Override + public HarmonicProdigyEffect copy() { + return new HarmonicProdigyEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.NUMBER_OF_TRIGGERS; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!(event instanceof NumberOfTriggersEvent)) { + return false; + } + Permanent permanent = game.getPermanent(((NumberOfTriggersEvent) event).getSourceId()); + return permanent != null + && permanent.isControlledBy(source.getControllerId()) + && (permanent.hasSubtype(SubType.SHAMAN, game) + || (permanent.hasSubtype(SubType.WIZARD, game) + && !permanent.getId().equals(source.getSourceId()))); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(event.getAmount() + 1); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HealersFlock.java b/Mage.Sets/src/mage/cards/h/HealersFlock.java new file mode 100644 index 00000000000..2e3c13a5d51 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HealersFlock.java @@ -0,0 +1,40 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HealersFlock extends CardImpl { + + public HealersFlock(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}{W}"); + + this.subtype.add(SubType.BIRD); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + } + + private HealersFlock(final HealersFlock card) { + super(card); + } + + @Override + public HealersFlock copy() { + return new HealersFlock(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HellMongrel.java b/Mage.Sets/src/mage/cards/h/HellMongrel.java new file mode 100644 index 00000000000..334b84710b5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HellMongrel.java @@ -0,0 +1,47 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.MadnessAbility; +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 HellMongrel extends CardImpl { + + public HellMongrel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.NIGHTMARE); + this.subtype.add(SubType.DOG); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Discard a card: Hell Mongrel gets +1/+1 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn), new DiscardCardCost() + )); + + // Madness {2}{B} + this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{2}{B}"))); + } + + private HellMongrel(final HellMongrel card) { + super(card); + } + + @Override + public HellMongrel copy() { + return new HellMongrel(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HexParasite.java b/Mage.Sets/src/mage/cards/h/HexParasite.java index 1bcdd38ad9c..05a919f937b 100644 --- a/Mage.Sets/src/mage/cards/h/HexParasite.java +++ b/Mage.Sets/src/mage/cards/h/HexParasite.java @@ -23,6 +23,7 @@ public final class HexParasite extends CardImpl { public HexParasite(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.INSECT); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/h/HollowDogs.java b/Mage.Sets/src/mage/cards/h/HollowDogs.java index 339efb55d8b..bb9d98b219b 100644 --- a/Mage.Sets/src/mage/cards/h/HollowDogs.java +++ b/Mage.Sets/src/mage/cards/h/HollowDogs.java @@ -19,6 +19,7 @@ public final class HollowDogs extends CardImpl { public HollowDogs(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.DOG); diff --git a/Mage.Sets/src/mage/cards/i/IchTekikSalvageSplicer.java b/Mage.Sets/src/mage/cards/i/IchTekikSalvageSplicer.java index 583fc459907..46effe8f592 100644 --- a/Mage.Sets/src/mage/cards/i/IchTekikSalvageSplicer.java +++ b/Mage.Sets/src/mage/cards/i/IchTekikSalvageSplicer.java @@ -17,7 +17,7 @@ import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; -import mage.game.permanent.token.GolemToken; +import mage.game.permanent.token.PhyrexianGolemToken; import java.util.UUID; @@ -32,13 +32,14 @@ public final class IchTekikSalvageSplicer extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ARTIFICER); this.power = new MageInt(1); this.toughness = new MageInt(1); // When Ich-Tekik, Salvage Splicer enters the battlefield, create a 3/3 colorless Golem artifact creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GolemToken()))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new PhyrexianGolemToken()))); // Whenever an artifact is put into a graveyard from the battlefield, put a +1/+1 counter on Ich-Tekik and a +1/+1 counter on each Golem you control. Ability ability = new PutIntoGraveFromBattlefieldAllTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/i/IchorRats.java b/Mage.Sets/src/mage/cards/i/IchorRats.java index d9a9a13dae6..6c7fcb39b3a 100644 --- a/Mage.Sets/src/mage/cards/i/IchorRats.java +++ b/Mage.Sets/src/mage/cards/i/IchorRats.java @@ -24,6 +24,7 @@ public final class IchorRats extends CardImpl { public IchorRats(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.RAT); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/i/IchorclawMyr.java b/Mage.Sets/src/mage/cards/i/IchorclawMyr.java index db36af568b1..c7441c698cd 100644 --- a/Mage.Sets/src/mage/cards/i/IchorclawMyr.java +++ b/Mage.Sets/src/mage/cards/i/IchorclawMyr.java @@ -20,6 +20,7 @@ public final class IchorclawMyr extends CardImpl { public IchorclawMyr(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.MYR); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/i/ImmolatingSouleater.java b/Mage.Sets/src/mage/cards/i/ImmolatingSouleater.java index a7ee6f69730..c795d8e54ec 100644 --- a/Mage.Sets/src/mage/cards/i/ImmolatingSouleater.java +++ b/Mage.Sets/src/mage/cards/i/ImmolatingSouleater.java @@ -22,6 +22,7 @@ public final class ImmolatingSouleater extends CardImpl { public ImmolatingSouleater(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DOG); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/i/ImpalerShrike.java b/Mage.Sets/src/mage/cards/i/ImpalerShrike.java index 8608e617a7d..74a1ee1f339 100644 --- a/Mage.Sets/src/mage/cards/i/ImpalerShrike.java +++ b/Mage.Sets/src/mage/cards/i/ImpalerShrike.java @@ -21,6 +21,7 @@ public final class ImpalerShrike extends CardImpl { public ImpalerShrike(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BIRD); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/i/InevitableBetrayal.java b/Mage.Sets/src/mage/cards/i/InevitableBetrayal.java new file mode 100644 index 00000000000..3afdd73ac37 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InevitableBetrayal.java @@ -0,0 +1,80 @@ +package mage.cards.i; + +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.SuspendAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InevitableBetrayal extends CardImpl { + + public InevitableBetrayal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, ""); + + this.color.setBlue(true); + + // Suspend 3—{1}{U}{U} + this.addAbility(new SuspendAbility(3, new ManaCostsImpl<>("{1}{U}{U}"), this)); + + // Search target opponent's library for a creature card and put that card onto the battlefield under your control. Then that player shuffles. + this.getSpellAbility().addEffect(new InevitableBetrayalEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + private InevitableBetrayal(final InevitableBetrayal card) { + super(card); + } + + @Override + public InevitableBetrayal copy() { + return new InevitableBetrayal(this); + } +} + +class InevitableBetrayalEffect extends OneShotEffect { + + InevitableBetrayalEffect() { + super(Outcome.Benefit); + staticText = "search target opponent's library for a creature card and put that card " + + "onto the battlefield under your control. Then that player shuffles"; + } + + private InevitableBetrayalEffect(final InevitableBetrayalEffect effect) { + super(effect); + } + + @Override + public InevitableBetrayalEffect copy() { + return new InevitableBetrayalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(source.getFirstTarget()); + if (controller == null || player == null) { + return false; + } + TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_CREATURE); + controller.searchLibrary(target, source, game, player.getId()); + Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + player.shuffleLibrary(source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/InkmothNexus.java b/Mage.Sets/src/mage/cards/i/InkmothNexus.java index 880d19cf647..ba181f82adc 100644 --- a/Mage.Sets/src/mage/cards/i/InkmothNexus.java +++ b/Mage.Sets/src/mage/cards/i/InkmothNexus.java @@ -33,7 +33,7 @@ public final class InkmothNexus extends CardImpl { // {1}: Inkmoth Nexus becomes a 1/1 Blinkmoth artifact creature with flying and infect until end of turn. It's still a land. (It deals damage to creatures in the form of -1/-1 counters and to players in the form of poison counters.) Effect effect = new BecomesCreatureSourceEffect(new InkmothNexusToken(), "land", Duration.EndOfTurn); - effect.setText("{this} becomes a 1/1 Blinkmoth artifact creature with flying and infect until end of turn. It's still a land. (It deals damage to creatures in the form of -1/-1 counters and to players in the form of poison counters.)"); + effect.setText("{this} becomes a 1/1 Phyrexian Blinkmoth artifact creature with flying and infect until end of turn. It's still a land. (It deals damage to creatures in the form of -1/-1 counters and to players in the form of poison counters.)"); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(1))); } @@ -49,9 +49,10 @@ public final class InkmothNexus extends CardImpl { class InkmothNexusToken extends TokenImpl { public InkmothNexusToken() { - super("Blinkmoth", "1/1 Blinkmoth artifact creature with flying and infect"); + super("Phyrexian Blinkmoth", "1/1 Phyrexian Blinkmoth artifact creature with flying and infect"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BLINKMOTH); power = new MageInt(1); toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/i/InquisitorExarch.java b/Mage.Sets/src/mage/cards/i/InquisitorExarch.java index 0c130d6b94f..c2ac1e11f29 100644 --- a/Mage.Sets/src/mage/cards/i/InquisitorExarch.java +++ b/Mage.Sets/src/mage/cards/i/InquisitorExarch.java @@ -22,6 +22,7 @@ public final class InquisitorExarch extends CardImpl { public InquisitorExarch(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{W}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/i/InsatiableSouleater.java b/Mage.Sets/src/mage/cards/i/InsatiableSouleater.java index d75eed0c29c..b6e2d3b19c9 100644 --- a/Mage.Sets/src/mage/cards/i/InsatiableSouleater.java +++ b/Mage.Sets/src/mage/cards/i/InsatiableSouleater.java @@ -23,6 +23,7 @@ public final class InsatiableSouleater extends CardImpl { public InsatiableSouleater(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BEAST); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/i/InvaderParasite.java b/Mage.Sets/src/mage/cards/i/InvaderParasite.java index cf730df4127..afce56d2f0c 100644 --- a/Mage.Sets/src/mage/cards/i/InvaderParasite.java +++ b/Mage.Sets/src/mage/cards/i/InvaderParasite.java @@ -30,6 +30,7 @@ public final class InvaderParasite extends CardImpl { public InvaderParasite(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.INSECT); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/j/JadeAvenger.java b/Mage.Sets/src/mage/cards/j/JadeAvenger.java new file mode 100644 index 00000000000..b9457873081 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JadeAvenger.java @@ -0,0 +1,37 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.keyword.BushidoAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JadeAvenger extends CardImpl { + + public JadeAvenger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.FROG); + this.subtype.add(SubType.SAMURAI); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Bushido 2 + this.addAbility(new BushidoAbility(2)); + } + + private JadeAvenger(final JadeAvenger card) { + super(card); + } + + @Override + public JadeAvenger copy() { + return new JadeAvenger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JewelEyedCobra.java b/Mage.Sets/src/mage/cards/j/JewelEyedCobra.java new file mode 100644 index 00000000000..85546f1285a --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JewelEyedCobra.java @@ -0,0 +1,42 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JewelEyedCobra extends CardImpl { + + public JewelEyedCobra(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.SNAKE); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // When Jewel-Eyed Cobra dies, create a Treasure token. + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new TreasureToken()))); + } + + private JewelEyedCobra(final JewelEyedCobra card) { + super(card); + } + + @Override + public JewelEyedCobra copy() { + return new JewelEyedCobra(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JinGitaxiasCoreAugur.java b/Mage.Sets/src/mage/cards/j/JinGitaxiasCoreAugur.java index 96f8d89edc5..13961872526 100644 --- a/Mage.Sets/src/mage/cards/j/JinGitaxiasCoreAugur.java +++ b/Mage.Sets/src/mage/cards/j/JinGitaxiasCoreAugur.java @@ -22,6 +22,7 @@ public final class JinGitaxiasCoreAugur extends CardImpl { public JinGitaxiasCoreAugur(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{8}{U}{U}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.PRAETOR); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/k/KaldraCompleat.java b/Mage.Sets/src/mage/cards/k/KaldraCompleat.java new file mode 100644 index 00000000000..d336cf27470 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KaldraCompleat.java @@ -0,0 +1,87 @@ +package mage.cards.k; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToACreatureTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.*; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.StaticFilters; + +/** + * + * @author weirddan455 + */ +public final class KaldraCompleat extends CardImpl { + + public KaldraCompleat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{7}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.EQUIPMENT); + + // Living weapon + this.addAbility(new LivingWeaponAbility()); + + // Indestructible + this.addAbility(IndestructibleAbility.getInstance()); + + // Equipped creature gets +5/+5 and has first strike, trample, indestructible, haste, and "Whenever this creature deals combat damage to a creature, exile that creature." + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(5, 5)); + ability.addEffect(new GainAbilityAttachedEffect( + FirstStrikeAbility.getInstance(), + AttachmentType.EQUIPMENT, + Duration.WhileOnBattlefield, + "and has first strike" + )); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), + AttachmentType.EQUIPMENT, + Duration.WhileOnBattlefield, + ", trample" + )); + ability.addEffect(new GainAbilityAttachedEffect( + IndestructibleAbility.getInstance(), + AttachmentType.EQUIPMENT, + Duration.WhileOnBattlefield, + ", indestructible" + )); + ability.addEffect(new GainAbilityAttachedEffect( + HasteAbility.getInstance(), + AttachmentType.EQUIPMENT, + Duration.WhileOnBattlefield, + ", haste" + )); + ability.addEffect(new GainAbilityAttachedEffect( + new DealsDamageToACreatureTriggeredAbility( + new ExileTargetEffect("exile that creature"), + true, + false, + true, + StaticFilters.FILTER_PERMANENT_CREATURE_A + ), + AttachmentType.EQUIPMENT, + Duration.WhileOnBattlefield, + ", and \"Whenever this creature deals combat damage to a creature, exile that creature.\"" + )); + this.addAbility(ability); + + // Equip {7} + this.addAbility(new EquipAbility(7)); + } + + private KaldraCompleat(final KaldraCompleat card) { + super(card); + } + + @Override + public KaldraCompleat copy() { + return new KaldraCompleat(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/Kaleidoscorch.java b/Mage.Sets/src/mage/cards/k/Kaleidoscorch.java new file mode 100644 index 00000000000..b33c8799e4e --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/Kaleidoscorch.java @@ -0,0 +1,41 @@ +package mage.cards.k; + +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.ColorsOfManaSpentToCastCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.FlashbackAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.TimingRule; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Kaleidoscorch extends CardImpl { + + public Kaleidoscorch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); + + // Converge — Kaleidoscorch deals X damage to any target, where X is the number of colors of mana spent to cast this spell. + this.getSpellAbility().addEffect(new DamageTargetEffect(ColorsOfManaSpentToCastCount.getInstance())); + this.getSpellAbility().addTarget(new TargetAnyTarget()); + this.getSpellAbility().setAbilityWord(AbilityWord.CONVERGE); + + // Flashback {4}{R} + this.addAbility(new FlashbackAbility(new ManaCostsImpl<>("{4}{R}"), TimingRule.SORCERY)); + } + + private Kaleidoscorch(final Kaleidoscorch card) { + super(card); + } + + @Override + public Kaleidoscorch copy() { + return new Kaleidoscorch(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KeskitTheFleshSculptor.java b/Mage.Sets/src/mage/cards/k/KeskitTheFleshSculptor.java index 8dfd0ab4cff..f1a3716bd85 100644 --- a/Mage.Sets/src/mage/cards/k/KeskitTheFleshSculptor.java +++ b/Mage.Sets/src/mage/cards/k/KeskitTheFleshSculptor.java @@ -42,6 +42,7 @@ public final class KeskitTheFleshSculptor extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ARTIFICER); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/k/KilnWalker.java b/Mage.Sets/src/mage/cards/k/KilnWalker.java index 2d1054fc1b4..ab8c70f078e 100644 --- a/Mage.Sets/src/mage/cards/k/KilnWalker.java +++ b/Mage.Sets/src/mage/cards/k/KilnWalker.java @@ -19,6 +19,7 @@ public final class KilnWalker extends CardImpl { public KilnWalker(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(0); diff --git a/Mage.Sets/src/mage/cards/k/KnightedMyr.java b/Mage.Sets/src/mage/cards/k/KnightedMyr.java new file mode 100644 index 00000000000..8e0c5855be3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnightedMyr.java @@ -0,0 +1,46 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.OneOrMoreCountersAddedTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.AdaptAbility; +import mage.abilities.keyword.DoubleStrikeAbility; +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 KnightedMyr extends CardImpl { + + public KnightedMyr(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.MYR); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {2}{W}: Adapt 1. + this.addAbility(new AdaptAbility(1, "{2}{W}")); + + // Whenever one or more +1/+1 counters are put on Knighted Myr, it gains double strike until end of turn. + this.addAbility(new OneOrMoreCountersAddedTriggeredAbility(new GainAbilitySourceEffect( + DoubleStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("it gains double strike until end of turn"))); + } + + private KnightedMyr(final KnightedMyr card) { + super(card); + } + + @Override + public KnightedMyr copy() { + return new KnightedMyr(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KrrikSonOfYawgmoth.java b/Mage.Sets/src/mage/cards/k/KrrikSonOfYawgmoth.java index f4aafa65196..e4656e2a872 100644 --- a/Mage.Sets/src/mage/cards/k/KrrikSonOfYawgmoth.java +++ b/Mage.Sets/src/mage/cards/k/KrrikSonOfYawgmoth.java @@ -43,6 +43,7 @@ public final class KrrikSonOfYawgmoth extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B/P}{B/P}{B/P}"); this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.subtype.add(SubType.MINION); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/l/LazotepChancellor.java b/Mage.Sets/src/mage/cards/l/LazotepChancellor.java new file mode 100644 index 00000000000..6cd2eb63b70 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LazotepChancellor.java @@ -0,0 +1,42 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DiscardCardControllerTriggeredAbility; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.keyword.AmassEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LazotepChancellor extends CardImpl { + + public LazotepChancellor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Whenever you discard a card, you may pay {1}. If you do, amass 2. + this.addAbility(new DiscardCardControllerTriggeredAbility( + new DoIfCostPaid(new AmassEffect(2), new GenericManaCost(1)), false + )); + } + + private LazotepChancellor(final LazotepChancellor card) { + super(card); + } + + @Override + public LazotepChancellor copy() { + return new LazotepChancellor(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/Leapfrog.java b/Mage.Sets/src/mage/cards/l/Leapfrog.java index b0f2cd6f660..9ddeea02e31 100644 --- a/Mage.Sets/src/mage/cards/l/Leapfrog.java +++ b/Mage.Sets/src/mage/cards/l/Leapfrog.java @@ -65,8 +65,6 @@ enum LeapfrogCondition implements Condition { return spells != null && spells .stream() .filter(Objects::nonNull) - .filter(MageObject::isInstantOrSorcery) - .map(Spell::getSourceId) - .anyMatch(source.getSourceId()::equals); + .anyMatch(MageObject::isInstantOrSorcery); } } diff --git a/Mage.Sets/src/mage/cards/l/LensFlare.java b/Mage.Sets/src/mage/cards/l/LensFlare.java new file mode 100644 index 00000000000..bc87ea67294 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LensFlare.java @@ -0,0 +1,36 @@ +package mage.cards.l; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.AffinityForArtifactsAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetAttackingOrBlockingCreature; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LensFlare extends CardImpl { + + public LensFlare(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{W}"); + + // Affinity for artifacts + this.addAbility(new AffinityForArtifactsAbility()); + + // Lens Flare deals 5 damage to target attacking or blocking creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + this.getSpellAbility().addTarget(new TargetAttackingOrBlockingCreature()); + } + + private LensFlare(final LensFlare card) { + super(card); + } + + @Override + public LensFlare copy() { + return new LensFlare(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LightningSpear.java b/Mage.Sets/src/mage/cards/l/LightningSpear.java new file mode 100644 index 00000000000..a9523063d60 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LightningSpear.java @@ -0,0 +1,59 @@ +package mage.cards.l; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LightningSpear extends CardImpl { + + public LightningSpear(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{R}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +1/+0 and has trample. + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(1, 0)); + ability.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), AttachmentType.EQUIPMENT + ).setText("and has trample")); + this.addAbility(ability); + + // {2}{R}, Sacrifice Lightning Spear: It deals 3 damage to any target. + ability = new SimpleActivatedAbility( + new DamageTargetEffect(3, "it"), new ManaCostsImpl<>("{2}{R}") + ); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + + // Equip {1} + this.addAbility(new EquipAbility(1)); + } + + private LightningSpear(final LightningSpear card) { + super(card); + } + + @Override + public LightningSpear copy() { + return new LightningSpear(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LiquimetalTorque.java b/Mage.Sets/src/mage/cards/l/LiquimetalTorque.java new file mode 100644 index 00000000000..5bf593522cf --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LiquimetalTorque.java @@ -0,0 +1,43 @@ +package mage.cards.l; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LiquimetalTorque extends CardImpl { + + public LiquimetalTorque(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Target nonland permanent becomes an artifact in addition to its other types until end of turn. + Ability ability = new SimpleActivatedAbility( + new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT), new TapSourceCost() + ); + ability.addTarget(new TargetNonlandPermanent()); + this.addAbility(ability); + } + + private LiquimetalTorque(final LiquimetalTorque card) { + super(card); + } + + @Override + public LiquimetalTorque copy() { + return new LiquimetalTorque(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LoathsomeCurator.java b/Mage.Sets/src/mage/cards/l/LoathsomeCurator.java new file mode 100644 index 00000000000..a8c5485f967 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LoathsomeCurator.java @@ -0,0 +1,63 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ExploitCreatureTriggeredAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.ExploitAbility; +import mage.abilities.keyword.MenaceAbility; +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.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LoathsomeCurator extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature you don't control with mana value 3 or less"); + + static { + filter.add(TargetController.NOT_YOU.getControllerPredicate()); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); + } + + public LoathsomeCurator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.GORGON); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Exploit + this.addAbility(new ExploitAbility()); + + // Menace + this.addAbility(new MenaceAbility()); + + // When Loathsome Curator exploits a creature, destroy target creature you don't control with mana value 3 or less. + Ability ability = new ExploitCreatureTriggeredAbility(new DestroyTargetEffect(), false); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private LoathsomeCurator(final LoathsomeCurator card) { + super(card); + } + + @Override + public LoathsomeCurator copy() { + return new LoathsomeCurator(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LonisCryptozoologist.java b/Mage.Sets/src/mage/cards/l/LonisCryptozoologist.java new file mode 100644 index 00000000000..32a8d29f7e9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LonisCryptozoologist.java @@ -0,0 +1,118 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeXTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.common.GetXValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.InvestigateEffect; +import mage.cards.*; +import mage.constants.*; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetOpponent; + +/** + * + * @author weirddan455 + */ +public final class LonisCryptozoologist extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another nontoken creature"); + private static final FilterControlledPermanent filter2 = new FilterControlledPermanent(SubType.CLUE, "Clues"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TokenPredicate.instance)); + } + + public LonisCryptozoologist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SNAKE); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Whenever another nontoken creature enters the battlefield under your control, investigate. + this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new InvestigateEffect(), filter, false, null, true)); + + // {T}, Sacrifice X Clues: Target opponent reveals the top X cards of their library. + // You may put a nonland permanent card with mana value X or less from among them onto the battlefield under your control. + // That player puts the rest on the bottom of their library in a random order. + Ability ability = new SimpleActivatedAbility(new LonisCryptozoologistEffect(), new TapSourceCost()); + ability.addCost(new SacrificeXTargetCost(filter2)); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private LonisCryptozoologist(final LonisCryptozoologist card) { + super(card); + } + + @Override + public LonisCryptozoologist copy() { + return new LonisCryptozoologist(this); + } +} + +class LonisCryptozoologistEffect extends OneShotEffect { + + public LonisCryptozoologistEffect() { + super(Outcome.PutCardInPlay); + this.staticText = "Target opponent reveals the top X cards of their library." + + " You may put a nonland permanent card with mana value X or less from among them onto the battlefield under your control." + + " That player puts the rest on the bottom of their library in a random order"; + } + + private LonisCryptozoologistEffect(final LonisCryptozoologistEffect effect) { + super(effect); + } + + @Override + public LonisCryptozoologistEffect copy() { + return new LonisCryptozoologistEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller != null && opponent != null) { + int xValue = GetXValue.instance.calculate(game, source, this); + Cards cards = new CardsImpl(opponent.getLibrary().getTopCards(game, xValue)); + opponent.revealCards(source, cards, game); + if (controller.chooseUse(outcome, "Put a nonland permanent card with mana value " + xValue + + " or less from among revealed cards onto the battlefield under your control?", source, game)) { + FilterPermanentCard filter = new FilterPermanentCard("nonland permanent card with mana value " + xValue + " or less"); + filter.add(Predicates.not(CardType.LAND.getPredicate())); + filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue + 1)); + TargetCard target = new TargetCard(Zone.LIBRARY, filter); + if (controller.choose(outcome, cards, target, game)) { + Card selectedCard = game.getCard(target.getFirstTarget()); + if (selectedCard != null) { + cards.remove(selectedCard); + controller.moveCards(selectedCard, Zone.BATTLEFIELD, source, game); + } + } + } + opponent.putCardsOnBottomOfLibrary(cards, game, source, false); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LostLeonin.java b/Mage.Sets/src/mage/cards/l/LostLeonin.java index b80e4bbf212..d7200e066bc 100644 --- a/Mage.Sets/src/mage/cards/l/LostLeonin.java +++ b/Mage.Sets/src/mage/cards/l/LostLeonin.java @@ -18,6 +18,7 @@ public final class LostLeonin extends CardImpl { public LostLeonin (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CAT); this.subtype.add(SubType.SOLDIER); diff --git a/Mage.Sets/src/mage/cards/l/LoxodonConvert.java b/Mage.Sets/src/mage/cards/l/LoxodonConvert.java index 5b855060575..1232bd23417 100644 --- a/Mage.Sets/src/mage/cards/l/LoxodonConvert.java +++ b/Mage.Sets/src/mage/cards/l/LoxodonConvert.java @@ -16,6 +16,7 @@ public final class LoxodonConvert extends CardImpl { public LoxodonConvert(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ELEPHANT); this.subtype.add(SubType.SOLDIER); diff --git a/Mage.Sets/src/mage/cards/l/LurkingEvil.java b/Mage.Sets/src/mage/cards/l/LurkingEvil.java index 668b982747f..ac141cce36b 100644 --- a/Mage.Sets/src/mage/cards/l/LurkingEvil.java +++ b/Mage.Sets/src/mage/cards/l/LurkingEvil.java @@ -33,7 +33,7 @@ public final class LurkingEvil extends CardImpl { // Pay half your life, rounded up: Lurking Evil becomes a 4/4 Horror creature with flying. Effect effect = new BecomesCreatureSourceEffect(new LurkingEvilToken(), null, Duration.EndOfGame, true, false); - effect.setText("{this} becomes a 4/4 Horror creature with flying"); + effect.setText("{this} becomes a 4/4 Phyrexian Horror creature with flying"); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new LurkingEvilCost())); } @@ -89,9 +89,10 @@ class LurkingEvilCost extends CostImpl { class LurkingEvilToken extends TokenImpl { LurkingEvilToken() { - super("Horror", "4/4 Horror creature with flying"); + super("Phyrexian Horror", "4/4 Phyrexian Horror creature with flying"); power = new MageInt(4); toughness = new MageInt(4); + subtype.add(SubType.PHYREXIAN); subtype.add(SubType.HORROR); cardType.add(CardType.CREATURE); this.addAbility(FlyingAbility.getInstance()); diff --git a/Mage.Sets/src/mage/cards/l/LurkingSkirge.java b/Mage.Sets/src/mage/cards/l/LurkingSkirge.java index 09f154f23ac..9c8e474aa5a 100644 --- a/Mage.Sets/src/mage/cards/l/LurkingSkirge.java +++ b/Mage.Sets/src/mage/cards/l/LurkingSkirge.java @@ -36,7 +36,7 @@ public final class LurkingSkirge extends CardImpl { // When a creature is put into an opponent's graveyard from the battlefield, if Lurking Skirge is an enchantment, Lurking Skirge becomes a 3/2 Imp creature with flying. TriggeredAbility ability = new PutIntoGraveFromBattlefieldAllTriggeredAbility(new BecomesCreatureSourceEffect(new LurkingSkirgeToken(), "", Duration.WhileOnBattlefield, true, false), false, filter, false); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_ENCHANTMENT_PERMANENT), - "When a creature is put into an opponent's graveyard from the battlefield, if {this} is an enchantment, {this} becomes a 3/2 Imp creature with flying.")); + "When a creature is put into an opponent's graveyard from the battlefield, if {this} is an enchantment, {this} becomes a 3/2 Phyrexian Imp creature with flying.")); } private LurkingSkirge(final LurkingSkirge card) { @@ -52,8 +52,9 @@ public final class LurkingSkirge extends CardImpl { class LurkingSkirgeToken extends TokenImpl { public LurkingSkirgeToken() { - super("Imp", "3/2 Imp with flying."); + super("Phyrexian Imp", "3/2 Phyrexian Imp with flying."); cardType.add(CardType.CREATURE); + subtype.add(SubType.PHYREXIAN); subtype.add(SubType.IMP); power = new MageInt(3); toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheBridge.java b/Mage.Sets/src/mage/cards/m/MagusOfTheBridge.java new file mode 100644 index 00000000000..d87ec7c5b97 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheBridge.java @@ -0,0 +1,99 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.ExileSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.ZombieToken; +import mage.players.Player; + +/** + * + * @author weirddan455 + */ +public final class MagusOfTheBridge extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a nontoken creature"); + + static { + filter.add(Predicates.not(TokenPredicate.instance)); + } + + public MagusOfTheBridge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever a nontoken creature is put into your graveyard from the battlefield, create a 2/2 black Zombie creature token. + this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility( + new CreateTokenEffect(new ZombieToken()), false, filter, false, true + )); + + // When a creature is put into an opponent's graveyard from the battlefield, exile Magus of the Bridge. + this.addAbility(new MagusOfTheBridgeTriggeredAbility()); + } + + private MagusOfTheBridge(final MagusOfTheBridge card) { + super(card); + } + + @Override + public MagusOfTheBridge copy() { + return new MagusOfTheBridge(this); + } +} + +class MagusOfTheBridgeTriggeredAbility extends TriggeredAbilityImpl { + + public MagusOfTheBridgeTriggeredAbility() { + super(Zone.BATTLEFIELD, new ExileSourceEffect()); + } + + private MagusOfTheBridgeTriggeredAbility(final MagusOfTheBridgeTriggeredAbility ability) { + super(ability); + } + + @Override + public MagusOfTheBridgeTriggeredAbility copy() { + return new MagusOfTheBridgeTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.isDiesEvent()) { + Permanent permanent = zEvent.getTarget(); + Player controller = game.getPlayer(getControllerId()); + return permanent != null && controller != null + && permanent.isCreature() && controller.hasOpponent(permanent.getOwnerId(), game); + } + return false; + } + + @Override + public String getRule() { + return "When a creature is put into an opponent's graveyard from the battlefield, " + super.getRule(); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MaraudingKnight.java b/Mage.Sets/src/mage/cards/m/MaraudingKnight.java index e40062705a7..5c392aa2a14 100644 --- a/Mage.Sets/src/mage/cards/m/MaraudingKnight.java +++ b/Mage.Sets/src/mage/cards/m/MaraudingKnight.java @@ -27,6 +27,7 @@ public final class MaraudingKnight extends CardImpl { public MaraudingKnight(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.KNIGHT); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/m/MarbleGargoyle.java b/Mage.Sets/src/mage/cards/m/MarbleGargoyle.java new file mode 100644 index 00000000000..3bbc44d2f39 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MarbleGargoyle.java @@ -0,0 +1,45 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FlyingAbility; +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 MarbleGargoyle extends CardImpl { + + public MarbleGargoyle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.GARGOYLE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {W}: Marble Gargoyle gets +0/+1 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(0, 1, Duration.EndOfTurn), new ManaCostsImpl<>("{W}") + )); + } + + private MarbleGargoyle(final MarbleGargoyle card) { + super(card); + } + + @Override + public MarbleGargoyle copy() { + return new MarbleGargoyle(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MassacreWurm.java b/Mage.Sets/src/mage/cards/m/MassacreWurm.java index 2bbd272e721..efab6b7e597 100644 --- a/Mage.Sets/src/mage/cards/m/MassacreWurm.java +++ b/Mage.Sets/src/mage/cards/m/MassacreWurm.java @@ -28,6 +28,7 @@ public final class MassacreWurm extends CardImpl { public MassacreWurm(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.WURM); this.power = new MageInt(6); diff --git a/Mage.Sets/src/mage/cards/m/MasterOfDeath.java b/Mage.Sets/src/mage/cards/m/MasterOfDeath.java new file mode 100644 index 00000000000..d4fbc80a7dd --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MasterOfDeath.java @@ -0,0 +1,54 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MasterOfDeath extends CardImpl { + + public MasterOfDeath(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // When Master of Death enters the battlefield, surveil 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SurveilEffect(2))); + + // At the beginning of your upkeep, if Master of Death is in your graveyard, you may pay 1 life. If you do, return it to your hand. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.GRAVEYARD, + new DoIfCostPaid( + new ReturnSourceFromGraveyardToHandEffect() + .setText("return it to your hand"), + new PayLifeCost(1) + ), TargetController.YOU, false + )); + } + + private MasterOfDeath(final MasterOfDeath card) { + super(card); + } + + @Override + public MasterOfDeath copy() { + return new MasterOfDeath(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MasterSplicer.java b/Mage.Sets/src/mage/cards/m/MasterSplicer.java index 9c88cb61aa9..febf3da2cd0 100644 --- a/Mage.Sets/src/mage/cards/m/MasterSplicer.java +++ b/Mage.Sets/src/mage/cards/m/MasterSplicer.java @@ -12,7 +12,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; -import mage.game.permanent.token.GolemToken; +import mage.game.permanent.token.PhyrexianGolemToken; import java.util.UUID; @@ -25,13 +25,14 @@ public final class MasterSplicer extends CardImpl { public MasterSplicer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ARTIFICER); this.power = new MageInt(1); this.toughness = new MageInt(1); - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GolemToken()))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new PhyrexianGolemToken()))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter, false))); } diff --git a/Mage.Sets/src/mage/cards/m/MaulSplicer.java b/Mage.Sets/src/mage/cards/m/MaulSplicer.java index 8c4aeef1e4d..366ad87e8c1 100644 --- a/Mage.Sets/src/mage/cards/m/MaulSplicer.java +++ b/Mage.Sets/src/mage/cards/m/MaulSplicer.java @@ -13,7 +13,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.game.permanent.token.GolemToken; +import mage.game.permanent.token.PhyrexianGolemToken; import java.util.UUID; @@ -31,6 +31,7 @@ public final class MaulSplicer extends CardImpl { public MaulSplicer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ARTIFICER); @@ -38,7 +39,7 @@ public final class MaulSplicer extends CardImpl { this.toughness = new MageInt(1); // When Maul Splicer enters the battlefield, create two 3/3 colorless Golem artifact creature tokens. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GolemToken(), 2))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new PhyrexianGolemToken(), 2))); // Golem creatures you control have trample. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter))); diff --git a/Mage.Sets/src/mage/cards/m/MeddlingMage.java b/Mage.Sets/src/mage/cards/m/MeddlingMage.java index 049fd87c83a..fbe56650a40 100644 --- a/Mage.Sets/src/mage/cards/m/MeddlingMage.java +++ b/Mage.Sets/src/mage/cards/m/MeddlingMage.java @@ -87,7 +87,6 @@ class MeddlingMageReplacementEffect extends ContinuousRuleModifyingEffectImpl { MageObject object = game.getObject(event.getSourceId()); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); return object != null - && !object.isCopy() && CardUtil.haveSameNames(object, cardName, game); } } diff --git a/Mage.Sets/src/mage/cards/m/MineCollapse.java b/Mage.Sets/src/mage/cards/m/MineCollapse.java new file mode 100644 index 00000000000..c389fdfd918 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MineCollapse.java @@ -0,0 +1,49 @@ +package mage.cards.m; + +import java.util.UUID; + +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.AlternativeCostSourceAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.hint.common.MyTurnHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreatureOrPlaneswalker; + +/** + * + * @author weirddan455 + */ +public final class MineCollapse extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.MOUNTAIN, "a Mountain"); + + public MineCollapse(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); + + // If it's your turn, you may sacrifice a Mountain rather than pay this spell's mana cost. + this.addAbility(new AlternativeCostSourceAbility( + new SacrificeTargetCost(new TargetControlledPermanent(filter)), + MyTurnCondition.instance, + "If it's your turn, you may sacrifice a Mountain rather than pay this spell's mana cost." + ).addHint(MyTurnHint.instance)); + + // Mine Collapse deals 5 damage to target creature or planeswalker. + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + } + + private MineCollapse(final MineCollapse card) { + super(card); + } + + @Override + public MineCollapse copy() { + return new MineCollapse(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/Moderation.java b/Mage.Sets/src/mage/cards/m/Moderation.java new file mode 100644 index 00000000000..9ed71375f9b --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Moderation.java @@ -0,0 +1,39 @@ +package mage.cards.m; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.CantCastMoreThanOneSpellEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Moderation extends CardImpl { + + public Moderation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{U}"); + + // You can't cast more than one spell each turn. + this.addAbility(new SimpleStaticAbility(new CantCastMoreThanOneSpellEffect(TargetController.YOU))); + + // Whenever you cast a spell, draw a card. + this.addAbility(new SpellCastControllerTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + )); + } + + private Moderation(final Moderation card) { + super(card); + } + + @Override + public Moderation copy() { + return new Moderation(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MoltensteelDragon.java b/Mage.Sets/src/mage/cards/m/MoltensteelDragon.java index 8a122be8e55..ad9430c080a 100644 --- a/Mage.Sets/src/mage/cards/m/MoltensteelDragon.java +++ b/Mage.Sets/src/mage/cards/m/MoltensteelDragon.java @@ -23,6 +23,7 @@ public final class MoltensteelDragon extends CardImpl { public MoltensteelDragon(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}{R/P}{R/P}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DRAGON); this.power = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/m/Morinfen.java b/Mage.Sets/src/mage/cards/m/Morinfen.java index db88cd87995..5af5dc21bd9 100644 --- a/Mage.Sets/src/mage/cards/m/Morinfen.java +++ b/Mage.Sets/src/mage/cards/m/Morinfen.java @@ -21,6 +21,7 @@ public final class Morinfen extends CardImpl { public Morinfen(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(5); this.toughness = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/m/MortisDogs.java b/Mage.Sets/src/mage/cards/m/MortisDogs.java index 79e16db707f..8452603ca2e 100644 --- a/Mage.Sets/src/mage/cards/m/MortisDogs.java +++ b/Mage.Sets/src/mage/cards/m/MortisDogs.java @@ -24,6 +24,7 @@ public final class MortisDogs extends CardImpl { public MortisDogs(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DOG); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/m/MountVelusManticore.java b/Mage.Sets/src/mage/cards/m/MountVelusManticore.java new file mode 100644 index 00000000000..7e89c53c291 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MountVelusManticore.java @@ -0,0 +1,85 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MountVelusManticore extends CardImpl { + + public MountVelusManticore(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{2}{R}{R}"); + + this.subtype.add(SubType.MANTICORE); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // At the beginning of combat on your turn, you may discard a card. When you do, Mount Velus Manticore deals X damage to any target, where X is the number of card types the discarded card has. + this.addAbility(new BeginningOfCombatTriggeredAbility( + new MountVelusManticoreEffect(), TargetController.YOU, false + )); + } + + private MountVelusManticore(final MountVelusManticore card) { + super(card); + } + + @Override + public MountVelusManticore copy() { + return new MountVelusManticore(this); + } +} + +class MountVelusManticoreEffect extends OneShotEffect { + + MountVelusManticoreEffect() { + super(Outcome.Benefit); + staticText = "you may discard a card. When you do, {this} deals X damage to any target, " + + "where X is the number of card types the discarded card has"; + } + + private MountVelusManticoreEffect(final MountVelusManticoreEffect effect) { + super(effect); + } + + @Override + public MountVelusManticoreEffect copy() { + return new MountVelusManticoreEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = player.discard(0, 1, false, source, game).getRandom(game); + if (card == null) { + return false; + } + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( + new DamageTargetEffect(card.getCardType().size()), false, "{this} deals X damage " + + "to any target, where X is the number of card types the discarded card has" + ); + ability.addTarget(new TargetAnyTarget()); + game.fireReflexiveTriggeredAbility(ability, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MurktideRegent.java b/Mage.Sets/src/mage/cards/m/MurktideRegent.java new file mode 100644 index 00000000000..b1bc5276390 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MurktideRegent.java @@ -0,0 +1,133 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.Card; +import mage.cards.Cards; +import mage.constants.SubType; +import mage.abilities.keyword.DelveAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.util.CardUtil; + +/** + * + * @author weirddan455 + */ +public final class MurktideRegent extends CardImpl { + + public MurktideRegent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}"); + + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Delve + this.addAbility(new DelveAbility()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Murktide Regent enters the battlefield with a +1/+1 counter on it for each instant and sorcery card exiled with it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(), MurktideRegentValue.instance, false), + "with a +1/+1 counter on it for each instant and sorcery card exiled with it" + )); + + // Whenever an instant or sorcery card leaves your graveyard, put a +1/+1 counter on Murktide Regent. + this.addAbility(new MurktideRegentTriggeredAbility()); + } + + private MurktideRegent(final MurktideRegent card) { + super(card); + } + + @Override + public MurktideRegent copy() { + return new MurktideRegent(this); + } +} + +enum MurktideRegentValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int amount = 0; + Cards delvedCards = (Cards) game.getState().getValue(CardUtil.getCardZoneString("delvedCards", sourceAbility.getSourceId(), game)); + if (delvedCards != null) { + for (UUID cardId : delvedCards) { + Card card = game.getCard(cardId); + if (card != null && card.isInstantOrSorcery()) { + amount++; + } + } + } + return amount; + } + + @Override + public MurktideRegentValue copy() { + return instance; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "instant and sorcery card exiled with it"; + } +} + +class MurktideRegentTriggeredAbility extends TriggeredAbilityImpl { + + public MurktideRegentTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + } + + private MurktideRegentTriggeredAbility(final MurktideRegentTriggeredAbility ability) { + super(ability); + } + + @Override + public MurktideRegentTriggeredAbility copy() { + return new MurktideRegentTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone() == Zone.GRAVEYARD) { + Card card = game.getCard(zEvent.getTargetId()); + return card != null && card.isInstantOrSorcery() && card.getOwnerId().equals(getControllerId()); + } + return false; + } + + @Override + public String getRule() { + return "Whenever an instant or sorcery card leaves your graveyard, " + super.getRule(); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MycosynthFiend.java b/Mage.Sets/src/mage/cards/m/MycosynthFiend.java index 895c8bde934..e13007a36b0 100644 --- a/Mage.Sets/src/mage/cards/m/MycosynthFiend.java +++ b/Mage.Sets/src/mage/cards/m/MycosynthFiend.java @@ -22,6 +22,7 @@ public final class MycosynthFiend extends CardImpl { public MycosynthFiend(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/m/MyrScrapling.java b/Mage.Sets/src/mage/cards/m/MyrScrapling.java new file mode 100644 index 00000000000..687a6080cff --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MyrScrapling.java @@ -0,0 +1,45 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MyrScrapling extends CardImpl { + + public MyrScrapling(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); + + this.subtype.add(SubType.MYR); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Sacrifice Myr Scrapling: Put a +1/+1 counter on target creature. + Ability ability = new SimpleActivatedAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new SacrificeSourceCost() + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private MyrScrapling(final MyrScrapling card) { + super(card); + } + + @Override + public MyrScrapling copy() { + return new MyrScrapling(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MyrSire.java b/Mage.Sets/src/mage/cards/m/MyrSire.java index 80b28b593c9..04adb1cb540 100644 --- a/Mage.Sets/src/mage/cards/m/MyrSire.java +++ b/Mage.Sets/src/mage/cards/m/MyrSire.java @@ -1,8 +1,5 @@ - - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; @@ -10,23 +7,25 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.permanent.token.MyrToken; +import mage.game.permanent.token.PhyrexianMyrToken; + +import java.util.UUID; /** - * * @author Loki */ public final class MyrSire extends CardImpl { - public MyrSire (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}"); + public MyrSire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.MYR); this.power = new MageInt(1); this.toughness = new MageInt(1); - this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new MyrToken()))); + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new PhyrexianMyrToken()))); } - public MyrSire (final MyrSire card) { + public MyrSire(final MyrSire card) { super(card); } @@ -34,5 +33,4 @@ public final class MyrSire extends CardImpl { public MyrSire copy() { return new MyrSire(this); } - } diff --git a/Mage.Sets/src/mage/cards/n/NecrogenScudder.java b/Mage.Sets/src/mage/cards/n/NecrogenScudder.java index 804bd41094f..04093299cdc 100644 --- a/Mage.Sets/src/mage/cards/n/NecrogenScudder.java +++ b/Mage.Sets/src/mage/cards/n/NecrogenScudder.java @@ -20,6 +20,7 @@ public final class NecrogenScudder extends CardImpl { public NecrogenScudder (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/n/Necrogoyf.java b/Mage.Sets/src/mage/cards/n/Necrogoyf.java new file mode 100644 index 00000000000..7201dab97dd --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/Necrogoyf.java @@ -0,0 +1,56 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; +import mage.abilities.effects.common.continuous.SetPowerSourceEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.keyword.MadnessAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Necrogoyf extends CardImpl { + + private static final DynamicValue xValue = new CardsInAllGraveyardsCount(StaticFilters.FILTER_CARD_CREATURES); + + public Necrogoyf(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.subtype.add(SubType.LHURGOYF); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Necrogoyf's power is equal to the number of creature cards in all graveyards. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SetPowerSourceEffect(xValue, Duration.EndOfGame) + )); + + // At the beginning of each player's upkeep, that player discards a card. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, new DiscardTargetEffect(1), + TargetController.EACH_PLAYER, false, true + )); + + // Madness {1}{B}{B} + this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{1}{B}{B}"))); + } + + private Necrogoyf(final Necrogoyf card) { + super(card); + } + + @Override + public Necrogoyf copy() { + return new Necrogoyf(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/Necropede.java b/Mage.Sets/src/mage/cards/n/Necropede.java index 5ec4b67ac1a..5234c9345ba 100644 --- a/Mage.Sets/src/mage/cards/n/Necropede.java +++ b/Mage.Sets/src/mage/cards/n/Necropede.java @@ -23,6 +23,7 @@ public final class Necropede extends CardImpl { public Necropede (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.INSECT); this.power = new MageInt(1); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/n/NestedGhoul.java b/Mage.Sets/src/mage/cards/n/NestedGhoul.java index bf65048e36b..7eecaa1a7ac 100644 --- a/Mage.Sets/src/mage/cards/n/NestedGhoul.java +++ b/Mage.Sets/src/mage/cards/n/NestedGhoul.java @@ -13,6 +13,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; +import mage.game.permanent.token.PhyrexianZombieToken; import mage.game.permanent.token.ZombieToken; /** @@ -23,6 +24,7 @@ public final class NestedGhoul extends CardImpl { public NestedGhoul(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.WARRIOR); @@ -45,7 +47,7 @@ public final class NestedGhoul extends CardImpl { class NestedGhoulTriggeredAbility extends TriggeredAbilityImpl { NestedGhoulTriggeredAbility() { - super(Zone.BATTLEFIELD, new CreateTokenEffect(new ZombieToken())); + super(Zone.BATTLEFIELD, new CreateTokenEffect(new PhyrexianZombieToken())); } NestedGhoulTriggeredAbility(final NestedGhoulTriggeredAbility ability) { @@ -69,6 +71,6 @@ class NestedGhoulTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a source deals damage to {this}, create a 2/2 black Zombie creature token."; + return "Whenever a source deals damage to {this}, create a 2/2 black Phyrexian Zombie creature token."; } } diff --git a/Mage.Sets/src/mage/cards/n/NestedShambler.java b/Mage.Sets/src/mage/cards/n/NestedShambler.java new file mode 100644 index 00000000000..6a19ea125d4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NestedShambler.java @@ -0,0 +1,44 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.SquirrelToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NestedShambler extends CardImpl { + + private static final DynamicValue xValue = new SourcePermanentPowerCount(false); + + public NestedShambler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Nested Shambler dies, create X tapped 1/1 green Squirrel creature tokens, where X is Nested Shambler's power. + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect( + new SquirrelToken(), xValue, true, false + ))); + } + + private NestedShambler(final NestedShambler card) { + super(card); + } + + @Override + public NestedShambler copy() { + return new NestedShambler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/Nettlecyst.java b/Mage.Sets/src/mage/cards/n/Nettlecyst.java new file mode 100644 index 00000000000..ea283a0a5fd --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/Nettlecyst.java @@ -0,0 +1,61 @@ +package mage.cards.n; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.LivingWeaponAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterArtifactOrEnchantmentPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Nettlecyst extends CardImpl { + + private static final FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent(); + + static { + filter.add(TargetController.YOU.getControllerPredicate()); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Artifacts and enchantments you control", xValue); + + public Nettlecyst(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Living weapon + this.addAbility(new LivingWeaponAbility()); + + // Equipped creature gets +1/+1 for each artifact and/or enchantment you control. + this.addAbility(new SimpleStaticAbility( + new BoostEquippedEffect(xValue, xValue) + .setText("equipped creature gets +1/+1 for each artifact and/or enchantment you control") + ).addHint(hint)); + + // Equip {2} + this.addAbility(new EquipAbility(2)); + } + + private Nettlecyst(final Nettlecyst card) { + super(card); + } + + @Override + public Nettlecyst copy() { + return new Nettlecyst(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NineRingedBo.java b/Mage.Sets/src/mage/cards/n/NineRingedBo.java index 70fdc0e87f7..9820975f238 100644 --- a/Mage.Sets/src/mage/cards/n/NineRingedBo.java +++ b/Mage.Sets/src/mage/cards/n/NineRingedBo.java @@ -1,9 +1,7 @@ - package mage.cards.n; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.ExileTargetIfDiesEffect; @@ -11,29 +9,26 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX */ public final class NineRingedBo extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("spirit"); - - static { - filter.add(SubType.SPIRIT.getPredicate()); - } + private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.SPIRIT, "Spirit creature"); public NineRingedBo(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // {T}: Nine-Ringed Bo deals 1 damage to target Spirit creature. If that creature would die this turn, exile it instead. - Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new TapSourceCost()); ability.addEffect(new ExileTargetIfDiesEffect()); - ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/n/NykthosParagon.java b/Mage.Sets/src/mage/cards/n/NykthosParagon.java new file mode 100644 index 00000000000..40ffbb9a8b0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NykthosParagon.java @@ -0,0 +1,140 @@ +package mage.cards.n; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * + * @author weirddan455 + */ +public final class NykthosParagon extends CardImpl { + + public NykthosParagon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{4}{W}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(4); + this.toughness = new MageInt(6); + + // Whenever you gain life, you may put that many +1/+1 counters on each creature you control. Do this only once each turn. + this.addAbility(new NykthosParagonTriggeredAbility()); + } + + private NykthosParagon(final NykthosParagon card) { + super(card); + } + + @Override + public NykthosParagon copy() { + return new NykthosParagon(this); + } +} + +class NykthosParagonTriggeredAbility extends TriggeredAbilityImpl { + + public NykthosParagonTriggeredAbility() { + super(Zone.BATTLEFIELD, new NykthosParagonEffect(), true); + } + + private NykthosParagonTriggeredAbility(final NykthosParagonTriggeredAbility ability) { + super(ability); + } + + @Override + public NykthosParagonTriggeredAbility copy() { + return new NykthosParagonTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.GAINED_LIFE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (abilityAvailableThisTurn(game) && event.getPlayerId().equals(this.getControllerId())) { + for (Effect effect : this.getEffects()) { + effect.setValue("gainedLife", event.getAmount()); + } + return true; + } + return false; + } + + @Override + public boolean resolve(Game game) { + if (abilityAvailableThisTurn(game) && super.resolve(game)) { + game.getState().setValue(CardUtil.getCardZoneString( + "lastTurnResolved" + originalId, sourceId, game + ), game.getTurnNum()); + return true; + } + return false; + } + + private boolean abilityAvailableThisTurn(Game game) { + Integer lastTurnResolved = (Integer) game.getState().getValue( + CardUtil.getCardZoneString("lastTurnResolved" + originalId, sourceId, game) + ); + return lastTurnResolved == null || lastTurnResolved != game.getTurnNum(); + } + + @Override + public String getRule() { + return "Whenever you gain life, you may put that many +1/+1 counters on each creature you control. Do this only once each turn."; + } +} + +class NykthosParagonEffect extends OneShotEffect { + + public NykthosParagonEffect() { + super(Outcome.BoostCreature); + } + + private NykthosParagonEffect(final NykthosParagonEffect effect) { + super(effect); + } + + @Override + public NykthosParagonEffect copy() { + return new NykthosParagonEffect(this); + } + + @Override + public boolean apply (Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + Integer life = (Integer) this.getValue("gainedLife"); + if (controller != null && sourceObject != null && life != null) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { + if (permanent != null && permanent.isCreature()) { + permanent.addCounters(CounterType.P1P1.createInstance(life), source.getControllerId(), source, game); + if (!game.isSimulation()) { + game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " puts " + life + + " +1/+1 counters on " + permanent.getLogName()); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/o/Oculus.java b/Mage.Sets/src/mage/cards/o/Oculus.java index ee4129d7b93..0d7450f024c 100644 --- a/Mage.Sets/src/mage/cards/o/Oculus.java +++ b/Mage.Sets/src/mage/cards/o/Oculus.java @@ -19,6 +19,7 @@ public final class Oculus extends CardImpl { public Oculus (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HOMUNCULUS); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/o/OgreMenial.java b/Mage.Sets/src/mage/cards/o/OgreMenial.java index ceffc6711f6..e14899e7726 100644 --- a/Mage.Sets/src/mage/cards/o/OgreMenial.java +++ b/Mage.Sets/src/mage/cards/o/OgreMenial.java @@ -22,6 +22,7 @@ public final class OgreMenial extends CardImpl { public OgreMenial(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.OGRE); this.power = new MageInt(0); diff --git a/Mage.Sets/src/mage/cards/o/OrderOfYawgmoth.java b/Mage.Sets/src/mage/cards/o/OrderOfYawgmoth.java index 89a3089deb1..3f06a90e66b 100644 --- a/Mage.Sets/src/mage/cards/o/OrderOfYawgmoth.java +++ b/Mage.Sets/src/mage/cards/o/OrderOfYawgmoth.java @@ -19,6 +19,7 @@ public final class OrderOfYawgmoth extends CardImpl { public OrderOfYawgmoth(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.KNIGHT); diff --git a/Mage.Sets/src/mage/cards/o/OrnithopterOfParadise.java b/Mage.Sets/src/mage/cards/o/OrnithopterOfParadise.java new file mode 100644 index 00000000000..fd045c2c3c4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OrnithopterOfParadise.java @@ -0,0 +1,40 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OrnithopterOfParadise extends CardImpl { + + public OrnithopterOfParadise(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + + this.subtype.add(SubType.THOPTER); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + } + + private OrnithopterOfParadise(final OrnithopterOfParadise card) { + super(card); + } + + @Override + public OrnithopterOfParadise copy() { + return new OrnithopterOfParadise(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OutOfTime.java b/Mage.Sets/src/mage/cards/o/OutOfTime.java new file mode 100644 index 00000000000..02a4c1188ca --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OutOfTime.java @@ -0,0 +1,194 @@ +package mage.cards.o; + +import java.util.*; + +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.PhaseOutAllEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.VanishingSacrificeAbility; +import mage.abilities.keyword.VanishingUpkeepAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +/** + * + * @author weirddan455 + */ +public final class OutOfTime extends CardImpl { + + public OutOfTime(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}"); + + // When Out of Time enters the battlefield, untap all creatures, then phase them out until Out of Time leaves the battlefield. + // Put a time counter on Out of Time for each creature phased out this way. + this.addAbility(new EntersBattlefieldTriggeredAbility(new OutOfTimePhaseOutEffect())); + + // Vanishing + this.addAbility(new VanishingUpkeepAbility(0, "enchantment")); + this.addAbility(new VanishingSacrificeAbility()); + } + + private OutOfTime(final OutOfTime card) { + super(card); + } + + @Override + public OutOfTime copy() { + return new OutOfTime(this); + } +} + +class OutOfTimePhaseOutEffect extends OneShotEffect { + + public OutOfTimePhaseOutEffect() { + super(Outcome.Detriment); + this.staticText = "untap all creatures, then phase them out until {this} leaves the battlefield. " + + "Put a time counter on {this} for each creature phased out this way"; + } + + private OutOfTimePhaseOutEffect(final OutOfTimePhaseOutEffect effect) { + super(effect); + } + + @Override + public OutOfTimePhaseOutEffect copy() { + return new OutOfTimePhaseOutEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List creatures = game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game); + int numCreatures = creatures.size(); + if (numCreatures > 0) { + Set creatureIds = new HashSet<>(numCreatures); + for (Permanent creature : creatures) { + creature.untap(game); + creatureIds.add(creature.getId()); + } + // https://magic.wizards.com/en/articles/archive/feature/modern-horizons-2-release-notes-2021-06-04 + // If Out of Time leaves the battlefield before its enter the battlefield trigger resolves, creatures will untap, but they won't phase out. + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + new PhaseOutAllEffect(new ArrayList<>(creatureIds)).apply(game, source); + new AddCountersSourceEffect(CounterType.TIME.createInstance(numCreatures)).apply(game, source); + game.getState().setValue(CardUtil.getCardZoneString("phasedOutCreatures", source.getSourceId(), game), creatureIds); + game.addDelayedTriggeredAbility(new OutOfTimeDelayedTriggeredAbility(), source); + game.addEffect(new OutOfTimeReplcementEffect(), source); + } + } + return true; + } +} + +class OutOfTimeDelayedTriggeredAbility extends DelayedTriggeredAbility { + + public OutOfTimeDelayedTriggeredAbility() { + super(new OutOfTimeLeavesBattlefieldEffect(), Duration.OneUse); + this.usesStack = false; + this.setRuleVisible(false); + } + + private OutOfTimeDelayedTriggeredAbility(final OutOfTimeDelayedTriggeredAbility ability) { + super(ability); + } + + @Override + public OutOfTimeDelayedTriggeredAbility copy() { + return new OutOfTimeDelayedTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getTargetId().equals(this.getSourceId())) { + return ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD; + } + return false; + } +} + +class OutOfTimeLeavesBattlefieldEffect extends OneShotEffect { + + public OutOfTimeLeavesBattlefieldEffect() { + super(Outcome.Benefit); + } + + private OutOfTimeLeavesBattlefieldEffect(final OutOfTimeLeavesBattlefieldEffect effect) { + super(effect); + } + + @Override + public OutOfTimeLeavesBattlefieldEffect copy() { + return new OutOfTimeLeavesBattlefieldEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Set creatureIds = (Set) game.getState().getValue(CardUtil.getCardZoneString( + "phasedOutCreatures", source.getSourceId(), game, true)); + if (creatureIds != null) { + for (UUID creatureId : creatureIds) { + Permanent creature = game.getPermanent(creatureId); + if (creature != null && !creature.isPhasedIn()) { + creature.phaseIn(game); + } + } + return true; + } + return false; + } +} + +// Stops creatures from phasing back in on their controller's next turn +class OutOfTimeReplcementEffect extends ReplacementEffectImpl { + + public OutOfTimeReplcementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + } + + private OutOfTimeReplcementEffect(final OutOfTimeReplcementEffect effect) { + super(effect); + } + + @Override + public OutOfTimeReplcementEffect copy() { + return new OutOfTimeReplcementEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.PHASE_IN; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Set creatureIds = (Set) game.getState().getValue(CardUtil.getCardZoneString( + "phasedOutCreatures", source.getSourceId(), game)); + return creatureIds != null && creatureIds.contains(event.getTargetId()); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/p/ParasiticImplant.java b/Mage.Sets/src/mage/cards/p/ParasiticImplant.java index 59f030d42fe..79524906bdb 100644 --- a/Mage.Sets/src/mage/cards/p/ParasiticImplant.java +++ b/Mage.Sets/src/mage/cards/p/ParasiticImplant.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -11,33 +9,33 @@ import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.TargetController; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.token.MyrToken; +import mage.game.permanent.token.PhyrexianMyrToken; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class ParasiticImplant extends CardImpl { public ParasiticImplant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); this.subtype.add(SubType.AURA); - TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.Sacrifice)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); ability = new BeginningOfUpkeepTriggeredAbility(new ParasiticImplantEffect(), TargetController.YOU, false); - ability.addEffect(new CreateTokenEffect(new MyrToken("NPH"))); + ability.addEffect(new CreateTokenEffect(new PhyrexianMyrToken())); this.addAbility(ability); } @@ -78,4 +76,4 @@ class ParasiticImplantEffect extends OneShotEffect { public ParasiticImplantEffect copy() { return new ParasiticImplantEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/p/ParcelMyr.java b/Mage.Sets/src/mage/cards/p/ParcelMyr.java new file mode 100644 index 00000000000..a52322bf5d0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ParcelMyr.java @@ -0,0 +1,45 @@ +package mage.cards.p; + +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.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ParcelMyr extends CardImpl { + + public ParcelMyr(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.CLUE); + this.subtype.add(SubType.MYR); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {2}, Sacrifice Parcel Myr: Draw a card + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), new GenericManaCost(2) + ); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private ParcelMyr(final ParcelMyr card) { + super(card); + } + + @Override + public ParcelMyr copy() { + return new ParcelMyr(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PerilousMyr.java b/Mage.Sets/src/mage/cards/p/PerilousMyr.java index 2c5f45dc876..afbf76a9d9a 100644 --- a/Mage.Sets/src/mage/cards/p/PerilousMyr.java +++ b/Mage.Sets/src/mage/cards/p/PerilousMyr.java @@ -20,6 +20,7 @@ public final class PerilousMyr extends CardImpl { public PerilousMyr(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.MYR); this.power = new MageInt(1); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/p/Persist.java b/Mage.Sets/src/mage/cards/p/Persist.java new file mode 100644 index 00000000000..87fd0feffcd --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/Persist.java @@ -0,0 +1,43 @@ +package mage.cards.p; + +import java.util.UUID; + +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldWithCounterTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.Predicates; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author weirddan455 + */ +public final class Persist extends CardImpl { + + private static final FilterCreatureCard filter = new FilterCreatureCard("nonlegendary creature card from your graveyard"); + + static { + filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); + } + + public Persist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); + + // Return target nonlegendary creature card from your graveyard to the battlefield with a -1/-1 counter on it. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(CounterType.M1M1.createInstance())); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + } + + private Persist(final Persist card) { + super(card); + } + + @Override + public Persist copy() { + return new Persist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PestilentSouleater.java b/Mage.Sets/src/mage/cards/p/PestilentSouleater.java index ffb9e5fe880..d9b448d4428 100644 --- a/Mage.Sets/src/mage/cards/p/PestilentSouleater.java +++ b/Mage.Sets/src/mage/cards/p/PestilentSouleater.java @@ -23,6 +23,7 @@ public final class PestilentSouleater extends CardImpl { public PestilentSouleater(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{5}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.INSECT); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianBattleflies.java b/Mage.Sets/src/mage/cards/p/PhyrexianBattleflies.java index 3b2b0c9e611..7d45906c444 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianBattleflies.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianBattleflies.java @@ -22,6 +22,7 @@ public final class PhyrexianBattleflies extends CardImpl { public PhyrexianBattleflies(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.INSECT); this.power = new MageInt(0); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianBloodstock.java b/Mage.Sets/src/mage/cards/p/PhyrexianBloodstock.java index eb56be94700..5b9fe000e32 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianBloodstock.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianBloodstock.java @@ -29,6 +29,7 @@ public final class PhyrexianBloodstock extends CardImpl { public PhyrexianBloodstock(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(3); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianBroodlings.java b/Mage.Sets/src/mage/cards/p/PhyrexianBroodlings.java index b9ad0325b52..f7cfd84feb2 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianBroodlings.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianBroodlings.java @@ -25,6 +25,7 @@ public final class PhyrexianBroodlings extends CardImpl { public PhyrexianBroodlings(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.MINION); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianColossus.java b/Mage.Sets/src/mage/cards/p/PhyrexianColossus.java index a8c10394f0d..41efa4e30eb 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianColossus.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianColossus.java @@ -23,6 +23,7 @@ public final class PhyrexianColossus extends CardImpl { public PhyrexianColossus(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{7}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.GOLEM); this.power = new MageInt(8); this.toughness = new MageInt(8); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianCrusader.java b/Mage.Sets/src/mage/cards/p/PhyrexianCrusader.java index 4f866559bc2..8cb0097d494 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianCrusader.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianCrusader.java @@ -21,6 +21,7 @@ public final class PhyrexianCrusader extends CardImpl { public PhyrexianCrusader(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.KNIGHT); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianDebaser.java b/Mage.Sets/src/mage/cards/p/PhyrexianDebaser.java index 04b7d3cd855..d97cbdfaa63 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianDebaser.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianDebaser.java @@ -25,6 +25,7 @@ public final class PhyrexianDebaser extends CardImpl { public PhyrexianDebaser(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CARRIER); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianDefiler.java b/Mage.Sets/src/mage/cards/p/PhyrexianDefiler.java index ef48e2f84b4..6d0a9a24f10 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianDefiler.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianDefiler.java @@ -24,6 +24,7 @@ public final class PhyrexianDefiler extends CardImpl { public PhyrexianDefiler(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CARRIER); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianDelver.java b/Mage.Sets/src/mage/cards/p/PhyrexianDelver.java index cd04e49362f..b7dc555b964 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianDelver.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianDelver.java @@ -27,6 +27,7 @@ public final class PhyrexianDelver extends CardImpl { public PhyrexianDelver(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianDenouncer.java b/Mage.Sets/src/mage/cards/p/PhyrexianDenouncer.java index 430ba97e7b8..5c596ffad95 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianDenouncer.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianDenouncer.java @@ -24,6 +24,7 @@ public final class PhyrexianDenouncer extends CardImpl { public PhyrexianDenouncer(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CARRIER); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianDevourer.java b/Mage.Sets/src/mage/cards/p/PhyrexianDevourer.java index a6bea763ef5..88c41c0f2a9 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianDevourer.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianDevourer.java @@ -32,6 +32,7 @@ public final class PhyrexianDevourer extends CardImpl { public PhyrexianDevourer(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{6}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(1); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianDigester.java b/Mage.Sets/src/mage/cards/p/PhyrexianDigester.java index 02f437763db..7f4d7d73622 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianDigester.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianDigester.java @@ -18,6 +18,7 @@ public final class PhyrexianDigester extends CardImpl { public PhyrexianDigester (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(2); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java b/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java index c8f0c49bc24..a036ab16ca5 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java @@ -29,6 +29,7 @@ public final class PhyrexianDreadnought extends CardImpl { public PhyrexianDreadnought(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DREADNOUGHT); this.power = new MageInt(12); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianDriver.java b/Mage.Sets/src/mage/cards/p/PhyrexianDriver.java index cc1c72e13c2..c3f47d64eb9 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianDriver.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianDriver.java @@ -25,6 +25,7 @@ public final class PhyrexianDriver extends CardImpl { public PhyrexianDriver(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.MERCENARY); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianGargantua.java b/Mage.Sets/src/mage/cards/p/PhyrexianGargantua.java index 37dce20cca4..a3f6df076d4 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianGargantua.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianGargantua.java @@ -20,6 +20,7 @@ public final class PhyrexianGargantua extends CardImpl { public PhyrexianGargantua(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianGhoul.java b/Mage.Sets/src/mage/cards/p/PhyrexianGhoul.java index 72c98e9a71b..b8334fd6cb4 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianGhoul.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianGhoul.java @@ -23,6 +23,7 @@ public final class PhyrexianGhoul extends CardImpl { public PhyrexianGhoul(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianGremlins.java b/Mage.Sets/src/mage/cards/p/PhyrexianGremlins.java index ded2cb376a1..a96aeb80ccc 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianGremlins.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianGremlins.java @@ -24,6 +24,7 @@ public final class PhyrexianGremlins extends CardImpl { public PhyrexianGremlins(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.GREMLIN); this.power = new MageInt(1); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianHulk.java b/Mage.Sets/src/mage/cards/p/PhyrexianHulk.java index 31f33cc063e..477768c9770 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianHulk.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianHulk.java @@ -16,6 +16,7 @@ public final class PhyrexianHulk extends CardImpl { public PhyrexianHulk(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{6}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.GOLEM); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianHydra.java b/Mage.Sets/src/mage/cards/p/PhyrexianHydra.java index 047e72c39cf..9618dc9ec0e 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianHydra.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianHydra.java @@ -28,6 +28,7 @@ public final class PhyrexianHydra extends CardImpl { public PhyrexianHydra(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HYDRA); this.power = new MageInt(7); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianInfiltrator.java b/Mage.Sets/src/mage/cards/p/PhyrexianInfiltrator.java index 0c1b60c6b21..1ff5018dd8a 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianInfiltrator.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianInfiltrator.java @@ -23,6 +23,7 @@ public final class PhyrexianInfiltrator extends CardImpl { public PhyrexianInfiltrator(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.MINION); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianIngester.java b/Mage.Sets/src/mage/cards/p/PhyrexianIngester.java index a3663b8f253..333c7b2efdf 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianIngester.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianIngester.java @@ -41,6 +41,7 @@ public final class PhyrexianIngester extends CardImpl { public PhyrexianIngester(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BEAST); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianIronfoot.java b/Mage.Sets/src/mage/cards/p/PhyrexianIronfoot.java index aedbc1eb91a..8dac37ec770 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianIronfoot.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianIronfoot.java @@ -24,6 +24,7 @@ public final class PhyrexianIronfoot extends CardImpl { public PhyrexianIronfoot(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); this.addSuperType(SuperType.SNOW); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(3); this.toughness = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianJuggernaut.java b/Mage.Sets/src/mage/cards/p/PhyrexianJuggernaut.java index b49b5951d31..54d97d43d09 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianJuggernaut.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianJuggernaut.java @@ -19,6 +19,7 @@ public final class PhyrexianJuggernaut extends CardImpl { public PhyrexianJuggernaut (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{6}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.JUGGERNAUT); this.power = new MageInt(5); this.toughness = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianMarauder.java b/Mage.Sets/src/mage/cards/p/PhyrexianMarauder.java index 49572995d8c..4a851f03506 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianMarauder.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianMarauder.java @@ -29,6 +29,7 @@ public final class PhyrexianMarauder extends CardImpl { public PhyrexianMarauder(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{X}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(0); this.toughness = new MageInt(0); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianMetamorph.java b/Mage.Sets/src/mage/cards/p/PhyrexianMetamorph.java index eb7773ffb77..e50d5505b89 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianMetamorph.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianMetamorph.java @@ -35,6 +35,7 @@ public final class PhyrexianMetamorph extends CardImpl { public PhyrexianMetamorph(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{U/P}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SHAPESHIFTER); this.power = new MageInt(0); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianMonitor.java b/Mage.Sets/src/mage/cards/p/PhyrexianMonitor.java index 3fb874d210a..282168ae6a6 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianMonitor.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianMonitor.java @@ -20,6 +20,7 @@ public final class PhyrexianMonitor extends CardImpl { public PhyrexianMonitor(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SKELETON); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianNegator.java b/Mage.Sets/src/mage/cards/p/PhyrexianNegator.java index 3f22d7d60fb..db1318db6f8 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianNegator.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianNegator.java @@ -26,6 +26,7 @@ public final class PhyrexianNegator extends CardImpl { public PhyrexianNegator(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianObliterator.java b/Mage.Sets/src/mage/cards/p/PhyrexianObliterator.java index 7a317304466..31b0acd27f5 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianObliterator.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianObliterator.java @@ -27,6 +27,7 @@ public final class PhyrexianObliterator extends CardImpl { public PhyrexianObliterator(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{B}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianPlaguelord.java b/Mage.Sets/src/mage/cards/p/PhyrexianPlaguelord.java index f60ad774345..6c4d05ec56a 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianPlaguelord.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianPlaguelord.java @@ -27,6 +27,7 @@ public final class PhyrexianPlaguelord extends CardImpl { public PhyrexianPlaguelord(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CARRIER); this.power = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java b/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java index 03852614e85..2333d2abfb8 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java @@ -92,7 +92,7 @@ class PhyrexianProcessorCreateTokenEffect extends OneShotEffect { PhyrexianProcessorCreateTokenEffect() { super(Outcome.PutCreatureInPlay); - staticText = "Create an X/X black Minion creature token, " + + staticText = "Create an X/X black Phyrexian Minion creature token, " + "where X is the life paid as {this} entered the battlefield."; } diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianProwler.java b/Mage.Sets/src/mage/cards/p/PhyrexianProwler.java index 23e6c2fc698..92db310ee74 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianProwler.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianProwler.java @@ -23,6 +23,7 @@ public final class PhyrexianProwler extends CardImpl { public PhyrexianProwler(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.MERCENARY); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianRager.java b/Mage.Sets/src/mage/cards/p/PhyrexianRager.java index 91a37d4fba3..a3e6ad0e9a0 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianRager.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianRager.java @@ -19,6 +19,7 @@ public final class PhyrexianRager extends CardImpl { public PhyrexianRager(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianReaper.java b/Mage.Sets/src/mage/cards/p/PhyrexianReaper.java index c959a2802b6..3c78c06997b 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianReaper.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianReaper.java @@ -27,6 +27,7 @@ public final class PhyrexianReaper extends CardImpl { public PhyrexianReaper(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(3); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianRebirth.java b/Mage.Sets/src/mage/cards/p/PhyrexianRebirth.java index 22bd1af0a12..e477bdb797f 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianRebirth.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianRebirth.java @@ -38,7 +38,7 @@ public final class PhyrexianRebirth extends CardImpl { private PhyrexianRebirthEffect() { super(Outcome.DestroyPermanent); - staticText = "Destroy all creatures, then create an X/X colorless Horror artifact creature token, " + + staticText = "Destroy all creatures, then create an X/X colorless Phyrexian Horror artifact creature token, " + "where X is the number of creatures destroyed this way"; } diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianRevoker.java b/Mage.Sets/src/mage/cards/p/PhyrexianRevoker.java index 06e0e58a258..0f8cec5c36b 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianRevoker.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianRevoker.java @@ -24,6 +24,7 @@ public final class PhyrexianRevoker extends CardImpl { public PhyrexianRevoker(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianScuta.java b/Mage.Sets/src/mage/cards/p/PhyrexianScuta.java index cb3bae29fc7..dc20822ee15 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianScuta.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianScuta.java @@ -23,6 +23,7 @@ public final class PhyrexianScuta extends CardImpl { public PhyrexianScuta(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(3); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianSlayer.java b/Mage.Sets/src/mage/cards/p/PhyrexianSlayer.java index 73fd21fb32a..530a39fc9f8 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianSlayer.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianSlayer.java @@ -28,6 +28,7 @@ public final class PhyrexianSlayer extends CardImpl { public PhyrexianSlayer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.MINION); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianSnowcrusher.java b/Mage.Sets/src/mage/cards/p/PhyrexianSnowcrusher.java index 8d6f0d87514..c44cf992ea1 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianSnowcrusher.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianSnowcrusher.java @@ -24,6 +24,7 @@ public final class PhyrexianSnowcrusher extends CardImpl { public PhyrexianSnowcrusher(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{6}"); addSuperType(SuperType.SNOW); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.JUGGERNAUT); this.power = new MageInt(6); this.toughness = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianSoulgorger.java b/Mage.Sets/src/mage/cards/p/PhyrexianSoulgorger.java index 2f978ceb9f0..2fb992c28b5 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianSoulgorger.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianSoulgorger.java @@ -22,6 +22,7 @@ public final class PhyrexianSoulgorger extends CardImpl { public PhyrexianSoulgorger(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); addSuperType(SuperType.SNOW); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(8); this.toughness = new MageInt(8); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianSwarmlord.java b/Mage.Sets/src/mage/cards/p/PhyrexianSwarmlord.java index b392a6e1a17..81cf6a32190 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianSwarmlord.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianSwarmlord.java @@ -22,6 +22,7 @@ public final class PhyrexianSwarmlord extends CardImpl { public PhyrexianSwarmlord(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.INSECT); this.subtype.add(SubType.HORROR); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianTotem.java b/Mage.Sets/src/mage/cards/p/PhyrexianTotem.java index 5fb1dfdf751..645aec63eec 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianTotem.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianTotem.java @@ -53,10 +53,11 @@ public final class PhyrexianTotem extends CardImpl { private static class PhyrexianTotemToken extends TokenImpl { PhyrexianTotemToken() { - super("Horror", "5/5 black Horror artifact creature with trample"); + super("Phyrexian Horror", "5/5 black Phyrexian Horror artifact creature with trample"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); color.setBlack(true); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); power = new MageInt(5); toughness = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianTriniform.java b/Mage.Sets/src/mage/cards/p/PhyrexianTriniform.java index d0bc175183b..c5ac63da431 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianTriniform.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianTriniform.java @@ -9,7 +9,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.game.permanent.token.GolemToken; +import mage.game.permanent.token.PhyrexianGolemToken; import java.util.UUID; @@ -21,12 +21,13 @@ public final class PhyrexianTriniform extends CardImpl { public PhyrexianTriniform(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{9}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.GOLEM); this.power = new MageInt(9); this.toughness = new MageInt(9); // When Phyrexian Triniform dies, create three 3/3 colorless Golem artifact creature tokens. - this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new GolemToken(), 3))); + this.addAbility(new DiesSourceTriggeredAbility(new CreateTokenEffect(new PhyrexianGolemToken(), 3))); // Encore {12} this.addAbility(new EncoreAbility(new GenericManaCost(12))); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianVatmother.java b/Mage.Sets/src/mage/cards/p/PhyrexianVatmother.java index 5c7fd054292..b1f88a2b7e5 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianVatmother.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianVatmother.java @@ -26,6 +26,7 @@ public final class PhyrexianVatmother extends CardImpl { public PhyrexianVatmother (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianWalker.java b/Mage.Sets/src/mage/cards/p/PhyrexianWalker.java index 2bb8358176a..63cd908abbb 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianWalker.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianWalker.java @@ -16,6 +16,7 @@ public final class PhyrexianWalker extends CardImpl { public PhyrexianWalker(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{0}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(0); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianWarBeast.java b/Mage.Sets/src/mage/cards/p/PhyrexianWarBeast.java index e1114fa7216..6e90f756ed2 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianWarBeast.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianWarBeast.java @@ -21,6 +21,7 @@ public final class PhyrexianWarBeast extends CardImpl { public PhyrexianWarBeast(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BEAST); this.power = new MageInt(3); this.toughness = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/p/PierceStrider.java b/Mage.Sets/src/mage/cards/p/PierceStrider.java index 1b9e8012ce4..ae288f53ed5 100644 --- a/Mage.Sets/src/mage/cards/p/PierceStrider.java +++ b/Mage.Sets/src/mage/cards/p/PierceStrider.java @@ -21,6 +21,7 @@ public final class PierceStrider extends CardImpl { public PierceStrider (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(3); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/p/PiercingRays.java b/Mage.Sets/src/mage/cards/p/PiercingRays.java new file mode 100644 index 00000000000..5a9f7670e44 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PiercingRays.java @@ -0,0 +1,52 @@ +package mage.cards.p; + +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.keyword.ForecastAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PiercingRays extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("tapped creature"); + private static final FilterPermanent filter2 = new FilterCreaturePermanent("untapped creature"); + + static { + filter.add(TappedPredicate.TAPPED); + filter2.add(TappedPredicate.UNTAPPED); + } + + public PiercingRays(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}"); + + // Exile target tapped creature. + this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + + // Forecast—{2}{W}, Reveal Piercing Rays from your hand: Tap target untapped creature. + Ability ability = new ForecastAbility(new TapTargetEffect(), new ManaCostsImpl<>("{2}{W}")); + ability.addTarget(new TargetPermanent(filter2)); + this.addAbility(ability); + } + + private PiercingRays(final PiercingRays card) { + super(card); + } + + @Override + public PiercingRays copy() { + return new PiercingRays(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PiruTheVolatile.java b/Mage.Sets/src/mage/cards/p/PiruTheVolatile.java new file mode 100644 index 00000000000..f2b8eaff643 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PiruTheVolatile.java @@ -0,0 +1,67 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PiruTheVolatile extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("nonlegendary creature"); + + static { + filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); + } + + public PiruTheVolatile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}{W}{W}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ELDER); + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // At the beginning of your upkeep, sacrifice Piru, the Volatile unless you pay {R}{W}{B}. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl<>("{R}{W}{B}")), + TargetController.YOU, false + )); + + // When Piru dies, it deals 7 damage to each nonlegendary creature. + this.addAbility(new DiesSourceTriggeredAbility(new DamageAllEffect(7, "it", filter))); + } + + private PiruTheVolatile(final PiruTheVolatile card) { + super(card); + } + + @Override + public PiruTheVolatile copy() { + return new PiruTheVolatile(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PithDriller.java b/Mage.Sets/src/mage/cards/p/PithDriller.java index 07b44f03063..4af034313ed 100644 --- a/Mage.Sets/src/mage/cards/p/PithDriller.java +++ b/Mage.Sets/src/mage/cards/p/PithDriller.java @@ -20,6 +20,7 @@ public final class PithDriller extends CardImpl { public PithDriller(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}{B/P}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/p/PlagueDogs.java b/Mage.Sets/src/mage/cards/p/PlagueDogs.java index 3ce5d491a27..00dc8bec8ed 100644 --- a/Mage.Sets/src/mage/cards/p/PlagueDogs.java +++ b/Mage.Sets/src/mage/cards/p/PlagueDogs.java @@ -25,6 +25,7 @@ public final class PlagueDogs extends CardImpl { public PlagueDogs(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.DOG); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/p/PlagueEngineer.java b/Mage.Sets/src/mage/cards/p/PlagueEngineer.java index 4fe25a965a1..839d6b6550a 100644 --- a/Mage.Sets/src/mage/cards/p/PlagueEngineer.java +++ b/Mage.Sets/src/mage/cards/p/PlagueEngineer.java @@ -33,6 +33,7 @@ public final class PlagueEngineer extends CardImpl { public PlagueEngineer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CARRIER); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/p/PlagueMyr.java b/Mage.Sets/src/mage/cards/p/PlagueMyr.java index c8299ae807b..a287eb12d03 100644 --- a/Mage.Sets/src/mage/cards/p/PlagueMyr.java +++ b/Mage.Sets/src/mage/cards/p/PlagueMyr.java @@ -19,6 +19,7 @@ public final class PlagueMyr extends CardImpl { public PlagueMyr (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.MYR); this.power = new MageInt(1); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/p/PlagueSpitter.java b/Mage.Sets/src/mage/cards/p/PlagueSpitter.java index 891f967a046..48cdf8a7abc 100644 --- a/Mage.Sets/src/mage/cards/p/PlagueSpitter.java +++ b/Mage.Sets/src/mage/cards/p/PlagueSpitter.java @@ -21,6 +21,7 @@ public final class PlagueSpitter extends CardImpl { public PlagueSpitter(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/p/PlagueStinger.java b/Mage.Sets/src/mage/cards/p/PlagueStinger.java index 2b7a79919b1..4860c65aa03 100644 --- a/Mage.Sets/src/mage/cards/p/PlagueStinger.java +++ b/Mage.Sets/src/mage/cards/p/PlagueStinger.java @@ -19,6 +19,7 @@ public final class PlagueStinger extends CardImpl { public PlagueStinger (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.INSECT); this.subtype.add(SubType.HORROR); diff --git a/Mage.Sets/src/mage/cards/p/PlaguemawBeast.java b/Mage.Sets/src/mage/cards/p/PlaguemawBeast.java index a179e9745c4..0e8605cf1b5 100644 --- a/Mage.Sets/src/mage/cards/p/PlaguemawBeast.java +++ b/Mage.Sets/src/mage/cards/p/PlaguemawBeast.java @@ -24,6 +24,7 @@ public final class PlaguemawBeast extends CardImpl { public PlaguemawBeast(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BEAST); this.power = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/p/PorcelainLegionnaire.java b/Mage.Sets/src/mage/cards/p/PorcelainLegionnaire.java index 0d82ca2d424..8b41e7c4da4 100644 --- a/Mage.Sets/src/mage/cards/p/PorcelainLegionnaire.java +++ b/Mage.Sets/src/mage/cards/p/PorcelainLegionnaire.java @@ -17,6 +17,7 @@ public final class PorcelainLegionnaire extends CardImpl { public PorcelainLegionnaire(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}{W/P}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/p/PowerDepot.java b/Mage.Sets/src/mage/cards/p/PowerDepot.java new file mode 100644 index 00000000000..2d379362e11 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PowerDepot.java @@ -0,0 +1,80 @@ +package mage.cards.p; + +import mage.ConditionalMana; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.keyword.ModularAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.mana.ConditionalAnyColorManaAbility; +import mage.abilities.mana.builder.ConditionalManaBuilder; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PowerDepot extends CardImpl { + + public PowerDepot(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.LAND}, ""); + + // Power Depot enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Add one mana of any color. Spend this mana only to cast artifact spells or activate abilities of artifacts. + this.addAbility(new ConditionalAnyColorManaAbility(1, new PowerDepotManaBuilder())); + + // Modular 1 + this.addAbility(new ModularAbility(this, 1)); + } + + private PowerDepot(final PowerDepot card) { + super(card); + } + + @Override + public PowerDepot copy() { + return new PowerDepot(this); + } +} + +class PowerDepotManaBuilder extends ConditionalManaBuilder { + + @Override + public ConditionalMana build(Object... options) { + return new PowerDepotConditionalMana(this.mana); + } + + @Override + public String getRule() { + return "Spend this mana only to cast artifact spells or activate abilities of artifacts"; + } +} + +class PowerDepotConditionalMana extends ConditionalMana { + + PowerDepotConditionalMana(Mana mana) { + super(mana); + this.addCondition(PowerDepotCondition.instance); + } +} + +enum PowerDepotCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + MageObject object = game.getObject(source.getSourceId()); + return object != null && object.isArtifact(); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PriestOfGix.java b/Mage.Sets/src/mage/cards/p/PriestOfGix.java index 84ff832bc1f..a6c52f6426f 100644 --- a/Mage.Sets/src/mage/cards/p/PriestOfGix.java +++ b/Mage.Sets/src/mage/cards/p/PriestOfGix.java @@ -19,6 +19,7 @@ public final class PriestOfGix extends CardImpl { public PriestOfGix(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.subtype.add(SubType.MINION); diff --git a/Mage.Sets/src/mage/cards/p/PriestOfUrabrask.java b/Mage.Sets/src/mage/cards/p/PriestOfUrabrask.java index d7dd0a8f16e..7188a59cf29 100644 --- a/Mage.Sets/src/mage/cards/p/PriestOfUrabrask.java +++ b/Mage.Sets/src/mage/cards/p/PriestOfUrabrask.java @@ -19,6 +19,7 @@ public final class PriestOfUrabrask extends CardImpl { public PriestOfUrabrask(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); diff --git a/Mage.Sets/src/mage/cards/p/PriestOfYawgmoth.java b/Mage.Sets/src/mage/cards/p/PriestOfYawgmoth.java index 8dbc04fd347..fcf8f65ba77 100644 --- a/Mage.Sets/src/mage/cards/p/PriestOfYawgmoth.java +++ b/Mage.Sets/src/mage/cards/p/PriestOfYawgmoth.java @@ -25,6 +25,7 @@ public final class PriestOfYawgmoth extends CardImpl { public PriestOfYawgmoth(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/p/PriestsOfNorn.java b/Mage.Sets/src/mage/cards/p/PriestsOfNorn.java index 986f99b3c56..58c2da44cab 100644 --- a/Mage.Sets/src/mage/cards/p/PriestsOfNorn.java +++ b/Mage.Sets/src/mage/cards/p/PriestsOfNorn.java @@ -19,6 +19,7 @@ public final class PriestsOfNorn extends CardImpl { public PriestsOfNorn (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/p/PrimalVigor.java b/Mage.Sets/src/mage/cards/p/PrimalVigor.java index 547ce9b03e5..377f203e933 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalVigor.java +++ b/Mage.Sets/src/mage/cards/p/PrimalVigor.java @@ -10,6 +10,7 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.CreateTokenEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -73,7 +74,9 @@ class PrimalVigorTokenEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() * 2); + if (event instanceof CreateTokenEvent) { + ((CreateTokenEvent) event).doubleTokens(); + } return false; } diff --git a/Mage.Sets/src/mage/cards/p/ProfaneTransfusion.java b/Mage.Sets/src/mage/cards/p/ProfaneTransfusion.java index 74134d9e0ef..dc8d2f26fe8 100644 --- a/Mage.Sets/src/mage/cards/p/ProfaneTransfusion.java +++ b/Mage.Sets/src/mage/cards/p/ProfaneTransfusion.java @@ -42,7 +42,7 @@ class ProfaneTransfusionEffect extends OneShotEffect { ProfaneTransfusionEffect() { super(Outcome.Benefit); - staticText = "You create an X/X colorless Horror artifact creature token, " + + staticText = "You create an X/X colorless Phyrexian Horror artifact creature token, " + "where X is the difference between those players' life totals"; } diff --git a/Mage.Sets/src/mage/cards/p/PropheticTitan.java b/Mage.Sets/src/mage/cards/p/PropheticTitan.java new file mode 100644 index 00000000000..91489e77086 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PropheticTitan.java @@ -0,0 +1,87 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.DeliriumCondition; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.hint.common.CardTypesInGraveyardHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PropheticTitan extends CardImpl { + + public PropheticTitan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{R}"); + + this.subtype.add(SubType.GIANT); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Delirium — When Prophetic Titan enters the battlefield, choose one. If there are four or more card types among cards in your graveyard, choose both. + // • Prophetic Titan deals 4 damage to any target. + // • Look at the top four cards of your library. Put one of them into your hand and the rest on the bottom of your library in a random order. + this.addAbility(new PropheticTitanTriggeredAbility()); + } + + private PropheticTitan(final PropheticTitan card) { + super(card); + } + + @Override + public PropheticTitan copy() { + return new PropheticTitan(this); + } +} + +class PropheticTitanTriggeredAbility extends EntersBattlefieldTriggeredAbility { + + public PropheticTitanTriggeredAbility() { + super(new DamageTargetEffect(4), false, "Delirium — "); + this.addTarget(new TargetAnyTarget()); + this.addMode(new Mode(new LookLibraryAndPickControllerEffect( + StaticValue.get(4), false, StaticValue.get(1), + StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false + ).setBackInRandomOrder(true).setText("look at the top four cards of your library. " + + "Put one of them into your hand and the rest on the bottom of your library in a random order"))); + this.getModes().setChooseText( + "choose one. If there are four or more card types among cards in your graveyard, choose both instead." + ); + this.addHint(CardTypesInGraveyardHint.YOU); + } + + private PropheticTitanTriggeredAbility(final PropheticTitanTriggeredAbility ability) { + super(ability); + } + + @Override + public PropheticTitanTriggeredAbility copy() { + return new PropheticTitanTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!super.checkTrigger(event, game)) { + return false; + } + int modes = DeliriumCondition.instance.apply(game, this) ? 2 : 1; + this.getModes().setMinModes(modes); + this.getModes().setMaxModes(modes); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/PsychosisCrawler.java b/Mage.Sets/src/mage/cards/p/PsychosisCrawler.java index 4b1d2c583f0..63e23e9087e 100644 --- a/Mage.Sets/src/mage/cards/p/PsychosisCrawler.java +++ b/Mage.Sets/src/mage/cards/p/PsychosisCrawler.java @@ -23,6 +23,7 @@ public final class PsychosisCrawler extends CardImpl { public PsychosisCrawler(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(0); diff --git a/Mage.Sets/src/mage/cards/p/Putrefax.java b/Mage.Sets/src/mage/cards/p/Putrefax.java index 57e19ef3166..f024fbf7be9 100644 --- a/Mage.Sets/src/mage/cards/p/Putrefax.java +++ b/Mage.Sets/src/mage/cards/p/Putrefax.java @@ -23,6 +23,7 @@ public final class Putrefax extends CardImpl { public Putrefax (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/q/QuilledSlagwurm.java b/Mage.Sets/src/mage/cards/q/QuilledSlagwurm.java index 60032380a64..12b43c47f79 100644 --- a/Mage.Sets/src/mage/cards/q/QuilledSlagwurm.java +++ b/Mage.Sets/src/mage/cards/q/QuilledSlagwurm.java @@ -17,6 +17,7 @@ public final class QuilledSlagwurm extends CardImpl { public QuilledSlagwurm (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}{G}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.WURM); this.power = new MageInt(8); diff --git a/Mage.Sets/src/mage/cards/q/QuirionRanger.java b/Mage.Sets/src/mage/cards/q/QuirionRanger.java index 6410827af1e..ea1cec61a3c 100644 --- a/Mage.Sets/src/mage/cards/q/QuirionRanger.java +++ b/Mage.Sets/src/mage/cards/q/QuirionRanger.java @@ -32,6 +32,7 @@ public final class QuirionRanger extends CardImpl { public QuirionRanger(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); this.subtype.add(SubType.ELF); + this.subtype.add(SubType.RANGER); this.power = new MageInt(1); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/r/Rackling.java b/Mage.Sets/src/mage/cards/r/Rackling.java index 3cbb3f21cff..44c76e398c2 100644 --- a/Mage.Sets/src/mage/cards/r/Rackling.java +++ b/Mage.Sets/src/mage/cards/r/Rackling.java @@ -20,6 +20,7 @@ public final class Rackling extends CardImpl { public Rackling(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(2); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/r/RadiantEpicure.java b/Mage.Sets/src/mage/cards/r/RadiantEpicure.java new file mode 100644 index 00000000000..479a818cbe3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RadiantEpicure.java @@ -0,0 +1,83 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.game.Game; +import mage.players.Player; +import mage.watchers.common.ManaSpentToCastWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RadiantEpicure extends CardImpl { + + public RadiantEpicure(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Converge — When Radiant Epicure enters the battlefield, each opponent loses X life and you gain X life, where X is the number of colors of mana spent to cast this spell. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new RadiantEpicureEffect(), false, "Converge — " + ), new ManaSpentToCastWatcher()); + } + + private RadiantEpicure(final RadiantEpicure card) { + super(card); + } + + @Override + public RadiantEpicure copy() { + return new RadiantEpicure(this); + } +} + +class RadiantEpicureEffect extends OneShotEffect { + + RadiantEpicureEffect() { + super(Outcome.Benefit); + staticText = "each opponent loses X life and you gain X life, " + + "where X is the number of colors of mana spent to cast this spell"; + } + + private RadiantEpicureEffect(final RadiantEpicureEffect effect) { + super(effect); + } + + @Override + public RadiantEpicureEffect copy() { + return new RadiantEpicureEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + ManaSpentToCastWatcher watcher = game.getState().getWatcher(ManaSpentToCastWatcher.class, source.getSourceId()); + if (player == null || watcher == null) { + return false; + } + Mana payment = watcher.getAndResetLastPayment(); + if (payment == null) { + return false; + } + int xValue = payment.getDifferentColors(); + new DamagePlayersEffect(xValue, TargetController.OPPONENT).apply(game, source); + player.gainLife(xValue, game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RagavanNimblePilferer.java b/Mage.Sets/src/mage/cards/r/RagavanNimblePilferer.java new file mode 100644 index 00000000000..a1e75b1cfdb --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RagavanNimblePilferer.java @@ -0,0 +1,86 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +import mage.abilities.keyword.DashAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.token.TreasureToken; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RagavanNimblePilferer extends CardImpl { + + public RagavanNimblePilferer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.MONKEY); + this.subtype.add(SubType.PIRATE); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Whenever Ragavan, Nimble Pilferer deals combat damage to a player, create a Treasure token and exile the top card of that player's library. Until end of turn, you may cast that card. + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( + new CreateTokenEffect(new TreasureToken()), false, true + ); + ability.addEffect(new RagavanNimblePilfererEffect()); + this.addAbility(ability); + + // Dash {1}{R} + this.addAbility(new DashAbility(this, "{1}{R}")); + } + + private RagavanNimblePilferer(final RagavanNimblePilferer card) { + super(card); + } + + @Override + public RagavanNimblePilferer copy() { + return new RagavanNimblePilferer(this); + } +} + +class RagavanNimblePilfererEffect extends OneShotEffect { + + RagavanNimblePilfererEffect() { + super(Outcome.Benefit); + staticText = "and exile the top card of that player's library. Until end of turn, you may cast that card"; + } + + private RagavanNimblePilfererEffect(final RagavanNimblePilfererEffect effect) { + super(effect); + } + + @Override + public RagavanNimblePilfererEffect copy() { + return new RagavanNimblePilfererEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || player == null) { + return false; + } + Card card = player.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + return PlayFromNotOwnHandZoneTargetEffect.exileAndPlayFromExile( + game, source, card, TargetController.YOU, Duration.EndOfTurn, false, true + ); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RakdosHeadliner.java b/Mage.Sets/src/mage/cards/r/RakdosHeadliner.java new file mode 100644 index 00000000000..40925264ced --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RakdosHeadliner.java @@ -0,0 +1,41 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.keyword.EchoAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RakdosHeadliner extends CardImpl { + + public RakdosHeadliner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}"); + + this.subtype.add(SubType.DEVIL); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Echo—Discard a card. + this.addAbility(new EchoAbility(new DiscardCardCost())); + } + + private RakdosHeadliner(final RakdosHeadliner card) { + super(card); + } + + @Override + public RakdosHeadliner copy() { + return new RakdosHeadliner(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RangerCaptainOfEos.java b/Mage.Sets/src/mage/cards/r/RangerCaptainOfEos.java index 60736bcc15c..c9044fbd5a7 100644 --- a/Mage.Sets/src/mage/cards/r/RangerCaptainOfEos.java +++ b/Mage.Sets/src/mage/cards/r/RangerCaptainOfEos.java @@ -39,6 +39,7 @@ public final class RangerCaptainOfEos extends CardImpl { this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); + this.subtype.add(SubType.RANGER); this.power = new MageInt(3); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/r/RathiAssassin.java b/Mage.Sets/src/mage/cards/r/RathiAssassin.java index ee1abc2834c..59ec3cc4a0e 100644 --- a/Mage.Sets/src/mage/cards/r/RathiAssassin.java +++ b/Mage.Sets/src/mage/cards/r/RathiAssassin.java @@ -44,6 +44,7 @@ public final class RathiAssassin extends CardImpl { public RathiAssassin(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.MERCENARY); this.subtype.add(SubType.ASSASSIN); diff --git a/Mage.Sets/src/mage/cards/r/RathiFiend.java b/Mage.Sets/src/mage/cards/r/RathiFiend.java index 288abb93a72..faace34319a 100644 --- a/Mage.Sets/src/mage/cards/r/RathiFiend.java +++ b/Mage.Sets/src/mage/cards/r/RathiFiend.java @@ -35,6 +35,7 @@ public final class RathiFiend extends CardImpl { public RathiFiend(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.subtype.add(SubType.MERCENARY); diff --git a/Mage.Sets/src/mage/cards/r/RathiIntimidator.java b/Mage.Sets/src/mage/cards/r/RathiIntimidator.java index b5c282d24fc..2b8bb22a2fe 100644 --- a/Mage.Sets/src/mage/cards/r/RathiIntimidator.java +++ b/Mage.Sets/src/mage/cards/r/RathiIntimidator.java @@ -34,6 +34,7 @@ public final class RathiIntimidator extends CardImpl { public RathiIntimidator(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.subtype.add(SubType.MERCENARY); diff --git a/Mage.Sets/src/mage/cards/r/RavenousSkirge.java b/Mage.Sets/src/mage/cards/r/RavenousSkirge.java index 03d37e43d43..7131d4b54e1 100644 --- a/Mage.Sets/src/mage/cards/r/RavenousSkirge.java +++ b/Mage.Sets/src/mage/cards/r/RavenousSkirge.java @@ -20,6 +20,7 @@ public final class RavenousSkirge extends CardImpl { public RavenousSkirge(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.IMP); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/r/RavingVisionary.java b/Mage.Sets/src/mage/cards/r/RavingVisionary.java new file mode 100644 index 00000000000..e5086f98889 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RavingVisionary.java @@ -0,0 +1,58 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.DeliriumCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.hint.common.CardTypesInGraveyardHint; +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 RavingVisionary extends CardImpl { + + public RavingVisionary(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {U}, {T}: Draw a card, then discard a card. + Ability ability = new SimpleActivatedAbility( + new DrawDiscardControllerEffect(1, 1), new ManaCostsImpl<>("{U}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // Delirium — {2}{U}, {T}: Draw a card. Activate only if there are four or more card types among cards in your graveyard. + ability = new ActivateIfConditionActivatedAbility( + Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), + new ManaCostsImpl<>("{2}{U}"), DeliriumCondition.instance + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability.addHint(CardTypesInGraveyardHint.YOU)); + } + + private RavingVisionary(final RavingVisionary card) { + super(card); + } + + @Override + public RavingVisionary copy() { + return new RavingVisionary(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RazorSwine.java b/Mage.Sets/src/mage/cards/r/RazorSwine.java index 27008c282f4..69653b3d333 100644 --- a/Mage.Sets/src/mage/cards/r/RazorSwine.java +++ b/Mage.Sets/src/mage/cards/r/RazorSwine.java @@ -18,6 +18,7 @@ public final class RazorSwine extends CardImpl { public RazorSwine(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BOAR); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/r/ReaperOfSheoldred.java b/Mage.Sets/src/mage/cards/r/ReaperOfSheoldred.java index c8314506266..66d96f9741f 100644 --- a/Mage.Sets/src/mage/cards/r/ReaperOfSheoldred.java +++ b/Mage.Sets/src/mage/cards/r/ReaperOfSheoldred.java @@ -27,6 +27,7 @@ public final class ReaperOfSheoldred extends CardImpl { public ReaperOfSheoldred(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/r/Recalibrate.java b/Mage.Sets/src/mage/cards/r/Recalibrate.java new file mode 100644 index 00000000000..3455a5c6858 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Recalibrate.java @@ -0,0 +1,44 @@ +package mage.cards.r; + +import mage.abilities.condition.common.ControllerDiscardedThisTurnCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.hint.common.ControllerDiscardedHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; +import mage.watchers.common.DiscardedCardWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Recalibrate extends CardImpl { + + public Recalibrate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Return target creature to its owner's hand. If you've discarded a card this turn, draw a card. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), + ControllerDiscardedThisTurnCondition.instance, + "If you've discarded a card this turn, draw a card" + )); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addHint(ControllerDiscardedHint.instance); + this.getSpellAbility().addWatcher(new DiscardedCardWatcher()); + } + + private Recalibrate(final Recalibrate card) { + super(card); + } + + @Override + public Recalibrate copy() { + return new Recalibrate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/ResurgentBelief.java b/Mage.Sets/src/mage/cards/r/ResurgentBelief.java new file mode 100644 index 00000000000..d553855a2b5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ResurgentBelief.java @@ -0,0 +1,71 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.SuspendAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterEnchantmentCard; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ResurgentBelief extends CardImpl { + + public ResurgentBelief(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, ""); + + this.color.setWhite(true); + + // Suspend 2—{1}{W} + this.addAbility(new SuspendAbility(2, new ManaCostsImpl<>("{1}{W}"), this)); + + // Return all enchantment cards from your graveyard to the battlefield. + this.getSpellAbility().addEffect(new ResurgentBeliefEffect()); + } + + private ResurgentBelief(final ResurgentBelief card) { + super(card); + } + + @Override + public ResurgentBelief copy() { + return new ResurgentBelief(this); + } +} + +class ResurgentBeliefEffect extends OneShotEffect { + + private static final FilterCard filter = new FilterEnchantmentCard(); + + ResurgentBeliefEffect() { + super(Outcome.Benefit); + staticText = "return all enchantment cards from your graveyard to the battlefield"; + } + + private ResurgentBeliefEffect(final ResurgentBeliefEffect effect) { + super(effect); + } + + @Override + public ResurgentBeliefEffect copy() { + return new ResurgentBeliefEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + return player != null && player.moveCards( + player.getGraveyard().getCards(filter, game), Zone.BATTLEFIELD, source, game + ); + } +} diff --git a/Mage.Sets/src/mage/cards/r/Revolutionist.java b/Mage.Sets/src/mage/cards/r/Revolutionist.java new file mode 100644 index 00000000000..9fb5d4e2a0d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Revolutionist.java @@ -0,0 +1,48 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.keyword.MadnessAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Revolutionist extends CardImpl { + + public Revolutionist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Revolutionist enters the battlefield, return target instant or sorcery card from your graveyard to your hand. + Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD)); + this.addAbility(ability); + + // Madness {3}{R} + this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{3}{R}"))); + } + + private Revolutionist(final Revolutionist card) { + super(card); + } + + @Override + public Revolutionist copy() { + return new Revolutionist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RiseAndShine.java b/Mage.Sets/src/mage/cards/r/RiseAndShine.java new file mode 100644 index 00000000000..dddb5f8df10 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiseAndShine.java @@ -0,0 +1,102 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.OverloadAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.predicate.Predicates; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTargets; + +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RiseAndShine extends CardImpl { + + static final FilterPermanent filter + = new FilterControlledArtifactPermanent("noncreature artifact you control"); + + static { + filter.add(Predicates.not(CardType.CREATURE.getPredicate())); + } + + public RiseAndShine(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); + + // Target noncreature artifact you control becomes a 0/0 artifact creature. Put four +1/+1 counters on each artifact that became a creature this way. + this.getSpellAbility().addEffect(new AddCardTypeTargetEffect( + Duration.EndOfGame, CardType.ARTIFACT, CardType.CREATURE + ).setText("Target noncreature artifact you control becomes")); + this.getSpellAbility().addEffect(new SetPowerToughnessTargetEffect( + 0, 0, Duration.EndOfGame + ).setText("a 0/0 artifact creature")); + this.getSpellAbility().addEffect(new AddCountersTargetEffect( + CounterType.P1P1.createInstance(4) + ).setText("Put four +1/+1 counters on each artifact that became a creature this way")); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + + // Overload {4}{U}{U} + this.addAbility(new OverloadAbility(this, new RiseAndShineEffect(), new ManaCostsImpl<>("{4}{U}{U}"))); + } + + private RiseAndShine(final RiseAndShine card) { + super(card); + } + + @Override + public RiseAndShine copy() { + return new RiseAndShine(this); + } +} + +class RiseAndShineEffect extends OneShotEffect { + + RiseAndShineEffect() { + super(Outcome.Benefit); + } + + private RiseAndShineEffect(final RiseAndShineEffect effect) { + super(effect); + } + + @Override + public RiseAndShineEffect copy() { + return new RiseAndShineEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + List permanents = game.getBattlefield().getActivePermanents( + RiseAndShine.filter, source.getControllerId(), source.getSourceId(), game + ); + if (permanents.isEmpty()) { + return false; + } + game.addEffect(new AddCardTypeTargetEffect( + Duration.EndOfGame, CardType.ARTIFACT, CardType.CREATURE + ).setTargetPointer(new FixedTargets(permanents, game)), source); + game.addEffect(new SetPowerToughnessTargetEffect( + 0, 0, Duration.EndOfGame + ).setTargetPointer(new FixedTargets(permanents, game)), source); + for (Permanent permanent : permanents) { + permanent.addCounters(CounterType.P1P1.createInstance(4), source.getControllerId(), source, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RoadRuin.java b/Mage.Sets/src/mage/cards/r/RoadRuin.java new file mode 100644 index 00000000000..24c67e0ac38 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RoadRuin.java @@ -0,0 +1,54 @@ +package mage.cards.r; + +import mage.abilities.dynamicvalue.common.LandsYouControlCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.hint.common.LandsYouControlHint; +import mage.abilities.keyword.AftermathAbility; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RoadRuin extends SplitCard { + public RoadRuin(UUID ownerId, CardSetInfo setInfo) { + super( + ownerId, setInfo, + new CardType[]{CardType.INSTANT}, new CardType[]{CardType.SORCERY}, + "{2}{G}", "{1}{R}{R}", SpellAbilityType.SPLIT_AFTERMATH + ); + + // Road + // Search your library for a basic land card, put it onto the battlefield tapped, then shuffle. + this.getLeftHalfCard().getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true + )); + + // Ruin + // Aftermath + this.getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); + + // Ruin deals damage to target creature equal to the number of lands you control. + this.getRightHalfCard().getSpellAbility().addEffect(new DamageTargetEffect(LandsYouControlCount.instance) + .setText("{this} deals damage to target creature equal to the number of lands you control")); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getRightHalfCard().getSpellAbility().addHint(LandsYouControlHint.instance); + } + + private RoadRuin(final RoadRuin card) { + super(card); + } + + @Override + public RoadRuin copy() { + return new RoadRuin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RotWolf.java b/Mage.Sets/src/mage/cards/r/RotWolf.java index e7e4674583e..1d4a0d92c5f 100644 --- a/Mage.Sets/src/mage/cards/r/RotWolf.java +++ b/Mage.Sets/src/mage/cards/r/RotWolf.java @@ -19,6 +19,7 @@ public final class RotWolf extends CardImpl { public RotWolf(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.WOLF); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/r/RottedHystrix.java b/Mage.Sets/src/mage/cards/r/RottedHystrix.java index 1bff74a7420..b45275a4a7b 100644 --- a/Mage.Sets/src/mage/cards/r/RottedHystrix.java +++ b/Mage.Sets/src/mage/cards/r/RottedHystrix.java @@ -16,6 +16,7 @@ public final class RottedHystrix extends CardImpl { public RottedHystrix(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BEAST); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/r/RustedSlasher.java b/Mage.Sets/src/mage/cards/r/RustedSlasher.java index 9e6e9010b43..7dbaf64020f 100644 --- a/Mage.Sets/src/mage/cards/r/RustedSlasher.java +++ b/Mage.Sets/src/mage/cards/r/RustedSlasher.java @@ -28,6 +28,7 @@ public final class RustedSlasher extends CardImpl { public RustedSlasher (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(4); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/s/SaidDone.java b/Mage.Sets/src/mage/cards/s/SaidDone.java new file mode 100644 index 00000000000..24cb3f31eb6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SaidDone.java @@ -0,0 +1,50 @@ +package mage.cards.s; + +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SaidDone extends SplitCard { + + public SaidDone(UUID ownerId, CardSetInfo setInfo) { + super( + ownerId, setInfo, + new CardType[]{CardType.SORCERY}, new CardType[]{CardType.INSTANT}, + "{2}{U}", "{3}{U}", SpellAbilityType.SPLIT + ); + + // Said + // Return target instant or sorcery card from your graveyard to your hand. + this.getLeftHalfCard().getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetCardInYourGraveyard( + StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD + )); + + // Done + // Tap up to two target creatures. They don't untap during their controllers' next untap step. + this.getRightHalfCard().getSpellAbility().addEffect(new TapTargetEffect()); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); + this.getRightHalfCard().getSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect("They")); + } + + private SaidDone(final SaidDone card) { + super(card); + } + + @Override + public SaidDone copy() { + return new SaidDone(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SanctifierEnVec.java b/Mage.Sets/src/mage/cards/s/SanctifierEnVec.java new file mode 100644 index 00000000000..1556accec8c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SanctifierEnVec.java @@ -0,0 +1,106 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.ExileGraveyardAllPlayersEffect; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.Card; +import mage.constants.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author weirddan455 + */ +public final class SanctifierEnVec extends CardImpl { + + private static final FilterCard filter = new FilterCard("cards that are black or red"); + + static { + filter.add(Predicates.or(new ColorPredicate(ObjectColor.BLACK), new ColorPredicate(ObjectColor.RED))); + } + + public SanctifierEnVec(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Protection from black and from red + this.addAbility(ProtectionAbility.from(ObjectColor.BLACK, ObjectColor.RED)); + + // When Sanctifier en-Vec enters the battlefield, exile all cards that are black or red from all graveyards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ExileGraveyardAllPlayersEffect(filter))); + + // If a black or red permanent, spell, or card not on the battlefield would be put into a graveyard, exile it instead. + this.addAbility(new SimpleStaticAbility(new SanctifierEnVecEffect())); + } + + private SanctifierEnVec(final SanctifierEnVec card) { + super(card); + } + + @Override + public SanctifierEnVec copy() { + return new SanctifierEnVec(this); + } +} + +class SanctifierEnVecEffect extends ReplacementEffectImpl { + + public SanctifierEnVecEffect() { + super(Duration.WhileOnBattlefield, Outcome.Exile); + this.staticText = "If a black or red permanent, spell, or card not on the battlefield would be put into a graveyard, exile it instead"; + } + + private SanctifierEnVecEffect(final SanctifierEnVecEffect effect) { + super(effect); + } + + @Override + public SanctifierEnVecEffect copy() { + return new SanctifierEnVecEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getToZone() == Zone.GRAVEYARD) { + Permanent permanent = zEvent.getTarget(); + if (permanent != null) { + return permanent.getColor(game).contains(ObjectColor.BLACK) || permanent.getColor(game).contains(ObjectColor.RED); + } + Card card = game.getCard(zEvent.getTargetId()); + if (card != null) { + return card.getColor(game).contains(ObjectColor.BLACK) || card.getColor(game).contains(ObjectColor.RED); + } + } + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + ((ZoneChangeEvent) event).setToZone(Zone.EXILED); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SanctuaryRaptor.java b/Mage.Sets/src/mage/cards/s/SanctuaryRaptor.java new file mode 100644 index 00000000000..7ef4fa3ed01 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SanctuaryRaptor.java @@ -0,0 +1,73 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +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.permanent.TokenPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SanctuaryRaptor extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(TokenPredicate.instance); + } + + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 2); + private static final Hint hint + = new ValueHint("Tokens you control", new PermanentsOnBattlefieldCount(filter)); + + public SanctuaryRaptor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + + this.subtype.add(SubType.BIRD); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Sanctuary Raptor attacks, if you control three or more tokens, Sanctuary Raptor gets +2/+0 and gains first strike until end of turn. + Ability ability = new ConditionalInterveningIfTriggeredAbility( + new AttacksTriggeredAbility( + new BoostSourceEffect(2, 0, Duration.EndOfTurn), false + ), condition, "Whenever {this} attacks, if you control three or more tokens, " + + "{this} gets +2/+0 and gains first strike until end of turn." + ); + ability.addEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); + this.addAbility(ability.addHint(hint)); + } + + private SanctuaryRaptor(final SanctuaryRaptor card) { + super(card); + } + + @Override + public SanctuaryRaptor copy() { + return new SanctuaryRaptor(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SanctumWeaver.java b/Mage.Sets/src/mage/cards/s/SanctumWeaver.java new file mode 100644 index 00000000000..f2368e149ba --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SanctumWeaver.java @@ -0,0 +1,52 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.mana.DynamicManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledEnchantmentPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SanctumWeaver extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledEnchantmentPermanent(); + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + private static final Hint hint = new ValueHint("Enchantments you control", xValue); + + public SanctumWeaver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.DRYAD); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // {T}: Add X mana of any one color, where X is the number of enchantments you control. + this.addAbility(new DynamicManaAbility( + new Mana(0, 0, 0, 0, 0, 0, 1, 0), + xValue, new TapSourceCost(), "Add X mana of any one color, " + + "where X is the number of enchantments you control", true + ).addHint(hint)); + } + + private SanctumWeaver(final SanctumWeaver card) { + super(card); + } + + @Override + public SanctumWeaver copy() { + return new SanctumWeaver(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SanguineGuard.java b/Mage.Sets/src/mage/cards/s/SanguineGuard.java index f1ad156270c..c92605234b2 100644 --- a/Mage.Sets/src/mage/cards/s/SanguineGuard.java +++ b/Mage.Sets/src/mage/cards/s/SanguineGuard.java @@ -22,6 +22,7 @@ public final class SanguineGuard extends CardImpl { public SanguineGuard(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.KNIGHT); diff --git a/Mage.Sets/src/mage/cards/s/SarcomiteMyr.java b/Mage.Sets/src/mage/cards/s/SarcomiteMyr.java index aec0f789693..5a26130a84f 100644 --- a/Mage.Sets/src/mage/cards/s/SarcomiteMyr.java +++ b/Mage.Sets/src/mage/cards/s/SarcomiteMyr.java @@ -25,6 +25,7 @@ public final class SarcomiteMyr extends CardImpl { public SarcomiteMyr(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.MYR); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/s/ScionOfDraco.java b/Mage.Sets/src/mage/cards/s/ScionOfDraco.java new file mode 100644 index 00000000000..7c60c360345 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScionOfDraco.java @@ -0,0 +1,101 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.DomainValue; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.cost.SpellCostReductionForEachSourceEffect; +import mage.abilities.hint.common.DomainHint; +import mage.abilities.keyword.*; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ScionOfDraco extends CardImpl { + + private static final DynamicValue xValue = new DomainValue(); + + public ScionOfDraco(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{12}"); + + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Domain — This spell costs {2} less to cast for each basic land type among lands you control. + this.addAbility(new SimpleStaticAbility(Zone.ALL, + new SpellCostReductionForEachSourceEffect(2, xValue) + ).addHint(DomainHint.instance).setAbilityWord(AbilityWord.DOMAIN)); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Each creature you control has vigilance if it's white, hexproof if it's blue, lifelink if it's black, first strike if it's red, and trample if it's green. + this.addAbility(new SimpleStaticAbility(new ScionOfDracoEffect())); + } + + private ScionOfDraco(final ScionOfDraco card) { + super(card); + } + + @Override + public ScionOfDraco copy() { + return new ScionOfDraco(this); + } +} + +class ScionOfDracoEffect extends ContinuousEffectImpl { + + ScionOfDracoEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.Benefit); + staticText = "each creature you control has vigilance if it's white, hexproof if it's blue, " + + "lifelink if it's black, first strike if it's red, and trample if it's green"; + this.addDependencyType(DependencyType.AddingAbility); + } + + private ScionOfDracoEffect(final ScionOfDracoEffect effect) { + super(effect); + } + + @Override + public ScionOfDracoEffect copy() { + return new ScionOfDracoEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getControllerId(), source.getSourceId(), game + )) { + ObjectColor color = permanent.getColor(game); + if (color.isWhite()) { + permanent.addAbility(VigilanceAbility.getInstance(), source.getSourceId(), game); + } + if (color.isBlue()) { + permanent.addAbility(HexproofAbility.getInstance(), source.getSourceId(), game); + } + if (color.isBlack()) { + permanent.addAbility(LifelinkAbility.getInstance(), source.getSourceId(), game); + } + if (color.isRed()) { + permanent.addAbility(FirstStrikeAbility.getInstance(), source.getSourceId(), game); + } + if (color.isGreen()) { + permanent.addAbility(TrampleAbility.getInstance(), source.getSourceId(), game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/ScourTheDesert.java b/Mage.Sets/src/mage/cards/s/ScourTheDesert.java new file mode 100644 index 00000000000..2b2124b6eca --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScourTheDesert.java @@ -0,0 +1,73 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.token.BirdToken; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ScourTheDesert extends CardImpl { + + public ScourTheDesert(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}{W}"); + + // Exile target creature card from your graveyard. Create X 1/1 white Bird creature tokens with flying, where X is the exiled card's toughness. + this.getSpellAbility().addEffect(new ScourTheDesertEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + } + + private ScourTheDesert(final ScourTheDesert card) { + super(card); + } + + @Override + public ScourTheDesert copy() { + return new ScourTheDesert(this); + } +} + +class ScourTheDesertEffect extends OneShotEffect { + + ScourTheDesertEffect() { + super(Outcome.Benefit); + staticText = "exile target creature card from your graveyard. " + + "Create X 1/1 white Bird creature tokens with flying, where X is the exiled card's toughness"; + } + + private ScourTheDesertEffect(final ScourTheDesertEffect effect) { + super(effect); + } + + @Override + public ScourTheDesertEffect copy() { + return new ScourTheDesertEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + Card card = game.getCard(source.getFirstTarget()); + if (player == null || card == null) { + return false; + } + int toughness = card.getToughness().getValue(); + player.moveCards(card, Zone.EXILED, source, game); + if (toughness > 0) { + new BirdToken().putOntoBattlefield(toughness, game, source, source.getControllerId()); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/ScourgeServant.java b/Mage.Sets/src/mage/cards/s/ScourgeServant.java index d104e85ab43..bcd1cacd990 100644 --- a/Mage.Sets/src/mage/cards/s/ScourgeServant.java +++ b/Mage.Sets/src/mage/cards/s/ScourgeServant.java @@ -18,6 +18,7 @@ public final class ScourgeServant extends CardImpl { public ScourgeServant (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/s/SearchThePremises.java b/Mage.Sets/src/mage/cards/s/SearchThePremises.java new file mode 100644 index 00000000000..c79173124be --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SearchThePremises.java @@ -0,0 +1,33 @@ +package mage.cards.s; + +import mage.abilities.common.AttacksAllTriggeredAbility; +import mage.abilities.effects.keyword.InvestigateEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SearchThePremises extends CardImpl { + + public SearchThePremises(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); + + // Whenever a creature attacks you or a planeswalker you control, investigate. + this.addAbility(new AttacksAllTriggeredAbility( + new InvestigateEffect(), false, true + )); + } + + private SearchThePremises(final SearchThePremises card) { + super(card); + } + + @Override + public SearchThePremises copy() { + return new SearchThePremises(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeleniaDarkAngel.java b/Mage.Sets/src/mage/cards/s/SeleniaDarkAngel.java index 98fa401c919..6f068b71954 100644 --- a/Mage.Sets/src/mage/cards/s/SeleniaDarkAngel.java +++ b/Mage.Sets/src/mage/cards/s/SeleniaDarkAngel.java @@ -23,6 +23,7 @@ public final class SeleniaDarkAngel extends CardImpl { public SeleniaDarkAngel(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{B}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ANGEL); diff --git a/Mage.Sets/src/mage/cards/s/SensorSplicer.java b/Mage.Sets/src/mage/cards/s/SensorSplicer.java index 2b6f3f277fd..e48902ca1b2 100644 --- a/Mage.Sets/src/mage/cards/s/SensorSplicer.java +++ b/Mage.Sets/src/mage/cards/s/SensorSplicer.java @@ -13,7 +13,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.game.permanent.token.GolemToken; +import mage.game.permanent.token.PhyrexianGolemToken; import java.util.UUID; @@ -31,13 +31,14 @@ public final class SensorSplicer extends CardImpl { public SensorSplicer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ARTIFICER); this.power = new MageInt(1); this.toughness = new MageInt(1); // When Sensor Splicer enters the battlefield, create a 3/3 colorless Golem artifact creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GolemToken()))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new PhyrexianGolemToken()))); // Golem creatures you control have vigilance. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, filter))); diff --git a/Mage.Sets/src/mage/cards/s/SepticRats.java b/Mage.Sets/src/mage/cards/s/SepticRats.java index 3e6eea36d44..d2c1ab757f0 100644 --- a/Mage.Sets/src/mage/cards/s/SepticRats.java +++ b/Mage.Sets/src/mage/cards/s/SepticRats.java @@ -26,6 +26,7 @@ public final class SepticRats extends CardImpl { public SepticRats(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.RAT); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/s/SerrasEmissary.java b/Mage.Sets/src/mage/cards/s/SerrasEmissary.java new file mode 100644 index 00000000000..77ae01d933d --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SerrasEmissary.java @@ -0,0 +1,90 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.ChooseCardTypeEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SerrasEmissary extends CardImpl { + + public SerrasEmissary(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}{W}"); + + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // As Serra's Emissary enters the battlefield, choose a card type. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCardTypeEffect(Outcome.Benefit))); + + // You and creatures you control have protection from the chosen card type. + this.addAbility(new SimpleStaticAbility(new SerrasEmissaryEffect())); + } + + private SerrasEmissary(final SerrasEmissary card) { + super(card); + } + + @Override + public SerrasEmissary copy() { + return new SerrasEmissary(this); + } +} + +class SerrasEmissaryEffect extends ContinuousEffectImpl { + + SerrasEmissaryEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "you and creatures you control have protection from the chosen card type"; + } + + private SerrasEmissaryEffect(final SerrasEmissaryEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Object savedType = game.getState().getValue(source.getSourceId() + "_type"); + if (controller == null || !(savedType instanceof CardType)) { + return false; + } + CardType cardType = ((CardType) savedType); + FilterCard filter = new FilterCard(cardType + "s"); + filter.add(cardType.getPredicate()); + Ability ability = new ProtectionAbility(filter); + controller.addAbility(ability); + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getControllerId(), source.getSourceId(), game + )) { + permanent.addAbility(ability, source.getSourceId(), game); + } + return true; + } + + @Override + public SerrasEmissaryEffect copy() { + return new SerrasEmissaryEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SerumRaker.java b/Mage.Sets/src/mage/cards/s/SerumRaker.java index 9055a92de9e..0ad107a9c0b 100644 --- a/Mage.Sets/src/mage/cards/s/SerumRaker.java +++ b/Mage.Sets/src/mage/cards/s/SerumRaker.java @@ -20,6 +20,7 @@ public final class SerumRaker extends CardImpl { public SerumRaker (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DRAKE); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/s/ShatteredAngel.java b/Mage.Sets/src/mage/cards/s/ShatteredAngel.java index 4e894aa6295..dca5cccaf0b 100644 --- a/Mage.Sets/src/mage/cards/s/ShatteredAngel.java +++ b/Mage.Sets/src/mage/cards/s/ShatteredAngel.java @@ -29,6 +29,7 @@ public final class ShatteredAngel extends CardImpl { public ShatteredAngel (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ANGEL); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/s/ShatteredEgo.java b/Mage.Sets/src/mage/cards/s/ShatteredEgo.java new file mode 100644 index 00000000000..0a9df3f3a15 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShatteredEgo.java @@ -0,0 +1,86 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ShatteredEgo extends CardImpl { + + public ShatteredEgo(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets -3/-0. + this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(-3, 0))); + + // {3}{U}{U}: Put enchanted creature into its owner's library third from the top. + this.addAbility(new SimpleActivatedAbility(new ShatteredEgoEffect(), new ManaCostsImpl<>("{3}{U}{U}"))); + } + + private ShatteredEgo(final ShatteredEgo card) { + super(card); + } + + @Override + public ShatteredEgo copy() { + return new ShatteredEgo(this); + } +} + +class ShatteredEgoEffect extends OneShotEffect { + + ShatteredEgoEffect() { + super(Outcome.Benefit); + staticText = "put enchanted creature into its owner's library third from the top"; + } + + private ShatteredEgoEffect(final ShatteredEgoEffect effect) { + super(effect); + } + + @Override + public ShatteredEgoEffect copy() { + return new ShatteredEgoEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent aura = source.getSourcePermanentOrLKI(game); + if (player == null || aura == null) { + return false; + } + Permanent permanent = game.getPermanent(aura.getAttachedTo()); + return permanent != null && player.putCardOnTopXOfLibrary( + permanent, game, source, 3, true + ); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SheoldredWhisperingOne.java b/Mage.Sets/src/mage/cards/s/SheoldredWhisperingOne.java index 5a99b501884..3a6f4b62d4a 100644 --- a/Mage.Sets/src/mage/cards/s/SheoldredWhisperingOne.java +++ b/Mage.Sets/src/mage/cards/s/SheoldredWhisperingOne.java @@ -26,6 +26,7 @@ public final class SheoldredWhisperingOne extends CardImpl { public SheoldredWhisperingOne(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.PRAETOR); this.power = new MageInt(6); diff --git a/Mage.Sets/src/mage/cards/s/ShivanZombie.java b/Mage.Sets/src/mage/cards/s/ShivanZombie.java index 5a1e0e3132f..f0cd0a6ea15 100644 --- a/Mage.Sets/src/mage/cards/s/ShivanZombie.java +++ b/Mage.Sets/src/mage/cards/s/ShivanZombie.java @@ -18,6 +18,7 @@ public final class ShivanZombie extends CardImpl { public ShivanZombie(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{R}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BARBARIAN); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/s/ShriekRaptor.java b/Mage.Sets/src/mage/cards/s/ShriekRaptor.java index 44a4f4b0dcf..d01ac8c6a5a 100644 --- a/Mage.Sets/src/mage/cards/s/ShriekRaptor.java +++ b/Mage.Sets/src/mage/cards/s/ShriekRaptor.java @@ -18,6 +18,7 @@ public final class ShriekRaptor extends CardImpl { public ShriekRaptor(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BIRD); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/s/ShrineOfLoyalLegions.java b/Mage.Sets/src/mage/cards/s/ShrineOfLoyalLegions.java index 3113bd29669..243720cc019 100644 --- a/Mage.Sets/src/mage/cards/s/ShrineOfLoyalLegions.java +++ b/Mage.Sets/src/mage/cards/s/ShrineOfLoyalLegions.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -22,10 +20,11 @@ import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ColorPredicate; -import mage.game.permanent.token.MyrToken; +import mage.game.permanent.token.PhyrexianMyrToken; + +import java.util.UUID; /** - * * @author North */ public final class ShrineOfLoyalLegions extends CardImpl { @@ -37,7 +36,7 @@ public final class ShrineOfLoyalLegions extends CardImpl { } public ShrineOfLoyalLegions(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); //At the beginning of your upkeep or whenever you cast a white spell, put a charge counter on Shrine of Loyal Legions. this.addAbility(new OrTriggeredAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), @@ -46,7 +45,7 @@ public final class ShrineOfLoyalLegions extends CardImpl { //{3}, {T}, Sacrifice Shrine of Loyal Legions: Create a 1/1 colorless Myr artifact creature token for each charge counter on Shrine of Loyal Legions. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new CreateTokenEffect(new MyrToken("NPH"), new CountersSourceCount(CounterType.CHARGE)), + new CreateTokenEffect(new PhyrexianMyrToken(), new CountersSourceCount(CounterType.CHARGE)), new GenericManaCost(3)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); diff --git a/Mage.Sets/src/mage/cards/s/SinisterStarfish.java b/Mage.Sets/src/mage/cards/s/SinisterStarfish.java new file mode 100644 index 00000000000..c66a927851a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SinisterStarfish.java @@ -0,0 +1,38 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.keyword.SurveilEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SinisterStarfish extends CardImpl { + + public SinisterStarfish(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.STARFISH); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // {T}: Surveil 1. + this.addAbility(new SimpleActivatedAbility(new SurveilEffect(1), new TapSourceCost())); + } + + private SinisterStarfish(final SinisterStarfish card) { + super(card); + } + + @Override + public SinisterStarfish copy() { + return new SinisterStarfish(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Skinrender.java b/Mage.Sets/src/mage/cards/s/Skinrender.java index 305fd352001..fa6dd4ec93f 100644 --- a/Mage.Sets/src/mage/cards/s/Skinrender.java +++ b/Mage.Sets/src/mage/cards/s/Skinrender.java @@ -24,6 +24,7 @@ public final class Skinrender extends CardImpl { public Skinrender(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/s/SkirgeFamiliar.java b/Mage.Sets/src/mage/cards/s/SkirgeFamiliar.java index 17882fa725e..b7a95acc200 100644 --- a/Mage.Sets/src/mage/cards/s/SkirgeFamiliar.java +++ b/Mage.Sets/src/mage/cards/s/SkirgeFamiliar.java @@ -23,6 +23,7 @@ public final class SkirgeFamiliar extends CardImpl { public SkirgeFamiliar(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.IMP); this.power = new MageInt(3); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/s/SkithiryxTheBlightDragon.java b/Mage.Sets/src/mage/cards/s/SkithiryxTheBlightDragon.java index 02fcc0eaf08..95279e779e5 100644 --- a/Mage.Sets/src/mage/cards/s/SkithiryxTheBlightDragon.java +++ b/Mage.Sets/src/mage/cards/s/SkithiryxTheBlightDragon.java @@ -28,6 +28,7 @@ public final class SkithiryxTheBlightDragon extends CardImpl { public SkithiryxTheBlightDragon (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DRAGON); this.subtype.add(SubType.SKELETON); diff --git a/Mage.Sets/src/mage/cards/s/SkitteringHorror.java b/Mage.Sets/src/mage/cards/s/SkitteringHorror.java index c976589973e..f685d21d370 100644 --- a/Mage.Sets/src/mage/cards/s/SkitteringHorror.java +++ b/Mage.Sets/src/mage/cards/s/SkitteringHorror.java @@ -19,6 +19,7 @@ public final class SkitteringHorror extends CardImpl { public SkitteringHorror(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(4); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/s/SkitteringSkirge.java b/Mage.Sets/src/mage/cards/s/SkitteringSkirge.java index 57654a9e52f..0623afc013f 100644 --- a/Mage.Sets/src/mage/cards/s/SkitteringSkirge.java +++ b/Mage.Sets/src/mage/cards/s/SkitteringSkirge.java @@ -20,6 +20,7 @@ public final class SkitteringSkirge extends CardImpl { public SkitteringSkirge(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.IMP); this.power = new MageInt(3); this.toughness = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/s/SkybladesBoon.java b/Mage.Sets/src/mage/cards/s/SkybladesBoon.java new file mode 100644 index 00000000000..d356f4620a5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkybladesBoon.java @@ -0,0 +1,79 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SkybladesBoon extends CardImpl { + + public SkybladesBoon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{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 gets +1/+1 and has flying. + ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1)); + ability.addEffect(new GainAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.AURA + ).setText("and has flying")); + this.addAbility(ability); + + // {2}{W}: Return Skyblade's Boon to its owner's hand. Activate only if Skyblade's Boon is on the battlefield or in your graveyard. + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.ALL, new ReturnToHandSourceEffect(), + new ManaCostsImpl<>("{2}{W}"), SkybladesBoonCondition.instance + )); + } + + private SkybladesBoon(final SkybladesBoon card) { + super(card); + } + + @Override + public SkybladesBoon copy() { + return new SkybladesBoon(this); + } +} + +enum SkybladesBoonCondition implements Condition { + instance; + private static final List zones = Arrays.asList(Zone.BATTLEFIELD, Zone.GRAVEYARD); + + @Override + public boolean apply(Game game, Ability source) { + return zones.contains(game.getState().getZone(source.getSourceId())); + } + + @Override + public String toString() { + return "{this} is on the battlefield or in your graveyard"; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SlagFiend.java b/Mage.Sets/src/mage/cards/s/SlagFiend.java index ed858c3c1cf..d90c39afa63 100644 --- a/Mage.Sets/src/mage/cards/s/SlagFiend.java +++ b/Mage.Sets/src/mage/cards/s/SlagFiend.java @@ -22,6 +22,7 @@ public final class SlagFiend extends CardImpl { public SlagFiend(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(0); diff --git a/Mage.Sets/src/mage/cards/s/SlagStrider.java b/Mage.Sets/src/mage/cards/s/SlagStrider.java new file mode 100644 index 00000000000..015eff9257e --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SlagStrider.java @@ -0,0 +1,52 @@ +package mage.cards.s; + +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.DamageTargetEffect; +import mage.abilities.keyword.AffinityForArtifactsAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SlagStrider extends CardImpl { + + public SlagStrider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Affinity for artifacts + this.addAbility(new AffinityForArtifactsAbility()); + + // {1}, Sacrifice an artifact: Slag Strider deals 1 damage to any target. + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(1), new GenericManaCost(1)); + ability.addCost(new SacrificeTargetCost( + new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN) + )); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private SlagStrider(final SlagStrider card) { + super(card); + } + + @Override + public SlagStrider copy() { + return new SlagStrider(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SlashPanther.java b/Mage.Sets/src/mage/cards/s/SlashPanther.java index cf54f9b1fe2..f0aecde0e97 100644 --- a/Mage.Sets/src/mage/cards/s/SlashPanther.java +++ b/Mage.Sets/src/mage/cards/s/SlashPanther.java @@ -17,6 +17,7 @@ public final class SlashPanther extends CardImpl { public SlashPanther(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}{R/P}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CAT); this.power = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/s/SleeperAgent.java b/Mage.Sets/src/mage/cards/s/SleeperAgent.java index 26740b62f07..38ad6e0df9e 100644 --- a/Mage.Sets/src/mage/cards/s/SleeperAgent.java +++ b/Mage.Sets/src/mage/cards/s/SleeperAgent.java @@ -29,6 +29,7 @@ public final class SleeperAgent extends CardImpl { public SleeperAgent(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.MINION); this.power = new MageInt(3); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/s/SlinkingSkirge.java b/Mage.Sets/src/mage/cards/s/SlinkingSkirge.java index e1ebd0e38c4..36d65b56eb0 100644 --- a/Mage.Sets/src/mage/cards/s/SlinkingSkirge.java +++ b/Mage.Sets/src/mage/cards/s/SlinkingSkirge.java @@ -23,6 +23,7 @@ public final class SlinkingSkirge extends CardImpl { public SlinkingSkirge(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.IMP); this.power = new MageInt(2); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/s/SmellFear.java b/Mage.Sets/src/mage/cards/s/SmellFear.java new file mode 100644 index 00000000000..601caa4aeed --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SmellFear.java @@ -0,0 +1,40 @@ +package mage.cards.s; + +import mage.abilities.effects.common.FightTargetsEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SmellFear extends CardImpl { + + public SmellFear(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); + + // Proliferate. + this.getSpellAbility().addEffect(new ProliferateEffect()); + + // Target creature you control fights up to one target creature you don't control. + this.getSpellAbility().addEffect(new FightTargetsEffect( + "
Target creature you control fights up to one target creature you don't control" + )); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); + } + + private SmellFear(final SmellFear card) { + super(card); + } + + @Override + public SmellFear copy() { + return new SmellFear(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoShiny.java b/Mage.Sets/src/mage/cards/s/SoShiny.java new file mode 100644 index 00000000000..535474ff5c7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoShiny.java @@ -0,0 +1,76 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; +import mage.abilities.effects.common.TapEnchantedEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SoShiny extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(TokenPredicate.instance); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ConditionHint(condition, "You control a token"); + + public SoShiny(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // When So Shiny enters the battlefield, if you control a token, tap enchanted creature, then scry 2. + ability = new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()), + condition, "When {this} enters the battlefield, " + + "if you control a token, tap enchanted creature, then scry 2." + ); + ability.addEffect(new ScryEffect(2)); + this.addAbility(ability.addHint(hint)); + + // Enchanted creature doesn't untap during its controller's untap step. + this.addAbility(new SimpleStaticAbility(new DontUntapInControllersUntapStepEnchantedEffect())); + } + + private SoShiny(final SoShiny card) { + super(card); + } + + @Override + public SoShiny copy() { + return new SoShiny(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SojournersCompanion.java b/Mage.Sets/src/mage/cards/s/SojournersCompanion.java new file mode 100644 index 00000000000..4213dbe9848 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SojournersCompanion.java @@ -0,0 +1,41 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.keyword.AffinityForArtifactsAbility; +import mage.abilities.keyword.ArtifactLandcyclingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SojournersCompanion extends CardImpl { + + public SojournersCompanion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{7}"); + + this.subtype.add(SubType.SALAMANDER); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Affinity for artifacts + this.addAbility(new AffinityForArtifactsAbility()); + + // Artifact landcycling {2} + this.addAbility(new ArtifactLandcyclingAbility(new GenericManaCost(2))); + } + + private SojournersCompanion(final SojournersCompanion card) { + super(card); + } + + @Override + public SojournersCompanion copy() { + return new SojournersCompanion(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SolTalisman.java b/Mage.Sets/src/mage/cards/s/SolTalisman.java new file mode 100644 index 00000000000..d37547f7f88 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SolTalisman.java @@ -0,0 +1,38 @@ +package mage.cards.s; + +import mage.Mana; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.keyword.SuspendAbility; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SolTalisman extends CardImpl { + + public SolTalisman(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, ""); + + // Suspend 3—{1} + this.addAbility(new SuspendAbility(3, new GenericManaCost(1), this)); + + // {T}: Add {C}{C}. + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana(2), new TapSourceCost())); + } + + private SolTalisman(final SolTalisman card) { + super(card); + } + + @Override + public SolTalisman copy() { + return new SolTalisman(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoulOfMigration.java b/Mage.Sets/src/mage/cards/s/SoulOfMigration.java new file mode 100644 index 00000000000..0ae5a3c590b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoulOfMigration.java @@ -0,0 +1,46 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.EvokeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.BirdToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SoulOfMigration extends CardImpl { + + public SoulOfMigration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{W}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Soul of Migration enters the battlefield, create two 1/1 white Bird creature tokens with flying. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new BirdToken(), 2))); + + // Evoke {3}{W} + this.addAbility(new EvokeAbility("{3}{W}")); + } + + private SoulOfMigration(final SoulOfMigration card) { + super(card); + } + + @Override + public SoulOfMigration copy() { + return new SoulOfMigration(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoulOfNewPhyrexia.java b/Mage.Sets/src/mage/cards/s/SoulOfNewPhyrexia.java index cbfaf7b84a5..cc289bfa397 100644 --- a/Mage.Sets/src/mage/cards/s/SoulOfNewPhyrexia.java +++ b/Mage.Sets/src/mage/cards/s/SoulOfNewPhyrexia.java @@ -25,6 +25,7 @@ public final class SoulOfNewPhyrexia extends CardImpl { public SoulOfNewPhyrexia(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{6}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.AVATAR); this.power = new MageInt(6); diff --git a/Mage.Sets/src/mage/cards/s/SpecimenCollector.java b/Mage.Sets/src/mage/cards/s/SpecimenCollector.java new file mode 100644 index 00000000000..91011f520ce --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpecimenCollector.java @@ -0,0 +1,60 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.CrabToken; +import mage.game.permanent.token.SquirrelToken; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpecimenCollector extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent("token you control"); + + static { + filter.add(TokenPredicate.instance); + } + + public SpecimenCollector(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.VEDALKEN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // When Specimen Collector enters the battlefield, create a 1/1 green Squirrel creature token and a 0/3 blue Crab creature token. + Ability ability = new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SquirrelToken())); + ability.addEffect(new CreateTokenEffect(new CrabToken()).setText("and a 0/3 blue Crab creature token")); + this.addAbility(ability); + + // When Specimen Collector dies, create a token that's a copy of target token you control. + ability = new DiesSourceTriggeredAbility(new CreateTokenCopyTargetEffect()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private SpecimenCollector(final SpecimenCollector card) { + super(card); + } + + @Override + public SpecimenCollector copy() { + return new SpecimenCollector(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Spellskite.java b/Mage.Sets/src/mage/cards/s/Spellskite.java index 21cad613489..f96b3ef70d4 100644 --- a/Mage.Sets/src/mage/cards/s/Spellskite.java +++ b/Mage.Sets/src/mage/cards/s/Spellskite.java @@ -32,6 +32,7 @@ public final class Spellskite extends CardImpl { public Spellskite(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(0); this.toughness = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/s/Spinebiter.java b/Mage.Sets/src/mage/cards/s/Spinebiter.java index bf935245b15..cb7a129873f 100644 --- a/Mage.Sets/src/mage/cards/s/Spinebiter.java +++ b/Mage.Sets/src/mage/cards/s/Spinebiter.java @@ -18,6 +18,7 @@ public final class Spinebiter extends CardImpl { public Spinebiter(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BEAST); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/s/SpinedThopter.java b/Mage.Sets/src/mage/cards/s/SpinedThopter.java index ac9f578473a..6ab3bdb076e 100644 --- a/Mage.Sets/src/mage/cards/s/SpinedThopter.java +++ b/Mage.Sets/src/mage/cards/s/SpinedThopter.java @@ -17,6 +17,7 @@ public final class SpinedThopter extends CardImpl { public SpinedThopter(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}{U/P}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.THOPTER); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/s/SpinelessThug.java b/Mage.Sets/src/mage/cards/s/SpinelessThug.java index 476c7ccc542..9b76ce7b93b 100644 --- a/Mage.Sets/src/mage/cards/s/SpinelessThug.java +++ b/Mage.Sets/src/mage/cards/s/SpinelessThug.java @@ -17,6 +17,7 @@ public final class SpinelessThug extends CardImpl { public SpinelessThug(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.MERCENARY); diff --git a/Mage.Sets/src/mage/cards/s/SpireMonitor.java b/Mage.Sets/src/mage/cards/s/SpireMonitor.java index 6e93c425d94..c03ca88b553 100644 --- a/Mage.Sets/src/mage/cards/s/SpireMonitor.java +++ b/Mage.Sets/src/mage/cards/s/SpireMonitor.java @@ -18,6 +18,7 @@ public final class SpireMonitor extends CardImpl { public SpireMonitor(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DRAKE); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/s/SpitefulBully.java b/Mage.Sets/src/mage/cards/s/SpitefulBully.java index 5f069b76c4f..e1470a78428 100644 --- a/Mage.Sets/src/mage/cards/s/SpitefulBully.java +++ b/Mage.Sets/src/mage/cards/s/SpitefulBully.java @@ -22,6 +22,7 @@ public final class SpitefulBully extends CardImpl { public SpitefulBully(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.MERCENARY); this.power = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/s/SplicersSkill.java b/Mage.Sets/src/mage/cards/s/SplicersSkill.java index 36522d00dfd..4b6076ff24c 100644 --- a/Mage.Sets/src/mage/cards/s/SplicersSkill.java +++ b/Mage.Sets/src/mage/cards/s/SplicersSkill.java @@ -5,7 +5,7 @@ import mage.abilities.keyword.SpliceOntoInstantOrSorceryAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.game.permanent.token.GolemToken; +import mage.game.permanent.token.PhyrexianGolemToken; import java.util.UUID; @@ -18,7 +18,7 @@ public final class SplicersSkill extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}"); // Create a 3/3 colorless Golem artifact creature token. - this.getSpellAbility().addEffect(new CreateTokenEffect(new GolemToken())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new PhyrexianGolemToken())); // Splice onto instant or sorcery {3}{W} this.addAbility(new SpliceOntoInstantOrSorceryAbility("{3}{W}")); diff --git a/Mage.Sets/src/mage/cards/s/SteelDromedary.java b/Mage.Sets/src/mage/cards/s/SteelDromedary.java new file mode 100644 index 00000000000..ec19ff467c9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SteelDromedary.java @@ -0,0 +1,98 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SteelDromedary extends CardImpl { + + private static final Condition condition = new SourceHasCounterCondition(CounterType.P1P1); + + public SteelDromedary(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + + this.subtype.add(SubType.CAMEL); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Steel Dromedary enters the battlefield tapped with two +1/+1 counters on it. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( + CounterType.P1P1.createInstance(2) + ), "with two +1/+1 counters on it")); + + // Steel Dromedary doesn't untap during your untap step if it has a +1/+1 counter on it. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousRuleModifyingEffect( + new DontUntapInControllersUntapStepSourceEffect(), condition + ).setText("{this} doesn't untap during your untap step if it has a +1/+1 counter on it"))); + + // At the beginning of combat on your turn, you may move a +1/+1 counter from Steel Dromedary onto target creature. + Ability ability = new BeginningOfCombatTriggeredAbility( + new SteelDromedaryEffect(), TargetController.YOU, true + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private SteelDromedary(final SteelDromedary card) { + super(card); + } + + @Override + public SteelDromedary copy() { + return new SteelDromedary(this); + } +} + +class SteelDromedaryEffect extends OneShotEffect { + + SteelDromedaryEffect() { + super(Outcome.Benefit); + staticText = "move a +1/+1 counter from {this} onto target creature"; + } + + private SteelDromedaryEffect(final SteelDromedaryEffect effect) { + super(effect); + } + + @Override + public SteelDromedaryEffect copy() { + return new SteelDromedaryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + Permanent creature = game.getPermanent(source.getFirstTarget()); + if (permanent != null + && creature != null + && permanent.getCounters(game).getCount(CounterType.P1P1) > 0 + && creature.addCounters(CounterType.P1P1.createInstance(), source.getControllerId(), source, game)) { + permanent.removeCounters(CounterType.P1P1.createInstance(), source, game); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SteelfinWhale.java b/Mage.Sets/src/mage/cards/s/SteelfinWhale.java new file mode 100644 index 00000000000..fbaa7cf5ccb --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SteelfinWhale.java @@ -0,0 +1,44 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.common.UntapSourceEffect; +import mage.abilities.keyword.AffinityForArtifactsAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SteelfinWhale extends CardImpl { + + public SteelfinWhale(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); + + this.subtype.add(SubType.WHALE); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Affinity for artifacts + this.addAbility(new AffinityForArtifactsAbility()); + + // Whenever an artifact enters the battlefield under your control, untap Steelfin Whale. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new UntapSourceEffect(), StaticFilters.FILTER_PERMANENT_ARTIFACT_AN + )); + } + + private SteelfinWhale(final SteelfinWhale card) { + super(card); + } + + @Override + public SteelfinWhale copy() { + return new SteelfinWhale(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StormGodsOracle.java b/Mage.Sets/src/mage/cards/s/StormGodsOracle.java new file mode 100644 index 00000000000..d3913a0e2a6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StormGodsOracle.java @@ -0,0 +1,51 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesSourceTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StormGodsOracle extends CardImpl { + + public StormGodsOracle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{1}{U}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // {1}: Storm God's Oracle gets +1/-1 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(1, -1, Duration.EndOfTurn), new GenericManaCost(1) + )); + + // When Storm God's Oracle dies, it deals 3 damage to any target. + Ability ability = new DiesSourceTriggeredAbility(new DamageTargetEffect(3, "it")); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private StormGodsOracle(final StormGodsOracle card) { + super(card); + } + + @Override + public StormGodsOracle copy() { + return new StormGodsOracle(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StrikeItRich.java b/Mage.Sets/src/mage/cards/s/StrikeItRich.java new file mode 100644 index 00000000000..27e974ad193 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StrikeItRich.java @@ -0,0 +1,37 @@ +package mage.cards.s; + +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.FlashbackAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TimingRule; +import mage.game.permanent.token.TreasureToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StrikeItRich extends CardImpl { + + public StrikeItRich(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}"); + + // Create a Treasure token. + this.getSpellAbility().addEffect(new CreateTokenEffect(new TreasureToken())); + + // Flashback {2}{R} + this.addAbility(new FlashbackAbility(new ManaCostsImpl<>("{2}{R}"), TimingRule.SORCERY)); + } + + private StrikeItRich(final StrikeItRich card) { + super(card); + } + + @Override + public StrikeItRich copy() { + return new StrikeItRich(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StrongholdAssassin.java b/Mage.Sets/src/mage/cards/s/StrongholdAssassin.java index 1b1d2d772f6..f7e3849f601 100644 --- a/Mage.Sets/src/mage/cards/s/StrongholdAssassin.java +++ b/Mage.Sets/src/mage/cards/s/StrongholdAssassin.java @@ -36,6 +36,7 @@ public final class StrongholdAssassin extends CardImpl { public StrongholdAssassin(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.ASSASSIN); diff --git a/Mage.Sets/src/mage/cards/s/Suspend.java b/Mage.Sets/src/mage/cards/s/Suspend.java new file mode 100644 index 00000000000..2c25424c704 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Suspend.java @@ -0,0 +1,88 @@ +package mage.cards.s; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainSuspendEffect; +import mage.abilities.keyword.SuspendAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Suspend extends CardImpl { + + public Suspend(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + + // Exile target creature and put two time counters on it. If it doesn't have suspend, it gains suspend. + this.getSpellAbility().addEffect(new SuspendEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private Suspend(final Suspend card) { + super(card); + } + + @Override + public Suspend copy() { + return new Suspend(this); + } +} + +class SuspendEffect extends OneShotEffect { + + SuspendEffect() { + super(Outcome.Benefit); + staticText = "exile target creature and put two time counters on it. " + + "If it doesn't have suspend, it gains suspend"; + } + + private SuspendEffect(final SuspendEffect effect) { + super(effect); + } + + @Override + public SuspendEffect copy() { + return new SuspendEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (controller == null || permanent == null) { + return false; + } + Card card = permanent.getMainCard(); + if (!controller.moveCards(permanent, Zone.EXILED, source, game) + || game.getState().getZone(card.getId()) != Zone.EXILED) { + return true; + } + UUID exileId = SuspendAbility.getSuspendExileId(controller.getId(), game); + if (!controller.moveCardToExileWithInfo( + card, exileId, "Suspended cards of " + controller.getLogName(), + source, game, Zone.HAND, true + )) { + return true; + } + card.addCounters(CounterType.TIME.createInstance(2), source.getControllerId(), source, game); + if (!card.getAbilities(game).containsClass(SuspendAbility.class)) { + game.addEffect(new GainSuspendEffect(new MageObjectReference(card, game)), source); + } + game.informPlayers(controller.getLogName() + " suspends 2 - " + card.getName()); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SuturePriest.java b/Mage.Sets/src/mage/cards/s/SuturePriest.java index 6cf412d3590..5baa7e14a62 100644 --- a/Mage.Sets/src/mage/cards/s/SuturePriest.java +++ b/Mage.Sets/src/mage/cards/s/SuturePriest.java @@ -29,6 +29,7 @@ public final class SuturePriest extends CardImpl { public SuturePriest(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/s/SvyelunOfSeaAndSky.java b/Mage.Sets/src/mage/cards/s/SvyelunOfSeaAndSky.java new file mode 100644 index 00000000000..c626f4c3ba9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SvyelunOfSeaAndSky.java @@ -0,0 +1,75 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.WardAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SvyelunOfSeaAndSky extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.MERFOLK, "other Merfolk"); + + static { + filter.add(AnotherPredicate.instance); + } + + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + private static final Hint hint + = new ValueHint("Other Merfolk you control", new PermanentsOnBattlefieldCount(filter)); + + public SvyelunOfSeaAndSky(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.GOD); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Svyelun of Sea and Sky has indestructible as long as you control at least two other Merfolk. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield), + condition, "{this} has indestructible as long as you control at least two other Merfolk" + ))); + + // Whenever Svyelun attacks, draw a card. + this.addAbility(new AttacksTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); + + // Other Merfolk you control have ward {1}. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new WardAbility(new GenericManaCost(1)), Duration.WhileOnBattlefield, filter + ))); + } + + private SvyelunOfSeaAndSky(final SvyelunOfSeaAndSky card) { + super(card); + } + + @Override + public SvyelunOfSeaAndSky copy() { + return new SvyelunOfSeaAndSky(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SwordOfBodyAndMind.java b/Mage.Sets/src/mage/cards/s/SwordOfBodyAndMind.java index a7be5dabb61..d7125ec8ffd 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfBodyAndMind.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfBodyAndMind.java @@ -1,14 +1,10 @@ - - package mage.cards.s; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; @@ -17,34 +13,30 @@ import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.ProtectionAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.permanent.token.WolfToken; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author Loki */ public final class SwordOfBodyAndMind extends CardImpl { public SwordOfBodyAndMind(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +2/+2 and has protection from green and from blue. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 2)); - Effect effect = new GainAbilityAttachedEffect(ProtectionAbility.from(ObjectColor.GREEN, ObjectColor.BLUE), AttachmentType.EQUIPMENT); - effect.setText("and has protection from green and from blue"); - ability.addEffect(effect); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2)); + ability.addEffect(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.GREEN, ObjectColor.BLUE), AttachmentType.EQUIPMENT + ).setText("and has protection from green and from blue")); this.addAbility(ability); // Whenever equipped creature deals combat damage to a player, you create a 2/2 green Wolf creature token and that player puts the top ten cards of their library into their graveyard. @@ -87,12 +79,10 @@ class SwordOfBodyAndMindAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent)event; + DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; Permanent p = game.getPermanent(event.getSourceId()); if (damageEvent.isCombatDamage() && p != null && p.getAttachments().contains(this.getSourceId())) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - } + this.getEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); return true; } return false; @@ -102,4 +92,4 @@ class SwordOfBodyAndMindAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever equipped creature deals combat damage to a player, you create a 2/2 green Wolf creature token and that player mills ten cards."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SwordOfFeastAndFamine.java b/Mage.Sets/src/mage/cards/s/SwordOfFeastAndFamine.java index 1fde6eb4249..2726d3e9a05 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfFeastAndFamine.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfFeastAndFamine.java @@ -1,10 +1,10 @@ package mage.cards.s; import mage.ObjectColor; +import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.UntapAllLandsControllerEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; @@ -17,7 +17,6 @@ import mage.constants.*; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; @@ -32,15 +31,18 @@ public final class SwordOfFeastAndFamine extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); this.subtype.add(SubType.EQUIPMENT); - // Equip {2} - this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2))); - // Equipped creature gets +2/+2 and has protection from black and from green. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 2))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ProtectionAbility.from(ObjectColor.GREEN, ObjectColor.BLACK), AttachmentType.EQUIPMENT))); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2)); + ability.addEffect(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.BLACK, ObjectColor.GREEN), AttachmentType.EQUIPMENT + ).setText("and has protection from black and from green")); + this.addAbility(ability); // Whenever equipped creature deals combat damage to a player, that player discards a card and you untap all lands you control. this.addAbility(new SwordOfFeastAndFamineAbility()); + + // Equip {2} + this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2))); } private SwordOfFeastAndFamine(final SwordOfFeastAndFamine card) { @@ -79,9 +81,7 @@ class SwordOfFeastAndFamineAbility extends TriggeredAbilityImpl { DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; Permanent p = game.getPermanent(event.getSourceId()); if (damageEvent.isCombatDamage() && p != null && p.getAttachments().contains(this.getSourceId())) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - } + this.getEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); return true; } return false; @@ -89,6 +89,7 @@ class SwordOfFeastAndFamineAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever equipped creature deals combat damage to a player, that player discards a card and you untap all lands you control."; + return "Whenever equipped creature deals combat damage to a player, " + + "that player discards a card and you untap all lands you control."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SwordOfFireAndIce.java b/Mage.Sets/src/mage/cards/s/SwordOfFireAndIce.java index dce0293fc3e..2f169cfbddd 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfFireAndIce.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfFireAndIce.java @@ -1,8 +1,8 @@ package mage.cards.s; -import java.util.UUID; import mage.ObjectColor; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.DamageTargetEffect; @@ -15,16 +15,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AttachmentType; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; +import mage.constants.SubType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** * @author Loki */ @@ -35,12 +31,21 @@ public final class SwordOfFireAndIce extends CardImpl { this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +2/+2 and has protection from red and from blue. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 2))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect( - ProtectionAbility.from(ObjectColor.RED, ObjectColor.BLUE), AttachmentType.EQUIPMENT))); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2)); + ability.addEffect(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.RED, ObjectColor.BLUE), AttachmentType.EQUIPMENT + ).setText("and has protection from red and from blue")); + this.addAbility(ability); + // Whenever equipped creature deals combat damage to a player, Sword of Fire // and Ice deals 2 damage to any target and you draw a card. - this.addAbility(new SwordOfFireAndIceAbility()); + ability = new DealsDamageToAPlayerAttachedTriggeredAbility( + new DamageTargetEffect(2), "equipped", false + ); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + // Equip {2} this.addAbility(new EquipAbility(Outcome.Benefit, new GenericManaCost(2))); } @@ -55,41 +60,3 @@ public final class SwordOfFireAndIce extends CardImpl { } } - -class SwordOfFireAndIceAbility extends TriggeredAbilityImpl { - - public SwordOfFireAndIceAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2)); - this.addEffect(new DrawCardSourceControllerEffect(1)); - this.addTarget(new TargetAnyTarget()); - } - - public SwordOfFireAndIceAbility(final SwordOfFireAndIceAbility ability) { - super(ability); - } - - @Override - public SwordOfFireAndIceAbility copy() { - return new SwordOfFireAndIceAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; - Permanent p = game.getPermanent(event.getSourceId()); - return damageEvent.isCombatDamage() - && p != null - && p.getAttachments().contains(this.getSourceId()); - } - - @Override - public String getRule() { - return "Whenever equipped creature deals combat damage to a player, " - + "{this} deals 2 damage to any target and you draw a card."; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SwordOfHearthAndHome.java b/Mage.Sets/src/mage/cards/s/SwordOfHearthAndHome.java new file mode 100644 index 00000000000..f43d18eb7d5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SwordOfHearthAndHome.java @@ -0,0 +1,109 @@ +package mage.cards.s; + +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SwordOfHearthAndHome extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature you own"); + + static { + filter.add(TargetController.YOU.getOwnerPredicate()); + } + + public SwordOfHearthAndHome(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +2/+2 and has protection from green and from white. + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2)); + ability.addEffect(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.GREEN, ObjectColor.WHITE), AttachmentType.EQUIPMENT + ).setText("and has protection from green and from white")); + this.addAbility(ability); + + // Whenever equipped creature deals combat damage to a player, exile up to one target creature you own, then search your library for a basic land card. Put both cards onto the battlefield under your control, then shuffle. + ability = new DealsDamageToAPlayerAttachedTriggeredAbility( + new SwordOfHearthAndHomeEffect(), "equipped", false + ); + ability.addTarget(new TargetPermanent(0, 1, filter)); + this.addAbility(ability); + + // Equip {2} + this.addAbility(new EquipAbility(Outcome.Benefit, new GenericManaCost(2))); + } + + private SwordOfHearthAndHome(final SwordOfHearthAndHome card) { + super(card); + } + + @Override + public SwordOfHearthAndHome copy() { + return new SwordOfHearthAndHome(this); + } +} + +class SwordOfHearthAndHomeEffect extends OneShotEffect { + + SwordOfHearthAndHomeEffect() { + super(Outcome.Benefit); + staticText = "exile up to one target creature you own, then search your library for a basic land card. " + + "Put both cards onto the battlefield under your control, then shuffle"; + } + + private SwordOfHearthAndHomeEffect(final SwordOfHearthAndHomeEffect effect) { + super(effect); + } + + @Override + public SwordOfHearthAndHomeEffect copy() { + return new SwordOfHearthAndHomeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + player.moveCards(permanent, Zone.EXILED, source, game); + cards.add(permanent); + } + TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND); + player.searchLibrary(target, source, game); + cards.add(player.getLibrary().getCard(target.getFirstTarget(), game)); + player.moveCards(cards, Zone.BATTLEFIELD, source, game); + player.shuffleLibrary(source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SwordOfLightAndShadow.java b/Mage.Sets/src/mage/cards/s/SwordOfLightAndShadow.java index 61a10a06634..9a27b5cd093 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfLightAndShadow.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfLightAndShadow.java @@ -1,10 +1,8 @@ - package mage.cards.s; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; @@ -16,20 +14,14 @@ import mage.abilities.keyword.ProtectionAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** * @author Loki */ @@ -40,12 +32,22 @@ public final class SwordOfLightAndShadow extends CardImpl { this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +2/+2 and has protection from white and from black. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 2))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ProtectionAbility.from(ObjectColor.WHITE, ObjectColor.BLACK), AttachmentType.EQUIPMENT))); - // Whenever equipped creature deals combat damage to a player, you gain 3 life and you may return up to one target creature card from your graveyard to your hand. - Ability ability = new SwordOfLightAndShadowAbility(); - ability.addTarget(new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2)); + ability.addEffect(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.WHITE, ObjectColor.BLACK), AttachmentType.EQUIPMENT + ).setText("and has protection from white and from black")); this.addAbility(ability); + + // Whenever equipped creature deals combat damage to a player, you gain 3 life and you may return up to one target creature card from your graveyard to your hand. + ability = new DealsDamageToAPlayerAttachedTriggeredAbility( + new GainLifeEffect(3), "equipped", false + ); + ability.addEffect(new SwordOfLightAndShadowEffect()); + ability.addTarget(new TargetCardInYourGraveyard( + 0, 1, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD + )); + this.addAbility(ability); + // Equip {2} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2))); } @@ -60,81 +62,28 @@ public final class SwordOfLightAndShadow extends CardImpl { } } -class SwordOfLightAndShadowAbility extends TriggeredAbilityImpl { +class SwordOfLightAndShadowEffect extends OneShotEffect { - public SwordOfLightAndShadowAbility() { - super(Zone.BATTLEFIELD, new GainLifeEffect(3), false); - this.addEffect(new SwordOfLightAndShadowReturnToHandTargetEffect()); - - } - - public SwordOfLightAndShadowAbility(final SwordOfLightAndShadowAbility ability) { - super(ability); - } - - @Override - public SwordOfLightAndShadowAbility copy() { - return new SwordOfLightAndShadowAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - DamagedPlayerEvent damageEvent = (DamagedPlayerEvent) event; - Permanent p = game.getPermanent(event.getSourceId()); - return damageEvent.isCombatDamage() && p != null && p.getAttachments().contains(this.getSourceId()); - } - - @Override - public String getRule() { - return "Whenever equipped creature deals combat damage to a player, you gain 3 life and you may return up to one target creature card from your graveyard to your hand."; - } -} - -class SwordOfLightAndShadowReturnToHandTargetEffect extends OneShotEffect { - - public SwordOfLightAndShadowReturnToHandTargetEffect() { + public SwordOfLightAndShadowEffect() { super(Outcome.ReturnToHand); staticText = "and you may return up to one target creature card from your graveyard to your hand"; } - public SwordOfLightAndShadowReturnToHandTargetEffect(final SwordOfLightAndShadowReturnToHandTargetEffect effect) { + public SwordOfLightAndShadowEffect(final SwordOfLightAndShadowEffect effect) { super(effect); } @Override - public SwordOfLightAndShadowReturnToHandTargetEffect copy() { - return new SwordOfLightAndShadowReturnToHandTargetEffect(this); + public SwordOfLightAndShadowEffect copy() { + return new SwordOfLightAndShadowEffect(this); } @Override public boolean apply(Game game, Ability source) { - boolean result = true; // in case no target is selected Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - if (!source.getTargets().isEmpty() && targetPointer.getFirst(game, source) != null) { - if (controller.chooseUse(outcome, "Return creature card from graveyard to hand?", source, game)) { - for (UUID targetId : targetPointer.getTargets(game, source)) { - switch (game.getState().getZone(targetId)) { - case GRAVEYARD: - Card card = game.getCard(targetId); - if (card != null) { - controller.moveCards(card, Zone.HAND, source, game); - } else { - result = false; - } - break; - } - } - } - } - return result; + Card card = game.getCard(targetPointer.getFirst(game, source)); + return controller != null && card != null && controller.chooseUse( + outcome, "Return " + card.getName() + " from your graveyard to your hand?", source, game + ) && controller.moveCards(card, Zone.HAND, source, game); } - } diff --git a/Mage.Sets/src/mage/cards/s/SwordOfSinewAndSteel.java b/Mage.Sets/src/mage/cards/s/SwordOfSinewAndSteel.java index 0ca554787de..5fd5c2d1c4c 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfSinewAndSteel.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfSinewAndSteel.java @@ -33,9 +33,9 @@ public final class SwordOfSinewAndSteel extends CardImpl { // Equipped creature gets +2/+2 and has protection from black and from red. Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2)); - ability.addEffect(new GainAbilityAttachedEffect(ProtectionAbility.from( - ObjectColor.BLACK, ObjectColor.RED - ), AttachmentType.EQUIPMENT).setText("and has protection from black and from red")); + ability.addEffect(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.BLACK, ObjectColor.RED), AttachmentType.EQUIPMENT + ).setText("and has protection from black and from red")); this.addAbility(ability); // Whenever equipped creature deals combat damage to a player, destroy up to one target planeswalker and up to one target artifact. diff --git a/Mage.Sets/src/mage/cards/s/SwordOfTruthAndJustice.java b/Mage.Sets/src/mage/cards/s/SwordOfTruthAndJustice.java index c8f902ef4c6..f4bc9dce2d4 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfTruthAndJustice.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfTruthAndJustice.java @@ -38,9 +38,9 @@ public final class SwordOfTruthAndJustice extends CardImpl { // Equipped creature gets +2/+2 and has protection from white and from blue. Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2)); - ability.addEffect(new GainAbilityAttachedEffect(ProtectionAbility.from( - ObjectColor.WHITE, ObjectColor.BLUE - ), AttachmentType.EQUIPMENT).setText("and has protection from white and from blue")); + ability.addEffect(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.WHITE, ObjectColor.BLUE), AttachmentType.EQUIPMENT + ).setText("and has protection from white and from blue")); this.addAbility(ability); // Whenever equipped creature deals combat damage to a player, put a +1/+1 counter on a creature you control, then proliferate. diff --git a/Mage.Sets/src/mage/cards/s/SwordOfWarAndPeace.java b/Mage.Sets/src/mage/cards/s/SwordOfWarAndPeace.java index fbb56c2eca9..4998d591815 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfWarAndPeace.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfWarAndPeace.java @@ -6,7 +6,6 @@ import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.BoostEquippedEffect; @@ -19,7 +18,6 @@ import mage.constants.*; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; @@ -36,10 +34,10 @@ public final class SwordOfWarAndPeace extends CardImpl { this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +2/+2 and has protection from red and from white. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 2)); - Effect effect = new GainAbilityAttachedEffect(ProtectionAbility.from(ObjectColor.RED, ObjectColor.WHITE), AttachmentType.EQUIPMENT); - effect.setText("and has protection from red and from white"); - ability.addEffect(effect); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(2, 2)); + ability.addEffect(new GainAbilityAttachedEffect( + ProtectionAbility.from(ObjectColor.RED, ObjectColor.WHITE), AttachmentType.EQUIPMENT + ).setText("and has protection from red and from white")); this.addAbility(ability); // Whenever equipped creature deals combat damage to a player, Sword of War and Peace deals damage to that player equal to the number of cards in their hand and you gain 1 life for each card in your hand. diff --git a/Mage.Sets/src/mage/cards/s/SythisHarvestsHand.java b/Mage.Sets/src/mage/cards/s/SythisHarvestsHand.java new file mode 100644 index 00000000000..9c2aa9cf337 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SythisHarvestsHand.java @@ -0,0 +1,50 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SythisHarvestsHand extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("an enchantment spell"); + + static { + filter.add(CardType.ENCHANTMENT.getPredicate()); + } + + public SythisHarvestsHand(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{G}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.NYMPH); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Whenever you cast an enchantment spell, you gain 1 life and draw a card. + Ability ability = new SpellCastControllerTriggeredAbility(new GainLifeEffect(1), filter, false); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + this.addAbility(ability); + } + + private SythisHarvestsHand(final SythisHarvestsHand card) { + super(card); + } + + @Override + public SythisHarvestsHand copy() { + return new SythisHarvestsHand(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TangleAngler.java b/Mage.Sets/src/mage/cards/t/TangleAngler.java index 7c759660a40..923170315fb 100644 --- a/Mage.Sets/src/mage/cards/t/TangleAngler.java +++ b/Mage.Sets/src/mage/cards/t/TangleAngler.java @@ -23,6 +23,7 @@ public final class TangleAngler extends CardImpl { public TangleAngler(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/t/TangleHulk.java b/Mage.Sets/src/mage/cards/t/TangleHulk.java index 962ba1c4ac3..b07d14d693a 100644 --- a/Mage.Sets/src/mage/cards/t/TangleHulk.java +++ b/Mage.Sets/src/mage/cards/t/TangleHulk.java @@ -21,6 +21,7 @@ public final class TangleHulk extends CardImpl { public TangleHulk (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{5}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BEAST); this.power = new MageInt(5); this.toughness = new MageInt(3); diff --git a/Mage.Sets/src/mage/cards/t/TavernScoundrel.java b/Mage.Sets/src/mage/cards/t/TavernScoundrel.java new file mode 100644 index 00000000000..986956ba18d --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TavernScoundrel.java @@ -0,0 +1,98 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.FlipCoinEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; +import mage.game.Game; +import mage.game.events.CoinFlippedEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.token.TreasureToken; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TavernScoundrel extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("another permanent"); + + static { + filter.add(AnotherPredicate.instance); + } + + public TavernScoundrel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Whenever you win a coin flip, create two Treasure tokens. + this.addAbility(new TavernScoundrelTriggeredAbility()); + + // {1}, {T}, Sacrifice another permanent: Flip a coin. + Ability ability = new SimpleActivatedAbility(new FlipCoinEffect(), new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + this.addAbility(ability); + } + + private TavernScoundrel(final TavernScoundrel card) { + super(card); + } + + @Override + public TavernScoundrel copy() { + return new TavernScoundrel(this); + } +} + +class TavernScoundrelTriggeredAbility extends TriggeredAbilityImpl { + + TavernScoundrelTriggeredAbility() { + super(Zone.BATTLEFIELD, new CreateTokenEffect(new TreasureToken(), 2), false); + } + + private TavernScoundrelTriggeredAbility(final TavernScoundrelTriggeredAbility ability) { + super(ability); + } + + @Override + public TavernScoundrelTriggeredAbility copy() { + return new TavernScoundrelTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.COIN_FLIPPED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + CoinFlippedEvent flipEvent = (CoinFlippedEvent) event; + return isControlledBy(event.getPlayerId()) + && flipEvent.isWinnable() + && flipEvent.wasWon(); + } + + @Override + public String getRule() { + return "Whenever you win a coin flip, create two Treasure tokens."; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TelJiladFallen.java b/Mage.Sets/src/mage/cards/t/TelJiladFallen.java index 252725852db..53b4d32b42b 100644 --- a/Mage.Sets/src/mage/cards/t/TelJiladFallen.java +++ b/Mage.Sets/src/mage/cards/t/TelJiladFallen.java @@ -20,6 +20,7 @@ public final class TelJiladFallen extends CardImpl { public TelJiladFallen (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ELF); this.subtype.add(SubType.WARRIOR); diff --git a/Mage.Sets/src/mage/cards/t/TerminalAgony.java b/Mage.Sets/src/mage/cards/t/TerminalAgony.java new file mode 100644 index 00000000000..f4200e43ee9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TerminalAgony.java @@ -0,0 +1,37 @@ +package mage.cards.t; + +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.MadnessAbility; +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 TerminalAgony extends CardImpl { + + public TerminalAgony(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{R}"); + + // Destroy target creature. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Madness {B}{R} + this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{B}{R}"))); + } + + private TerminalAgony(final TerminalAgony card) { + super(card); + } + + @Override + public TerminalAgony copy() { + return new TerminalAgony(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/Terramorph.java b/Mage.Sets/src/mage/cards/t/Terramorph.java new file mode 100644 index 00000000000..5576991e4a7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/Terramorph.java @@ -0,0 +1,38 @@ +package mage.cards.t; + +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.keyword.ReboundAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Terramorph extends CardImpl { + + public Terramorph(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); + + // Search your library for a basic land card, put it into the battlefield, then shuffle. + this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), false + )); + + // Rebound + this.addAbility(new ReboundAbility()); + } + + private Terramorph(final Terramorph card) { + super(card); + } + + @Override + public Terramorph copy() { + return new Terramorph(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TerritorialKavu.java b/Mage.Sets/src/mage/cards/t/TerritorialKavu.java new file mode 100644 index 00000000000..136ee8f1b1c --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TerritorialKavu.java @@ -0,0 +1,67 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.DomainValue; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.abilities.hint.common.DomainHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.target.common.TargetCardInGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TerritorialKavu extends CardImpl { + + private static final DynamicValue xValue = new DomainValue(); + + public TerritorialKavu(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}"); + + this.subtype.add(SubType.KAVU); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Domain — Territorial Kavu's power and toughness are each equal to the number of basic land types among lands you control. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SetPowerToughnessSourceEffect(xValue, Duration.EndOfGame) + ).addHint(DomainHint.instance)); + + // Whenever Territorial Kavu attacks, choose one — + // • Discard a card. If you do, draw a card. + Ability ability = new AttacksTriggeredAbility(new DoIfCostPaid( + new DrawCardSourceControllerEffect(1), + null, new DiscardCardCost(), false + ), false); + + // • Exile up to one target card from a graveyard. + Mode mode = new Mode(new ExileTargetEffect()); + mode.addTarget(new TargetCardInGraveyard(0, 1)); + ability.addMode(mode); + this.addAbility(ability); + } + + private TerritorialKavu(final TerritorialKavu card) { + super(card); + } + + @Override + public TerritorialKavu copy() { + return new TerritorialKavu(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TetheredSkirge.java b/Mage.Sets/src/mage/cards/t/TetheredSkirge.java index 9057fa2800f..015eb2eb10a 100644 --- a/Mage.Sets/src/mage/cards/t/TetheredSkirge.java +++ b/Mage.Sets/src/mage/cards/t/TetheredSkirge.java @@ -19,6 +19,7 @@ public final class TetheredSkirge extends CardImpl { public TetheredSkirge(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.IMP); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/t/ThoughtMonitor.java b/Mage.Sets/src/mage/cards/t/ThoughtMonitor.java new file mode 100644 index 00000000000..604ea385805 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThoughtMonitor.java @@ -0,0 +1,45 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.AffinityForArtifactsAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThoughtMonitor extends CardImpl { + + public ThoughtMonitor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{6}{U}"); + + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Affinity for artifacts + this.addAbility(new AffinityForArtifactsAbility()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Thought Monitor enters the battlefield, draw two cards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(2))); + } + + private ThoughtMonitor(final ThoughtMonitor card) { + super(card); + } + + @Override + public ThoughtMonitor copy() { + return new ThoughtMonitor(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThrabenWatcher.java b/Mage.Sets/src/mage/cards/t/ThrabenWatcher.java new file mode 100644 index 00000000000..ff86877b2b3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThrabenWatcher.java @@ -0,0 +1,63 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TokenPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThrabenWatcher extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creatures"); + + static { + filter.add(Predicates.not(TokenPredicate.instance)); + } + + public ThrabenWatcher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); + + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Other nontoken creatures you control get +1/+1 and have vigilance. + Ability ability = new SimpleStaticAbility(new BoostControlledEffect( + 1, 1, Duration.WhileOnBattlefield, filter, true + )); + ability.addEffect(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, filter, true + ).setText("and have vigilance")); + this.addAbility(ability); + } + + private ThrabenWatcher(final ThrabenWatcher card) { + super(card); + } + + @Override + public ThrabenWatcher copy() { + return new ThrabenWatcher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/Thrummingbird.java b/Mage.Sets/src/mage/cards/t/Thrummingbird.java index d7dc1578dec..e2e55f1c1b7 100644 --- a/Mage.Sets/src/mage/cards/t/Thrummingbird.java +++ b/Mage.Sets/src/mage/cards/t/Thrummingbird.java @@ -18,6 +18,7 @@ public final class Thrummingbird extends CardImpl { public Thrummingbird(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BIRD); this.subtype.add(SubType.HORROR); diff --git a/Mage.Sets/src/mage/cards/t/ThunderingTanadon.java b/Mage.Sets/src/mage/cards/t/ThunderingTanadon.java index 5bfd2a81b05..986bb4e0b7a 100644 --- a/Mage.Sets/src/mage/cards/t/ThunderingTanadon.java +++ b/Mage.Sets/src/mage/cards/t/ThunderingTanadon.java @@ -17,6 +17,7 @@ public final class ThunderingTanadon extends CardImpl { public ThunderingTanadon(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}{G/P}{G/P}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BEAST); this.power = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/t/TideShaper.java b/Mage.Sets/src/mage/cards/t/TideShaper.java new file mode 100644 index 00000000000..2c42a2c3154 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TideShaper.java @@ -0,0 +1,110 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.KickedCondition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.abilities.keyword.KickerAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.target.common.TargetLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TideShaper extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent(SubType.ISLAND, "An opponent controls an Island"); + + static { + filter.add(TargetController.OPPONENT.getControllerPredicate()); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 0, false); + private static final Hint hint = new ConditionHint(condition); + + public TideShaper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Kicker {1} + this.addAbility(new KickerAbility("{1}")); + + // When Tide Shaper enters the battlefield, if it was kicked, target land becomes an Island for as long as Tide Shaper remains on the battlefield. + Ability ability = new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new TideShaperEffect()), + KickedCondition.instance, "When {this} enters the battlefield, if it was kicked, " + + "target land becomes an Island for as long as {this} remains on the battlefield." + ); + ability.addTarget(new TargetLandPermanent()); + this.addAbility(ability); + + // Tide Shaper gets +1/+1 as long as an opponent controls an Island. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), + condition, "{this} gets +1/+1 as long as an opponent controls an Island" + )).addHint(hint)); + } + + private TideShaper(final TideShaper card) { + super(card); + } + + @Override + public TideShaper copy() { + return new TideShaper(this); + } +} + +class TideShaperEffect extends BecomesBasicLandTargetEffect { + + TideShaperEffect() { + super(Duration.Custom, false, true, SubType.ISLAND); + } + + private TideShaperEffect(final TideShaperEffect effect) { + super(effect); + } + + @Override + public TideShaperEffect copy() { + return new TideShaperEffect(this); + } + + @Override + public void init(Ability source, Game game) { + if (source.getSourcePermanentIfItStillExists(game) == null) { + discard(); + return; + } + super.init(source, game); + } + + @Override + public boolean apply(Game game, Ability source) { + if (source.getSourcePermanentIfItStillExists(game) == null) { + discard(); + return false; + } + return super.apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TineShrike.java b/Mage.Sets/src/mage/cards/t/TineShrike.java index ec3b05cdb7b..1340dd4ce0f 100644 --- a/Mage.Sets/src/mage/cards/t/TineShrike.java +++ b/Mage.Sets/src/mage/cards/t/TineShrike.java @@ -19,6 +19,7 @@ public final class TineShrike extends CardImpl { public TineShrike (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.BIRD); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/t/TirelessProvisioner.java b/Mage.Sets/src/mage/cards/t/TirelessProvisioner.java new file mode 100644 index 00000000000..8aefdf25bd5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TirelessProvisioner.java @@ -0,0 +1,75 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LandfallAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.token.FoodToken; +import mage.game.permanent.token.Token; +import mage.game.permanent.token.TreasureToken; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TirelessProvisioner extends CardImpl { + + public TirelessProvisioner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Landfall — Whenever a land enters the battelfield under your control, create a Food token or a Treasure token. + this.addAbility(new LandfallAbility(new TirelessProvisionerEffect())); + } + + private TirelessProvisioner(final TirelessProvisioner card) { + super(card); + } + + @Override + public TirelessProvisioner copy() { + return new TirelessProvisioner(this); + } +} + +class TirelessProvisionerEffect extends OneShotEffect { + + TirelessProvisionerEffect() { + super(Outcome.Benefit); + staticText = "create a Food token or a Treasure token"; + } + + private TirelessProvisionerEffect(final TirelessProvisionerEffect effect) { + super(effect); + } + + @Override + public TirelessProvisionerEffect copy() { + return new TirelessProvisionerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Token token = player.chooseUse( + outcome, "Create a Food token or a Treasure token?", + null, "Food", "Treasure", source, game + ) ? new FoodToken() : new TreasureToken(); + return token.putOntoBattlefield(1, game, source, source.getControllerId()); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TizerusCharger.java b/Mage.Sets/src/mage/cards/t/TizerusCharger.java new file mode 100644 index 00000000000..856ca85927f --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TizerusCharger.java @@ -0,0 +1,97 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.EscapeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityType; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TizerusCharger extends CardImpl { + + public TizerusCharger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.PEGASUS); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Escape—{4}{B}, Exile five other cards from your graveyard. + this.addAbility(new EscapeAbility(this, "{4}{B}", 5)); + + // Tizerus Charger escapes with your choice of a +1/+1 counter or a flying counter on it. + this.addAbility(new EntersBattlefieldAbility( + new TizerusChargerEffect(), null, "{this} escapes " + + "with your choice of a +1/+1 counter or a flying counter on it", "" + )); + } + + private TizerusCharger(final TizerusCharger card) { + super(card); + } + + @Override + public TizerusCharger copy() { + return new TizerusCharger(this); + } +} + +class TizerusChargerEffect extends OneShotEffect { + + TizerusChargerEffect() { + super(Outcome.Benefit); + } + + private TizerusChargerEffect(final TizerusChargerEffect effect) { + super(effect); + } + + @Override + public TizerusChargerEffect copy() { + return new TizerusChargerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null && source.getAbilityType() == AbilityType.STATIC) { + permanent = game.getPermanentEntering(source.getSourceId()); + } + Player player = game.getPlayer(source.getControllerId()); + if (permanent == null || player == null) { + return false; + } + SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); + if (!(spellAbility instanceof EscapeAbility) + || !spellAbility.getSourceId().equals(source.getSourceId()) + || permanent.getZoneChangeCounter(game) != spellAbility.getSourceObjectZoneChangeCounter() + || !spellAbility.getSourceId().equals(source.getSourceId())) { + return false; + } + List appliedEffects = (ArrayList) this.getValue("appliedEffects"); + CounterType counterType = player.chooseUse( + outcome, "Choose +1/+1 or flying", null, + "+1/+1", "Flying", source, game + ) ? CounterType.P1P1 : CounterType.FLYING; + permanent.addCounters(counterType.createInstance(), source.getControllerId(), source, game, appliedEffects); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TormentorExarch.java b/Mage.Sets/src/mage/cards/t/TormentorExarch.java index d4aeec1687a..e005ad9d6d8 100644 --- a/Mage.Sets/src/mage/cards/t/TormentorExarch.java +++ b/Mage.Sets/src/mage/cards/t/TormentorExarch.java @@ -22,6 +22,7 @@ public final class TormentorExarch extends CardImpl { public TormentorExarch(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/t/TourachDreadCantor.java b/Mage.Sets/src/mage/cards/t/TourachDreadCantor.java new file mode 100644 index 00000000000..b35566390ab --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TourachDreadCantor.java @@ -0,0 +1,67 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.DiscardsACardOpponentTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.KickedCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.keyword.KickerAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TourachDreadCantor extends CardImpl { + + public TourachDreadCantor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Kicker {B}{B} + this.addAbility(new KickerAbility("{B}{B}")); + + // Protection from white + this.addAbility(ProtectionAbility.from(ObjectColor.WHITE)); + + // Whenever an opponent discards a card, put a +1/+1 counter on Tourach, Dread Cantor. + this.addAbility(new DiscardsACardOpponentTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false + )); + + // When Tourach enters the battelfield, if it was kicked, target opponent discards two cards at random. + Ability ability = new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(2, true)), + KickedCondition.instance, "When {this} enters the battlefield, if it was kicked, " + + "target opponent discards two cards at random." + ); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private TourachDreadCantor(final TourachDreadCantor card) { + super(card); + } + + @Override + public TourachDreadCantor copy() { + return new TourachDreadCantor(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/ToxicNim.java b/Mage.Sets/src/mage/cards/t/ToxicNim.java index dd5ef530e08..5e24e935af4 100644 --- a/Mage.Sets/src/mage/cards/t/ToxicNim.java +++ b/Mage.Sets/src/mage/cards/t/ToxicNim.java @@ -21,6 +21,7 @@ public final class ToxicNim extends CardImpl { public ToxicNim(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/t/TragicFall.java b/Mage.Sets/src/mage/cards/t/TragicFall.java new file mode 100644 index 00000000000..26063dce5f5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TragicFall.java @@ -0,0 +1,41 @@ +package mage.cards.t; + +import mage.abilities.condition.LockedInCondition; +import mage.abilities.condition.common.MorbidCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +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 TragicFall extends CardImpl { + + public TragicFall(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // Target creature gets -3/-3 until end of turn. + // Hellbent — That creature gets -13/-13 until end of turn instead if you have no cards in hand. + this.getSpellAbility().addEffect(new ConditionalContinuousEffect( + new BoostTargetEffect(-13, -13), new BoostTargetEffect(-3, -3), + new LockedInCondition(MorbidCondition.instance), "Target creature gets -1/-1 " + + "until end of turn.
Hellbent — That creature gets -13/-13 " + + "until end of turn instead if you have no cards in hand" + )); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private TragicFall(final TragicFall card) { + super(card); + } + + @Override + public TragicFall copy() { + return new TragicFall(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TragicSlip.java b/Mage.Sets/src/mage/cards/t/TragicSlip.java index 0146d5aef5f..8916202a87a 100644 --- a/Mage.Sets/src/mage/cards/t/TragicSlip.java +++ b/Mage.Sets/src/mage/cards/t/TragicSlip.java @@ -28,7 +28,7 @@ public final class TragicSlip extends CardImpl { new BoostTargetEffect(-13, -13, Duration.EndOfTurn), new BoostTargetEffect(-1, -1, Duration.EndOfTurn), new LockedInCondition(MorbidCondition.instance), - "Target creature gets -1/-1 until end of turn. Morbid — That creature gets -13/-13 until end of turn instead if a creature died this turn")); + "Target creature gets -1/-1 until end of turn.
Morbid — That creature gets -13/-13 until end of turn instead if a creature died this turn")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/t/TrespassingSouleater.java b/Mage.Sets/src/mage/cards/t/TrespassingSouleater.java index 72cf877b71f..6dc1726a4ad 100644 --- a/Mage.Sets/src/mage/cards/t/TrespassingSouleater.java +++ b/Mage.Sets/src/mage/cards/t/TrespassingSouleater.java @@ -22,6 +22,7 @@ public final class TrespassingSouleater extends CardImpl { public TrespassingSouleater(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/t/TsaboTavoc.java b/Mage.Sets/src/mage/cards/t/TsaboTavoc.java index 205410f5d65..3bd7bfbd3ae 100644 --- a/Mage.Sets/src/mage/cards/t/TsaboTavoc.java +++ b/Mage.Sets/src/mage/cards/t/TsaboTavoc.java @@ -36,6 +36,7 @@ public final class TsaboTavoc extends CardImpl { public TsaboTavoc(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}{R}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(7); diff --git a/Mage.Sets/src/mage/cards/t/TsabosAssassin.java b/Mage.Sets/src/mage/cards/t/TsabosAssassin.java index 9ab680eb9b3..38cf883be9f 100644 --- a/Mage.Sets/src/mage/cards/t/TsabosAssassin.java +++ b/Mage.Sets/src/mage/cards/t/TsabosAssassin.java @@ -31,6 +31,7 @@ public final class TsabosAssassin extends CardImpl { public TsabosAssassin(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.ASSASSIN); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/u/UnboundedPotential.java b/Mage.Sets/src/mage/cards/u/UnboundedPotential.java new file mode 100644 index 00000000000..06bc2a58918 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnboundedPotential.java @@ -0,0 +1,44 @@ +package mage.cards.u; + +import mage.abilities.Mode; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.abilities.keyword.EntwineAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnboundedPotential extends CardImpl { + + public UnboundedPotential(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Choose one — + // • Put a +1/+1 counter on each of up to two target creatures. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + .setText("put a +1/+1 counter on each of up to two target creatures")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); + + // • Proliferate. + this.getSpellAbility().addMode(new Mode(new ProliferateEffect())); + + // Entwine {3}{W} + this.addAbility(new EntwineAbility("{3}{W}")); + } + + private UnboundedPotential(final UnboundedPotential card) { + super(card); + } + + @Override + public UnboundedPotential copy() { + return new UnboundedPotential(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnbreakableBond.java b/Mage.Sets/src/mage/cards/u/UnbreakableBond.java index e67158554cc..5c665708341 100644 --- a/Mage.Sets/src/mage/cards/u/UnbreakableBond.java +++ b/Mage.Sets/src/mage/cards/u/UnbreakableBond.java @@ -1,20 +1,11 @@ package mage.cards.u; -import mage.abilities.Ability; -import mage.abilities.effects.ReplacementEffectImpl; -import mage.abilities.effects.common.InfoEffect; -import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldWithCounterTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; import mage.counters.CounterType; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.events.EntersTheBattlefieldEvent; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.target.common.TargetCardInYourGraveyard; import java.util.UUID; @@ -28,9 +19,7 @@ public final class UnbreakableBond extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); // Return target creature card from your graveyard to the battlefield with a lifelink counter on it. - this.getSpellAbility().addEffect(new UnbreakableBondReplacementEffect()); - this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addEffect(new InfoEffect("with a lifelink counter on it")); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(CounterType.LIFELINK.createInstance())); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); } @@ -43,45 +32,3 @@ public final class UnbreakableBond extends CardImpl { return new UnbreakableBond(this); } } - -class UnbreakableBondReplacementEffect extends ReplacementEffectImpl { - - UnbreakableBondReplacementEffect() { - super(Duration.EndOfStep, Outcome.BoostCreature); - } - - private UnbreakableBondReplacementEffect(UnbreakableBondReplacementEffect effect) { - super(effect); - } - - @Override - public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - return event.getTargetId().equals(getTargetPointer().getFirst(game, source)); - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); - if (creature == null) { - return false; - } - creature.addCounters(CounterType.LIFELINK.createInstance(), source.getControllerId(), source, game, event.getAppliedEffects()); - discard(); - return false; - } - - @Override - public UnbreakableBondReplacementEffect copy() { - return new UnbreakableBondReplacementEffect(this); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/u/UnholyHeat.java b/Mage.Sets/src/mage/cards/u/UnholyHeat.java new file mode 100644 index 00000000000..ae3f1920fd6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnholyHeat.java @@ -0,0 +1,42 @@ +package mage.cards.u; + +import mage.abilities.condition.common.DeliriumCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.hint.common.CardTypesInGraveyardHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnholyHeat extends CardImpl { + + public UnholyHeat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); + + // Unholy Heat deals 2 damage to target creature or planeswalker. + // Delirium — Unholy Heat deals 6 damage instead if there are four or more card types among cards in your graveyard. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DamageTargetEffect(6), new DamageTargetEffect(2), + DeliriumCondition.instance, "{this} deals 2 damage to target creature " + + "or planeswalker.
Delirium — {this} deals 6 damage instead " + + "if there are four or more card types among cards in your graveyard." + )); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + this.getSpellAbility().addHint(CardTypesInGraveyardHint.YOU); + } + + private UnholyHeat(final UnholyHeat card) { + super(card); + } + + @Override + public UnholyHeat copy() { + return new UnholyHeat(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnworthyDead.java b/Mage.Sets/src/mage/cards/u/UnworthyDead.java index 10f52cf38eb..a6acfbdc4b8 100644 --- a/Mage.Sets/src/mage/cards/u/UnworthyDead.java +++ b/Mage.Sets/src/mage/cards/u/UnworthyDead.java @@ -21,6 +21,7 @@ public final class UnworthyDead extends CardImpl { public UnworthyDead(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SKELETON); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/u/UrabraskTheHidden.java b/Mage.Sets/src/mage/cards/u/UrabraskTheHidden.java index 234e1e00208..b70145d94fe 100644 --- a/Mage.Sets/src/mage/cards/u/UrabraskTheHidden.java +++ b/Mage.Sets/src/mage/cards/u/UrabraskTheHidden.java @@ -27,6 +27,7 @@ public final class UrabraskTheHidden extends CardImpl { public UrabraskTheHidden(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}{R}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.PRAETOR); this.power = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/u/UrborgTombOfYawgmoth.java b/Mage.Sets/src/mage/cards/u/UrborgTombOfYawgmoth.java index 61e5f9558d2..87e57628444 100644 --- a/Mage.Sets/src/mage/cards/u/UrborgTombOfYawgmoth.java +++ b/Mage.Sets/src/mage/cards/u/UrborgTombOfYawgmoth.java @@ -1,32 +1,14 @@ package mage.cards.u; -import java.util.List; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.Effect; -import mage.abilities.mana.BlackManaAbility; +import mage.abilities.effects.common.continuous.AddBasicLandTypeAllLandsEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.DependencyType; -import mage.constants.Duration; -import mage.constants.Layer; -import static mage.constants.Layer.TypeChangingEffects_4; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.filter.common.FilterLandPermanent; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.constants.*; + +import java.util.UUID; /** - * * @author Plopman */ public final class UrborgTombOfYawgmoth extends CardImpl { @@ -36,9 +18,7 @@ public final class UrborgTombOfYawgmoth extends CardImpl { addSuperType(SuperType.LEGENDARY); // Each land is a Swamp in addition to its other land types. - Ability ability = new SimpleStaticAbility(new UrborgTombOfYawgmothEffect()); - this.addAbility(ability); - + this.addAbility(new SimpleStaticAbility(new AddBasicLandTypeAllLandsEffect(SubType.SWAMP))); } private UrborgTombOfYawgmoth(final UrborgTombOfYawgmoth card) { @@ -49,62 +29,4 @@ public final class UrborgTombOfYawgmoth extends CardImpl { public UrborgTombOfYawgmoth copy() { return new UrborgTombOfYawgmoth(this); } - - class UrborgTombOfYawgmothEffect extends ContinuousEffectImpl { - - UrborgTombOfYawgmothEffect() { - super(Duration.WhileOnBattlefield, Outcome.AIDontUseIt); - this.staticText = "Each land is a Swamp in addition to its other land types"; - this.dependencyTypes.add(DependencyType.BecomeSwamp); - } - - UrborgTombOfYawgmothEffect(final UrborgTombOfYawgmothEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public UrborgTombOfYawgmothEffect copy() { - return new UrborgTombOfYawgmothEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - for (Permanent land : game.getBattlefield().getActivePermanents(new FilterLandPermanent(), source.getControllerId(), game)) { - switch (layer) { - 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 - // Lands have their mana ability intrinsically, so that is added in layer 4 - if (!land.hasSubtype(SubType.SWAMP, game)) { - land.addSubType(game, SubType.SWAMP); - } - if (!land.getAbilities().containsRule(new BlackManaAbility())) { - land.addAbility(new BlackManaAbility(), source.getSourceId(), game); - } - break; - } - } - return true; - } - - @Override - public boolean hasLayer(Layer layer) { - return 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 -> mage.cards.b.BloodMoon.class.equals(effect.getClass().getEnclosingClass())) - .map(Effect::getId) - .collect(Collectors.toSet()); // Blood Moon affects non-basic land like Urborg - - } - } } diff --git a/Mage.Sets/src/mage/cards/u/UrzasSaga.java b/Mage.Sets/src/mage/cards/u/UrzasSaga.java index 983c62a1aa7..473d00d0727 100644 --- a/Mage.Sets/src/mage/cards/u/UrzasSaga.java +++ b/Mage.Sets/src/mage/cards/u/UrzasSaga.java @@ -93,6 +93,6 @@ enum UrzasSagaPredicate implements Predicate { @Override public boolean apply(Card input, Game game) { - return costs.contains(input.getManaCostSymbols().stream().reduce(String::join)); + return costs.contains(String.join("", input.getManaCostSymbols())); } } diff --git a/Mage.Sets/src/mage/cards/v/VaultSkirge.java b/Mage.Sets/src/mage/cards/v/VaultSkirge.java index 2e3450585d0..73db74576b4 100644 --- a/Mage.Sets/src/mage/cards/v/VaultSkirge.java +++ b/Mage.Sets/src/mage/cards/v/VaultSkirge.java @@ -18,6 +18,7 @@ public final class VaultSkirge extends CardImpl { public VaultSkirge(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{1}{B/P}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.IMP); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/v/Vebulid.java b/Mage.Sets/src/mage/cards/v/Vebulid.java index 59fc0e50a1c..6f36e1fcb4d 100644 --- a/Mage.Sets/src/mage/cards/v/Vebulid.java +++ b/Mage.Sets/src/mage/cards/v/Vebulid.java @@ -26,6 +26,7 @@ public final class Vebulid extends CardImpl { public Vebulid(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(0); this.toughness = new MageInt(0); diff --git a/Mage.Sets/src/mage/cards/v/VectorAsp.java b/Mage.Sets/src/mage/cards/v/VectorAsp.java index 1414f9c011b..4a5804b4e15 100644 --- a/Mage.Sets/src/mage/cards/v/VectorAsp.java +++ b/Mage.Sets/src/mage/cards/v/VectorAsp.java @@ -23,6 +23,7 @@ public final class VectorAsp extends CardImpl { public VectorAsp (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{1}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SNAKE); this.power = new MageInt(1); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/v/VedalkenAnatomist.java b/Mage.Sets/src/mage/cards/v/VedalkenAnatomist.java index ecfb5264bfa..b7f57cb519f 100644 --- a/Mage.Sets/src/mage/cards/v/VedalkenAnatomist.java +++ b/Mage.Sets/src/mage/cards/v/VedalkenAnatomist.java @@ -25,6 +25,7 @@ public final class VedalkenAnatomist extends CardImpl { public VedalkenAnatomist(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.VEDALKEN); this.subtype.add(SubType.WIZARD); diff --git a/Mage.Sets/src/mage/cards/v/VerdantCommand.java b/Mage.Sets/src/mage/cards/v/VerdantCommand.java new file mode 100644 index 00000000000..e31df3f6825 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VerdantCommand.java @@ -0,0 +1,85 @@ +package mage.cards.v; + +import mage.abilities.LoyaltyAbility; +import mage.abilities.Mode; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.CreateTokenTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.GainLifeTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterStackObject; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.SquirrelToken; +import mage.game.stack.StackObject; +import mage.target.TargetPlayer; +import mage.target.TargetStackObject; +import mage.target.common.TargetCardInGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VerdantCommand extends CardImpl { + + private static final FilterStackObject filter = new FilterStackObject("loyalty ability of a planeswalker"); + + static { + filter.add(VerdantCommandPredicate.instance); + } + + public VerdantCommand(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // Choose two — + this.getSpellAbility().getModes().setMinModes(2); + this.getSpellAbility().getModes().setMaxModes(2); + + // • Target player creates two tapped 1/1 green Squirrel creature tokens. + this.getSpellAbility().addEffect(new CreateTokenTargetEffect( + new SquirrelToken(), StaticValue.get(2), true, false + )); + + // • Counter target loyalty ability of a planeswalker. + Mode mode = new Mode(new CounterTargetEffect()); + mode.addTarget(new TargetStackObject(filter)); + this.getSpellAbility().addMode(mode); + + // • Exile target card from a graveyard. + mode = new Mode(new ExileTargetEffect()); + mode.addTarget(new TargetCardInGraveyard()); + this.getSpellAbility().addMode(mode); + + // • Target player gains 3 life. + mode = new Mode(new GainLifeTargetEffect(3)); + mode.addTarget(new TargetPlayer()); + this.getSpellAbility().addMode(mode); + } + + private VerdantCommand(final VerdantCommand card) { + super(card); + } + + @Override + public VerdantCommand copy() { + return new VerdantCommand(this); + } +} + +enum VerdantCommandPredicate implements Predicate { + instance; + + @Override + public boolean apply(StackObject input, Game game) { + if (!(input instanceof LoyaltyAbility)) { + return false; + } + Permanent permanent = ((LoyaltyAbility) input).getSourcePermanentOrLKI(game); + return permanent != null && permanent.isPlaneswalker(); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VerminGorger.java b/Mage.Sets/src/mage/cards/v/VerminGorger.java new file mode 100644 index 00000000000..bd04209696c --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VerminGorger.java @@ -0,0 +1,46 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VerminGorger extends CardImpl { + + public VerminGorger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {T}, Sacrifice another creature: Each opponent loses 2 life and you gain 2 life. + Ability ability = new SimpleActivatedAbility(new LoseLifeOpponentsEffect(2), new TapSourceCost()); + ability.addEffect(new GainLifeEffect(2).concatBy("and")); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); + this.addAbility(ability); + } + + private VerminGorger(final VerminGorger card) { + super(card); + } + + @Override + public VerminGorger copy() { + return new VerminGorger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/ViashinoLashclaw.java b/Mage.Sets/src/mage/cards/v/ViashinoLashclaw.java new file mode 100644 index 00000000000..e4ddb9cacac --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/ViashinoLashclaw.java @@ -0,0 +1,49 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ViashinoLashclaw extends CardImpl { + + public ViashinoLashclaw(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {T}, Discard a card: Creatures you control gain haste until end of turn. + Ability ability = new SimpleActivatedAbility(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES + ), new TapSourceCost()); + ability.addCost(new DiscardCardCost()); + this.addAbility(ability); + } + + private ViashinoLashclaw(final ViashinoLashclaw card) { + super(card); + } + + @Override + public ViashinoLashclaw copy() { + return new ViashinoLashclaw(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VileEntomber.java b/Mage.Sets/src/mage/cards/v/VileEntomber.java new file mode 100644 index 00000000000..144ad9a5c6c --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VileEntomber.java @@ -0,0 +1,42 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.search.SearchLibraryPutInGraveyardEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VileEntomber extends CardImpl { + + public VileEntomber(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WARLOCK); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // When Vile Entomber enters the battlefield, search your library for a card, put that card into your graveyard, then shuffle. + this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInGraveyardEffect())); + } + + private VileEntomber(final VileEntomber card) { + super(card); + } + + @Override + public VileEntomber copy() { + return new VileEntomber(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/ViralDrake.java b/Mage.Sets/src/mage/cards/v/ViralDrake.java index 83223a8aebe..3b20768ad5c 100644 --- a/Mage.Sets/src/mage/cards/v/ViralDrake.java +++ b/Mage.Sets/src/mage/cards/v/ViralDrake.java @@ -21,6 +21,7 @@ public final class ViralDrake extends CardImpl { public ViralDrake(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DRAKE); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/v/ViridianBetrayers.java b/Mage.Sets/src/mage/cards/v/ViridianBetrayers.java index f1305c09d40..4ce8889986c 100644 --- a/Mage.Sets/src/mage/cards/v/ViridianBetrayers.java +++ b/Mage.Sets/src/mage/cards/v/ViridianBetrayers.java @@ -28,6 +28,7 @@ public final class ViridianBetrayers extends CardImpl { public ViridianBetrayers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ELF); this.subtype.add(SubType.WARRIOR); diff --git a/Mage.Sets/src/mage/cards/v/ViridianCorrupter.java b/Mage.Sets/src/mage/cards/v/ViridianCorrupter.java index 9e70cb46ecc..1a73219ba97 100644 --- a/Mage.Sets/src/mage/cards/v/ViridianCorrupter.java +++ b/Mage.Sets/src/mage/cards/v/ViridianCorrupter.java @@ -21,6 +21,7 @@ public final class ViridianCorrupter extends CardImpl { public ViridianCorrupter (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SHAMAN); diff --git a/Mage.Sets/src/mage/cards/v/ViridianEmissary.java b/Mage.Sets/src/mage/cards/v/ViridianEmissary.java index bf4bae5caa7..43ae5d4e0cd 100644 --- a/Mage.Sets/src/mage/cards/v/ViridianEmissary.java +++ b/Mage.Sets/src/mage/cards/v/ViridianEmissary.java @@ -21,6 +21,7 @@ public final class ViridianEmissary extends CardImpl { public ViridianEmissary(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SCOUT); diff --git a/Mage.Sets/src/mage/cards/v/Viseling.java b/Mage.Sets/src/mage/cards/v/Viseling.java index 0851a03baf8..b48d058b83b 100644 --- a/Mage.Sets/src/mage/cards/v/Viseling.java +++ b/Mage.Sets/src/mage/cards/v/Viseling.java @@ -22,6 +22,7 @@ public final class Viseling extends CardImpl { public Viseling(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(2); diff --git a/Mage.Sets/src/mage/cards/v/VitalSplicer.java b/Mage.Sets/src/mage/cards/v/VitalSplicer.java index 57be559a9e5..8bf587ebb74 100644 --- a/Mage.Sets/src/mage/cards/v/VitalSplicer.java +++ b/Mage.Sets/src/mage/cards/v/VitalSplicer.java @@ -14,7 +14,7 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; -import mage.game.permanent.token.GolemToken; +import mage.game.permanent.token.PhyrexianGolemToken; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; @@ -34,6 +34,7 @@ public final class VitalSplicer extends CardImpl { public VitalSplicer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ARTIFICER); @@ -41,7 +42,7 @@ public final class VitalSplicer extends CardImpl { this.toughness = new MageInt(1); // When Vital Splicer enters the battlefield, create a 3/3 colorless Golem artifact creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GolemToken()))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new PhyrexianGolemToken()))); // {1}: Regenerate target Golem you control. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateTargetEffect(), new ManaCostsImpl("{1}")); diff --git a/Mage.Sets/src/mage/cards/v/VolrathTheFallen.java b/Mage.Sets/src/mage/cards/v/VolrathTheFallen.java index 5c02ce8411a..d8e325e3c2a 100644 --- a/Mage.Sets/src/mage/cards/v/VolrathTheFallen.java +++ b/Mage.Sets/src/mage/cards/v/VolrathTheFallen.java @@ -27,6 +27,7 @@ public final class VolrathTheFallen extends CardImpl { public VolrathTheFallen(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}{B}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SHAPESHIFTER); this.power = new MageInt(6); this.toughness = new MageInt(4); diff --git a/Mage.Sets/src/mage/cards/v/VolrathTheShapestealer.java b/Mage.Sets/src/mage/cards/v/VolrathTheShapestealer.java index 1772a12e95a..fb45ecb6cef 100644 --- a/Mage.Sets/src/mage/cards/v/VolrathTheShapestealer.java +++ b/Mage.Sets/src/mage/cards/v/VolrathTheShapestealer.java @@ -42,6 +42,7 @@ public final class VolrathTheShapestealer extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{G}{U}"); this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SHAPESHIFTER); this.power = new MageInt(7); this.toughness = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/v/VolrathsShapeshifter.java b/Mage.Sets/src/mage/cards/v/VolrathsShapeshifter.java index 640cb71e713..aa2c8058abe 100644 --- a/Mage.Sets/src/mage/cards/v/VolrathsShapeshifter.java +++ b/Mage.Sets/src/mage/cards/v/VolrathsShapeshifter.java @@ -23,6 +23,7 @@ public final class VolrathsShapeshifter extends CardImpl { public VolrathsShapeshifter(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SHAPESHIFTER); this.power = new MageInt(0); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/v/VorinclexVoiceOfHunger.java b/Mage.Sets/src/mage/cards/v/VorinclexVoiceOfHunger.java index 594dc6c7235..252dcc66d74 100644 --- a/Mage.Sets/src/mage/cards/v/VorinclexVoiceOfHunger.java +++ b/Mage.Sets/src/mage/cards/v/VorinclexVoiceOfHunger.java @@ -30,6 +30,7 @@ public final class VorinclexVoiceOfHunger extends CardImpl { public VorinclexVoiceOfHunger(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{G}{G}"); addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.PRAETOR); this.power = new MageInt(7); diff --git a/Mage.Sets/src/mage/cards/w/Wavesifter.java b/Mage.Sets/src/mage/cards/w/Wavesifter.java new file mode 100644 index 00000000000..4a05a057d7a --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/Wavesifter.java @@ -0,0 +1,48 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.InvestigateEffect; +import mage.abilities.keyword.EvokeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Wavesifter extends CardImpl { + + public Wavesifter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{U}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Wavesifter enters the battlefield, investigate twice. + Ability ability = new EntersBattlefieldTriggeredAbility(new InvestigateEffect().setText("investigate")); + ability.addEffect(new InvestigateEffect().setText("twice")); + this.addAbility(ability); + + // Evoke {G}{U} + this.addAbility(new EvokeAbility("{G}{U}")); + } + + private Wavesifter(final Wavesifter card) { + super(card); + } + + @Override + public Wavesifter copy() { + return new Wavesifter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WesternPaladin.java b/Mage.Sets/src/mage/cards/w/WesternPaladin.java index 0dee6ec8637..cd00734e1ba 100644 --- a/Mage.Sets/src/mage/cards/w/WesternPaladin.java +++ b/Mage.Sets/src/mage/cards/w/WesternPaladin.java @@ -34,6 +34,7 @@ public final class WesternPaladin extends CardImpl { public WesternPaladin(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.KNIGHT); diff --git a/Mage.Sets/src/mage/cards/w/WhisperingSpecter.java b/Mage.Sets/src/mage/cards/w/WhisperingSpecter.java index b3309a01572..e70cc5d209b 100644 --- a/Mage.Sets/src/mage/cards/w/WhisperingSpecter.java +++ b/Mage.Sets/src/mage/cards/w/WhisperingSpecter.java @@ -26,6 +26,7 @@ public final class WhisperingSpecter extends CardImpl { public WhisperingSpecter(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.SPECTER); this.power = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/w/WillowduskEssenceSeer.java b/Mage.Sets/src/mage/cards/w/WillowduskEssenceSeer.java index c6cc1294e71..837a5ef0e59 100644 --- a/Mage.Sets/src/mage/cards/w/WillowduskEssenceSeer.java +++ b/Mage.Sets/src/mage/cards/w/WillowduskEssenceSeer.java @@ -48,7 +48,7 @@ public final class WillowduskEssenceSeer extends CardImpl { // {1}, {T}: Choose another target creature. Put a number of +1/+1 counters on it equal to the amount of life you gained this turn or the amount of life you lost this turn, whichever is greater. Activate only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(new AddCountersTargetEffect( - CounterType.P1P1.createInstance(), WillowduskEssenceSeerValue.instance + CounterType.P1P1.createInstance(0), WillowduskEssenceSeerValue.instance ).setText("choose another target creature. Put a number of +1/+1 counters on it " + "equal to the amount of life you gained this turn or the amount of " + "life you lost this turn, whichever is greater"), new GenericManaCost(1)); diff --git a/Mage.Sets/src/mage/cards/w/WingSplicer.java b/Mage.Sets/src/mage/cards/w/WingSplicer.java index 5cb56fe321f..9fb84b1a88c 100644 --- a/Mage.Sets/src/mage/cards/w/WingSplicer.java +++ b/Mage.Sets/src/mage/cards/w/WingSplicer.java @@ -13,7 +13,7 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.game.permanent.token.GolemToken; +import mage.game.permanent.token.PhyrexianGolemToken; import java.util.UUID; @@ -31,6 +31,7 @@ public final class WingSplicer extends CardImpl { public WingSplicer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ARTIFICER); @@ -38,7 +39,7 @@ public final class WingSplicer extends CardImpl { this.toughness = new MageInt(1); // When Wing Splicer enters the battlefield, create a 3/3 colorless Golem artifact creature token. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GolemToken()))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new PhyrexianGolemToken()))); // Golem creatures you control have flying. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield, filter))); diff --git a/Mage.Sets/src/mage/cards/w/WrensRunHydra.java b/Mage.Sets/src/mage/cards/w/WrensRunHydra.java new file mode 100644 index 00000000000..2f915f4644c --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WrensRunHydra.java @@ -0,0 +1,48 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.ReinforceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WrensRunHydra extends CardImpl { + + public WrensRunHydra(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{G}"); + + this.subtype.add(SubType.HYDRA); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Wren's Run Hydra enters the battlefield with X +1/+1 counters on it. + this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.P1P1.createInstance()))); + + // Reinforce X—{X}{G}{G} + this.addAbility(new ReinforceAbility(ManacostVariableValue.instance, new ManaCostsImpl<>("{X}{G}{G}"))); + } + + private WrensRunHydra(final WrensRunHydra card) { + super(card); + } + + @Override + public WrensRunHydra copy() { + return new WrensRunHydra(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WurmcoilEngine.java b/Mage.Sets/src/mage/cards/w/WurmcoilEngine.java index 37e0a9b0791..1fb322332da 100644 --- a/Mage.Sets/src/mage/cards/w/WurmcoilEngine.java +++ b/Mage.Sets/src/mage/cards/w/WurmcoilEngine.java @@ -22,6 +22,7 @@ public final class WurmcoilEngine extends CardImpl { public WurmcoilEngine(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{6}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.WURM); this.power = new MageInt(6); this.toughness = new MageInt(6); @@ -32,7 +33,7 @@ public final class WurmcoilEngine extends CardImpl { // When Wurmcoil Engine dies, create a 3/3 colorless Wurm artifact creature token with deathtouch and a 3/3 colorless Wurm artifact creature token with lifelink. Ability ability = new DiesSourceTriggeredAbility(new CreateTokenEffect(new WurmWithDeathtouchToken()), false); - ability.addEffect(new CreateTokenEffect(new WurmWithLifelinkToken()).setText("and a 3/3 colorless Wurm artifact creature token with lifelink")); + ability.addEffect(new CreateTokenEffect(new WurmWithLifelinkToken()).setText("and a 3/3 colorless Phyrexian Wurm artifact creature token with lifelink")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/x/XantchaSleeperAgent.java b/Mage.Sets/src/mage/cards/x/XantchaSleeperAgent.java index 41800ad8537..00f1b6d472d 100644 --- a/Mage.Sets/src/mage/cards/x/XantchaSleeperAgent.java +++ b/Mage.Sets/src/mage/cards/x/XantchaSleeperAgent.java @@ -30,6 +30,7 @@ public final class XantchaSleeperAgent extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}"); this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.MINION); this.power = new MageInt(5); this.toughness = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/y/YavimayaCradleOfGrowth.java b/Mage.Sets/src/mage/cards/y/YavimayaCradleOfGrowth.java new file mode 100644 index 00000000000..19966050032 --- /dev/null +++ b/Mage.Sets/src/mage/cards/y/YavimayaCradleOfGrowth.java @@ -0,0 +1,35 @@ +package mage.cards.y; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.AddBasicLandTypeAllLandsEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class YavimayaCradleOfGrowth extends CardImpl { + + public YavimayaCradleOfGrowth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + this.addSuperType(SuperType.LEGENDARY); + + // Each land is a Forest in addition to its other land types. + this.addAbility(new SimpleStaticAbility(new AddBasicLandTypeAllLandsEffect(SubType.FOREST))); + } + + private YavimayaCradleOfGrowth(final YavimayaCradleOfGrowth card) { + super(card); + } + + @Override + public YavimayaCradleOfGrowth copy() { + return new YavimayaCradleOfGrowth(this); + } +} diff --git a/Mage.Sets/src/mage/cards/y/YawgmothDemon.java b/Mage.Sets/src/mage/cards/y/YawgmothDemon.java index 5b62a083daa..dbc0c266458 100644 --- a/Mage.Sets/src/mage/cards/y/YawgmothDemon.java +++ b/Mage.Sets/src/mage/cards/y/YawgmothDemon.java @@ -24,6 +24,7 @@ public final class YawgmothDemon extends CardImpl { public YawgmothDemon(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.DEMON); this.power = new MageInt(6); this.toughness = new MageInt(6); diff --git a/Mage.Sets/src/mage/cards/y/YoungNecromancer.java b/Mage.Sets/src/mage/cards/y/YoungNecromancer.java new file mode 100644 index 00000000000..e630791c55a --- /dev/null +++ b/Mage.Sets/src/mage/cards/y/YoungNecromancer.java @@ -0,0 +1,52 @@ +package mage.cards.y; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.ReflexiveTriggeredAbility; +import mage.abilities.costs.common.ExileFromGraveCost; +import mage.abilities.effects.common.DoWhenCostPaid; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class YoungNecromancer extends CardImpl { + + public YoungNecromancer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARLOCK); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // When Young Necromancer enters the battlefield, you may exile two cards from your graveyard. When you do, return target creature card from your graveyard to the battlefield. + ReflexiveTriggeredAbility ability = new ReflexiveTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect(), false, + "return target creature card from your graveyard to the battlefield" + ); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DoWhenCostPaid(ability, new ExileFromGraveCost( + new TargetCardInYourGraveyard(2, StaticFilters.FILTER_CARD) + ), "Exile two cards from your graveyard?") + )); + } + + private YoungNecromancer(final YoungNecromancer card) { + super(card); + } + + @Override + public YoungNecromancer copy() { + return new YoungNecromancer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZabazTheGlimmerwasp.java b/Mage.Sets/src/mage/cards/z/ZabazTheGlimmerwasp.java new file mode 100644 index 00000000000..90caaec27d0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZabazTheGlimmerwasp.java @@ -0,0 +1,116 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.ModularAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZabazTheGlimmerwasp extends CardImpl { + + public ZabazTheGlimmerwasp(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{1}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.INSECT); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Modular 1 + this.addAbility(new ModularAbility(this, 1)); + + // If a modular triggered ability would put one or more +1/+1 counters on a creature you control, that many plus one +1/+1 counters are put on it instead. + this.addAbility(new SimpleStaticAbility(new ZabazTheGlimmerwaspEffect())); + + // {R}: Destroy target artifact you control. + Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl<>("{R}")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT)); + this.addAbility(ability); + + // {W}: Zabaz, the Glimmerwasp gains flying until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl<>("{W}"))); + } + + private ZabazTheGlimmerwasp(final ZabazTheGlimmerwasp card) { + super(card); + } + + @Override + public ZabazTheGlimmerwasp copy() { + return new ZabazTheGlimmerwasp(this); + } +} + +class ZabazTheGlimmerwaspEffect extends ReplacementEffectImpl { + + ZabazTheGlimmerwaspEffect() { + super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false); + staticText = "if a modular triggered ability would put one or more +1/+1 counters on a creature you control, " + + "that many plus one +1/+1 counters are put on it instead"; + } + + ZabazTheGlimmerwaspEffect(final ZabazTheGlimmerwaspEffect effect) { + super(effect); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmountForCounters(event.getAmount() + 1, true); + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ADD_COUNTERS; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!event.getData().equals(CounterType.P1P1.getName()) || event.getAmount() < 1) { + return false; + } + StackObject stackAbility = game.getStack().getStackObject(event.getSourceId()); + if (stackAbility == null || !(stackAbility.getStackAbility() instanceof ModularAbility)) { + return false; + } + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + } + return permanent != null + && permanent.isControlledBy(source.getControllerId()) + && permanent.isCreature(); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public ZabazTheGlimmerwaspEffect copy() { + return new ZabazTheGlimmerwaspEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/HistoricAnthology5.java b/Mage.Sets/src/mage/sets/HistoricAnthology5.java new file mode 100644 index 00000000000..756007e9fb8 --- /dev/null +++ b/Mage.Sets/src/mage/sets/HistoricAnthology5.java @@ -0,0 +1,50 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class HistoricAnthology5 extends ExpansionSet { + + private static final HistoricAnthology5 instance = new HistoricAnthology5(); + + public static HistoricAnthology5 getInstance() { + return instance; + } + + private HistoricAnthology5() { + super("Historic Anthology 5", "HA5", ExpansionSet.buildDate(2021, 5, 27), SetType.MAGIC_ARENA); + this.blockName = "Reprint"; + this.hasBoosters = false; + this.hasBasicLands = false; + + cards.add(new SetCardInfo("Ancient Grudge", 12, Rarity.COMMON, mage.cards.a.AncientGrudge.class)); + cards.add(new SetCardInfo("Atarka's Command", 21, Rarity.RARE, mage.cards.a.AtarkasCommand.class)); + cards.add(new SetCardInfo("Court Homunculus", 1, Rarity.COMMON, mage.cards.c.CourtHomunculus.class)); + cards.add(new SetCardInfo("Dragonstorm", 13, Rarity.RARE, mage.cards.d.Dragonstorm.class)); + cards.add(new SetCardInfo("Dromoka's Command", 22, Rarity.RARE, mage.cards.d.DromokasCommand.class)); + cards.add(new SetCardInfo("Elesh Norn, Grand Cenobite", 2, Rarity.MYTHIC, mage.cards.e.EleshNornGrandCenobite.class)); + cards.add(new SetCardInfo("Grisly Salvage", 23, Rarity.COMMON, mage.cards.g.GrislySalvage.class)); + cards.add(new SetCardInfo("Ichor Wellspring", 24, Rarity.COMMON, mage.cards.i.IchorWellspring.class)); + cards.add(new SetCardInfo("Intangible Virtue", 3, Rarity.UNCOMMON, mage.cards.i.IntangibleVirtue.class)); + cards.add(new SetCardInfo("Into the North", 16, Rarity.COMMON, mage.cards.i.IntoTheNorth.class)); + cards.add(new SetCardInfo("Jin-Gitaxias, Core Augur", 5, Rarity.MYTHIC, mage.cards.j.JinGitaxiasCoreAugur.class)); + cards.add(new SetCardInfo("Kolaghan's Command", 20, Rarity.RARE, mage.cards.k.KolaghansCommand.class)); + cards.add(new SetCardInfo("Merfolk Looter", 6, Rarity.COMMON, mage.cards.m.MerfolkLooter.class)); + cards.add(new SetCardInfo("Ojutai's Command", 18, Rarity.RARE, mage.cards.o.OjutaisCommand.class)); + cards.add(new SetCardInfo("Ray of Revelation", 4, Rarity.COMMON, mage.cards.r.RayOfRevelation.class)); + cards.add(new SetCardInfo("Relic of Progenitus", 25, Rarity.COMMON, mage.cards.r.RelicOfProgenitus.class)); + cards.add(new SetCardInfo("Reverse Engineer", 7, Rarity.UNCOMMON, mage.cards.r.ReverseEngineer.class)); + cards.add(new SetCardInfo("Sheoldred, Whispering One", 10, Rarity.MYTHIC, mage.cards.s.SheoldredWhisperingOne.class)); + cards.add(new SetCardInfo("Silumgar's Command", 19, Rarity.RARE, mage.cards.s.SilumgarsCommand.class)); + cards.add(new SetCardInfo("Stifle", 8, Rarity.RARE, mage.cards.s.Stifle.class)); + cards.add(new SetCardInfo("Trash for Treasure", 14, Rarity.UNCOMMON, mage.cards.t.TrashForTreasure.class)); + cards.add(new SetCardInfo("Urabrask the Hidden", 15, Rarity.MYTHIC, mage.cards.u.UrabraskTheHidden.class)); + cards.add(new SetCardInfo("Vault Skirge", 11, Rarity.COMMON, mage.cards.v.VaultSkirge.class)); + cards.add(new SetCardInfo("Vorinclex, Voice of Hunger", 17, Rarity.MYTHIC, mage.cards.v.VorinclexVoiceOfHunger.class)); + cards.add(new SetCardInfo("Whirler Rogue", 9, Rarity.UNCOMMON, mage.cards.w.WhirlerRogue.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons1Timeshifts.java b/Mage.Sets/src/mage/sets/ModernHorizons1Timeshifts.java new file mode 100644 index 00000000000..15dc95108f6 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ModernHorizons1Timeshifts.java @@ -0,0 +1,64 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class ModernHorizons1Timeshifts extends ExpansionSet { + + private static final ModernHorizons1Timeshifts instance = new ModernHorizons1Timeshifts(); + + public static ModernHorizons1Timeshifts getInstance() { + return instance; + } + + private ModernHorizons1Timeshifts() { + super("Modern Horizons 1 Timeshifts", "RMH1", ExpansionSet.buildDate(2021, 6, 11), SetType.SUPPLEMENTAL); + this.hasBasicLands = false; + this.hasBoosters = false; + + cards.add(new SetCardInfo("Archmage's Charm", 7, Rarity.RARE, mage.cards.a.ArchmagesCharm.class)); + cards.add(new SetCardInfo("Ayula, Queen Among Bears", 19, Rarity.RARE, mage.cards.a.AyulaQueenAmongBears.class)); + cards.add(new SetCardInfo("Changeling Outcast", 12, Rarity.UNCOMMON, mage.cards.c.ChangelingOutcast.class)); + cards.add(new SetCardInfo("Deep Forest Hermit", 20, Rarity.RARE, mage.cards.d.DeepForestHermit.class)); + cards.add(new SetCardInfo("Defile", 13, Rarity.UNCOMMON, mage.cards.d.Defile.class)); + cards.add(new SetCardInfo("Ephemerate", 1, Rarity.UNCOMMON, mage.cards.e.Ephemerate.class)); + cards.add(new SetCardInfo("Etchings of the Chosen", 25, Rarity.UNCOMMON, mage.cards.e.EtchingsOfTheChosen.class)); + cards.add(new SetCardInfo("Faerie Seer", 8, Rarity.UNCOMMON, mage.cards.f.FaerieSeer.class)); + cards.add(new SetCardInfo("Force of Negation", 9, Rarity.RARE, mage.cards.f.ForceOfNegation.class)); + cards.add(new SetCardInfo("Force of Vigor", 21, Rarity.RARE, mage.cards.f.ForceOfVigor.class)); + cards.add(new SetCardInfo("Generous Gift", 2, Rarity.UNCOMMON, mage.cards.g.GenerousGift.class)); + cards.add(new SetCardInfo("Giver of Runes", 3, Rarity.RARE, mage.cards.g.GiverOfRunes.class)); + cards.add(new SetCardInfo("Goblin Engineer", 16, Rarity.RARE, mage.cards.g.GoblinEngineer.class)); + cards.add(new SetCardInfo("Hall of Heliod's Generosity", 39, Rarity.RARE, mage.cards.h.HallOfHeliodsGenerosity.class)); + cards.add(new SetCardInfo("Ice-Fang Coatl", 27, Rarity.RARE, mage.cards.i.IceFangCoatl.class)); + cards.add(new SetCardInfo("Ingenious Infiltrator", 28, Rarity.UNCOMMON, mage.cards.i.IngeniousInfiltrator.class)); + cards.add(new SetCardInfo("King of the Pride", 4, Rarity.UNCOMMON, mage.cards.k.KingOfThePride.class)); + cards.add(new SetCardInfo("Lavabelly Sliver", 29, Rarity.UNCOMMON, mage.cards.l.LavabellySliver.class)); + cards.add(new SetCardInfo("Llanowar Tribe", 22, Rarity.UNCOMMON, mage.cards.l.LlanowarTribe.class)); + cards.add(new SetCardInfo("Magmatic Sinkhole", 17, Rarity.UNCOMMON, mage.cards.m.MagmaticSinkhole.class)); + cards.add(new SetCardInfo("Plague Engineer", 14, Rarity.RARE, mage.cards.p.PlagueEngineer.class)); + cards.add(new SetCardInfo("Prismatic Vista", 40, Rarity.RARE, mage.cards.p.PrismaticVista.class)); + cards.add(new SetCardInfo("Ranger-Captain of Eos", 5, Rarity.MYTHIC, mage.cards.r.RangerCaptainOfEos.class)); + cards.add(new SetCardInfo("Scale Up", 23, Rarity.UNCOMMON, mage.cards.s.ScaleUp.class)); + cards.add(new SetCardInfo("Shenanigans", 18, Rarity.UNCOMMON, mage.cards.s.Shenanigans.class)); + cards.add(new SetCardInfo("Sisay, Weatherlight Captain", 6, Rarity.RARE, mage.cards.s.SisayWeatherlightCaptain.class)); + cards.add(new SetCardInfo("Soulherder", 30, Rarity.UNCOMMON, mage.cards.s.Soulherder.class)); + cards.add(new SetCardInfo("Sword of Sinew and Steel", 31, Rarity.MYTHIC, mage.cards.s.SwordOfSinewAndSteel.class)); + cards.add(new SetCardInfo("Sword of Truth and Justice", 32, Rarity.MYTHIC, mage.cards.s.SwordOfTruthAndJustice.class)); + cards.add(new SetCardInfo("Talisman of Conviction", 33, Rarity.UNCOMMON, mage.cards.t.TalismanOfConviction.class)); + cards.add(new SetCardInfo("Talisman of Creativity", 34, Rarity.UNCOMMON, mage.cards.t.TalismanOfCreativity.class)); + cards.add(new SetCardInfo("Talisman of Curiosity", 35, Rarity.UNCOMMON, mage.cards.t.TalismanOfCuriosity.class)); + cards.add(new SetCardInfo("Talisman of Hierarchy", 36, Rarity.UNCOMMON, mage.cards.t.TalismanOfHierarchy.class)); + cards.add(new SetCardInfo("Talisman of Resilience", 37, Rarity.UNCOMMON, mage.cards.t.TalismanOfResilience.class)); + cards.add(new SetCardInfo("The First Sliver", 26, Rarity.MYTHIC, mage.cards.t.TheFirstSliver.class)); + cards.add(new SetCardInfo("Tribute Mage", 10, Rarity.UNCOMMON, mage.cards.t.TributeMage.class)); + cards.add(new SetCardInfo("Undead Augur", 15, Rarity.UNCOMMON, mage.cards.u.UndeadAugur.class)); + cards.add(new SetCardInfo("Universal Automaton", 38, Rarity.UNCOMMON, mage.cards.u.UniversalAutomaton.class)); + cards.add(new SetCardInfo("Urza, Lord High Artificer", 11, Rarity.MYTHIC, mage.cards.u.UrzaLordHighArtificer.class)); + cards.add(new SetCardInfo("Weather the Storm", 24, Rarity.UNCOMMON, mage.cards.w.WeatherTheStorm.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons2.java b/Mage.Sets/src/mage/sets/ModernHorizons2.java index d41030f1755..d1d1918ea1b 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons2.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons2.java @@ -30,125 +30,284 @@ public final class ModernHorizons2 extends ExpansionSet { cards.add(new SetCardInfo("Abiding Grace", 1, Rarity.UNCOMMON, mage.cards.a.AbidingGrace.class)); cards.add(new SetCardInfo("Abundant Harvest", 147, Rarity.COMMON, mage.cards.a.AbundantHarvest.class)); cards.add(new SetCardInfo("Altar of the Goyf", 220, Rarity.UNCOMMON, mage.cards.a.AltarOfTheGoyf.class)); + cards.add(new SetCardInfo("Academy Manufactor", 219, Rarity.RARE, mage.cards.a.AcademyManufactor.class)); cards.add(new SetCardInfo("Aeromoeba", 37, Rarity.COMMON, mage.cards.a.Aeromoeba.class)); + cards.add(new SetCardInfo("Aeve, Progenitor Ooze", 148, Rarity.RARE, mage.cards.a.AeveProgenitorOoze.class)); + cards.add(new SetCardInfo("Angelic Curator", 262, Rarity.UNCOMMON, mage.cards.a.AngelicCurator.class)); + cards.add(new SetCardInfo("Arcbound Javelineer", 2, Rarity.UNCOMMON, mage.cards.a.ArcboundJavelineer.class)); cards.add(new SetCardInfo("Arcbound Mouser", 3, Rarity.COMMON, mage.cards.a.ArcboundMouser.class)); + cards.add(new SetCardInfo("Arcbound Prototype", 4, Rarity.COMMON, mage.cards.a.ArcboundPrototype.class)); cards.add(new SetCardInfo("Arcbound Shikari", 184, Rarity.UNCOMMON, mage.cards.a.ArcboundShikari.class)); + cards.add(new SetCardInfo("Arcbound Slasher", 111, Rarity.COMMON, mage.cards.a.ArcboundSlasher.class)); + cards.add(new SetCardInfo("Arcbound Tracker", 112, Rarity.COMMON, mage.cards.a.ArcboundTracker.class)); cards.add(new SetCardInfo("Arcbound Whelp", 113, Rarity.UNCOMMON, mage.cards.a.ArcboundWhelp.class)); cards.add(new SetCardInfo("Archfiend of Sorrows", 74, Rarity.UNCOMMON, mage.cards.a.ArchfiendOfSorrows.class)); + cards.add(new SetCardInfo("Archon of Cruelty", 75, Rarity.MYTHIC, mage.cards.a.ArchonOfCruelty.class)); + cards.add(new SetCardInfo("Arcus Acolyte", 185, Rarity.UNCOMMON, mage.cards.a.ArcusAcolyte.class)); cards.add(new SetCardInfo("Arid Mesa", 244, Rarity.RARE, mage.cards.a.AridMesa.class)); cards.add(new SetCardInfo("Asmoranomardicadaistinaculdacar", 186, Rarity.RARE, mage.cards.a.Asmoranomardicadaistinaculdacar.class)); + cards.add(new SetCardInfo("Bannerhide Krushok", 149, Rarity.COMMON, mage.cards.b.BannerhideKrushok.class)); + cards.add(new SetCardInfo("Barbed Spike", 5, Rarity.UNCOMMON, mage.cards.b.BarbedSpike.class)); + cards.add(new SetCardInfo("Batterbone", 221, Rarity.UNCOMMON, mage.cards.b.Batterbone.class)); cards.add(new SetCardInfo("Battle Plan", 114, Rarity.COMMON, mage.cards.b.BattlePlan.class)); cards.add(new SetCardInfo("Blazing Rootwalla", 115, Rarity.UNCOMMON, mage.cards.b.BlazingRootwalla.class)); + cards.add(new SetCardInfo("Blacksmith's Skill", 6, Rarity.COMMON, mage.cards.b.BlacksmithsSkill.class)); + cards.add(new SetCardInfo("Blessed Respite", 150, Rarity.UNCOMMON, mage.cards.b.BlessedRespite.class)); + cards.add(new SetCardInfo("Bloodbraid Marauder", 116, Rarity.RARE, mage.cards.b.BloodbraidMarauder.class)); + cards.add(new SetCardInfo("Blossoming Calm", 7, Rarity.UNCOMMON, mage.cards.b.BlossomingCalm.class)); cards.add(new SetCardInfo("Bone Shards", 76, Rarity.COMMON, mage.cards.b.BoneShards.class)); cards.add(new SetCardInfo("Bone Shredder", 272, Rarity.UNCOMMON, mage.cards.b.BoneShredder.class)); cards.add(new SetCardInfo("Bottle Golems", 222, Rarity.COMMON, mage.cards.b.BottleGolems.class)); cards.add(new SetCardInfo("Braids, Cabal Minion", 273, Rarity.RARE, mage.cards.b.BraidsCabalMinion.class)); cards.add(new SetCardInfo("Brainstone", 223, Rarity.UNCOMMON, mage.cards.b.Brainstone.class)); cards.add(new SetCardInfo("Break Ties", 8, Rarity.COMMON, mage.cards.b.BreakTies.class)); + cards.add(new SetCardInfo("Break the Ice", 77, Rarity.UNCOMMON, mage.cards.b.BreakTheIce.class)); + cards.add(new SetCardInfo("Breathless Knight", 187, Rarity.COMMON, mage.cards.b.BreathlessKnight.class)); cards.add(new SetCardInfo("Breya's Apprentice", 117, Rarity.RARE, mage.cards.b.BreyasApprentice.class)); + cards.add(new SetCardInfo("Burdened Aerialist", 38, Rarity.COMMON, mage.cards.b.BurdenedAerialist.class)); cards.add(new SetCardInfo("Cabal Coffers", 301, Rarity.MYTHIC, mage.cards.c.CabalCoffers.class)); + cards.add(new SetCardInfo("Cabal Initiate", 78, Rarity.COMMON, mage.cards.c.CabalInitiate.class)); cards.add(new SetCardInfo("Calibrated Blast", 118, Rarity.RARE, mage.cards.c.CalibratedBlast.class)); + cards.add(new SetCardInfo("Captain Ripley Vance", 119, Rarity.UNCOMMON, mage.cards.c.CaptainRipleyVance.class)); + cards.add(new SetCardInfo("Captured by Lagacs", 188, Rarity.COMMON, mage.cards.c.CapturedByLagacs.class)); + cards.add(new SetCardInfo("Chainer, Nightmare Adept", 289, Rarity.RARE, mage.cards.c.ChainerNightmareAdept.class)); cards.add(new SetCardInfo("Chance Encounter", 277, Rarity.RARE, mage.cards.c.ChanceEncounter.class)); + cards.add(new SetCardInfo("Chatterfang, Squirrel General", 151, Rarity.MYTHIC, mage.cards.c.ChatterfangSquirrelGeneral.class)); cards.add(new SetCardInfo("Chatterstorm", 152, Rarity.COMMON, mage.cards.c.Chatterstorm.class)); cards.add(new SetCardInfo("Clattering Augur", 79, Rarity.UNCOMMON, mage.cards.c.ClatteringAugur.class)); + cards.add(new SetCardInfo("Chitterspitter", 153, Rarity.RARE, mage.cards.c.Chitterspitter.class)); + cards.add(new SetCardInfo("Chrome Courier", 190, Rarity.COMMON, mage.cards.c.ChromeCourier.class)); + cards.add(new SetCardInfo("Combine Chrysalis", 191, Rarity.UNCOMMON, mage.cards.c.CombineChrysalis.class)); cards.add(new SetCardInfo("Constable of the Realm", 10, Rarity.UNCOMMON, mage.cards.c.ConstableOfTheRealm.class)); cards.add(new SetCardInfo("Counterspell", 267, Rarity.UNCOMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Crack Open", 154, Rarity.COMMON, mage.cards.c.CrackOpen.class)); + cards.add(new SetCardInfo("Cursed Totem", 295, Rarity.RARE, mage.cards.c.CursedTotem.class)); cards.add(new SetCardInfo("Dakkon, Shadow Slayer", 192, Rarity.MYTHIC, mage.cards.d.DakkonShadowSlayer.class)); cards.add(new SetCardInfo("Damn", 80, Rarity.RARE, mage.cards.d.Damn.class)); cards.add(new SetCardInfo("Darkmoss Bridge", 245, Rarity.COMMON, mage.cards.d.DarkmossBridge.class)); + cards.add(new SetCardInfo("Dauthi Voidwalker", 81, Rarity.RARE, mage.cards.d.DauthiVoidwalker.class)); + cards.add(new SetCardInfo("Deepwood Denizen", 155, Rarity.COMMON, mage.cards.d.DeepwoodDenizen.class)); cards.add(new SetCardInfo("Diamond Lion", 225, Rarity.RARE, mage.cards.d.DiamondLion.class)); + cards.add(new SetCardInfo("Dihada's Ploy", 193, Rarity.COMMON, mage.cards.d.DihadasPloy.class)); cards.add(new SetCardInfo("Discerning Taste", 82, Rarity.COMMON, mage.cards.d.DiscerningTaste.class)); + cards.add(new SetCardInfo("Disciple of the Sun", 11, Rarity.COMMON, mage.cards.d.DiscipleOfTheSun.class)); cards.add(new SetCardInfo("Dragon's Rage Channeler", 121, Rarity.UNCOMMON, mage.cards.d.DragonsRageChanneler.class)); cards.add(new SetCardInfo("Dress Down", 39, Rarity.RARE, mage.cards.d.DressDown.class)); cards.add(new SetCardInfo("Drey Keeper", 194, Rarity.COMMON, mage.cards.d.DreyKeeper.class)); cards.add(new SetCardInfo("Drossforge Bridge", 246, Rarity.COMMON, mage.cards.d.DrossforgeBridge.class)); + cards.add(new SetCardInfo("Duskshell Crawler", 156, Rarity.COMMON, mage.cards.d.DuskshellCrawler.class)); + cards.add(new SetCardInfo("Echoing Return", 83, Rarity.COMMON, mage.cards.e.EchoingReturn.class)); cards.add(new SetCardInfo("Enchantress's Presence", 283, Rarity.RARE, mage.cards.e.EnchantresssPresence.class)); + cards.add(new SetCardInfo("Endurance", 157, Rarity.MYTHIC, mage.cards.e.Endurance.class)); + cards.add(new SetCardInfo("Esper Sentinel", 12, Rarity.RARE, mage.cards.e.EsperSentinel.class)); + cards.add(new SetCardInfo("Etherium Spinner", 40, Rarity.COMMON, mage.cards.e.EtheriumSpinner.class)); + cards.add(new SetCardInfo("Ethersworn Sphinx", 195, Rarity.UNCOMMON, mage.cards.e.EtherswornSphinx.class)); cards.add(new SetCardInfo("Extruder", 296, Rarity.UNCOMMON, mage.cards.e.Extruder.class)); + cards.add(new SetCardInfo("Fae Offering", 158, Rarity.UNCOMMON, mage.cards.f.FaeOffering.class)); + cards.add(new SetCardInfo("Fairgrounds Patrol", 13, Rarity.COMMON, mage.cards.f.FairgroundsPatrol.class)); + cards.add(new SetCardInfo("Faithless Salvaging", 122, Rarity.COMMON, mage.cards.f.FaithlessSalvaging.class)); + cards.add(new SetCardInfo("Fast // Furious", 123, Rarity.UNCOMMON, mage.cards.f.FastFurious.class)); + cards.add(new SetCardInfo("Feast of Sanity", 84, Rarity.UNCOMMON, mage.cards.f.FeastOfSanity.class)); + cards.add(new SetCardInfo("Filigree Attendant", 41, Rarity.UNCOMMON, mage.cards.f.FiligreeAttendant.class)); cards.add(new SetCardInfo("Fire // Ice", 290, Rarity.RARE, mage.cards.f.FireIce.class)); + cards.add(new SetCardInfo("Flame Blitz", 124, Rarity.UNCOMMON, mage.cards.f.FlameBlitz.class)); cards.add(new SetCardInfo("Flame Rift", 278, Rarity.UNCOMMON, mage.cards.f.FlameRift.class)); cards.add(new SetCardInfo("Flametongue Yearling", 125, Rarity.UNCOMMON, mage.cards.f.FlametongueYearling.class)); cards.add(new SetCardInfo("Flay Essence", 85, Rarity.UNCOMMON, mage.cards.f.FlayEssence.class)); + cards.add(new SetCardInfo("Floodhound", 42, Rarity.COMMON, mage.cards.f.Floodhound.class)); + cards.add(new SetCardInfo("Flourishing Strike", 159, Rarity.COMMON, mage.cards.f.FlourishingStrike.class)); + cards.add(new SetCardInfo("Fodder Tosser", 226, Rarity.COMMON, mage.cards.f.FodderTosser.class)); cards.add(new SetCardInfo("Forest", 489, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Foul Watcher", 43, Rarity.COMMON, mage.cards.f.FoulWatcher.class)); + cards.add(new SetCardInfo("Foundation Breaker", 160, Rarity.UNCOMMON, mage.cards.f.FoundationBreaker.class)); + cards.add(new SetCardInfo("Foundry Helix", 196, Rarity.COMMON, mage.cards.f.FoundryHelix.class)); cards.add(new SetCardInfo("Fractured Sanity", 44, Rarity.RARE, mage.cards.f.FracturedSanity.class)); - cards.add(new SetCardInfo("Glorious Enforcer", 14, Rarity.UNCOMMON, mage.cards.g.GloriousEnforcer.class)); + cards.add(new SetCardInfo("Funnel-Web Recluse", 161, Rarity.COMMON, mage.cards.f.FunnelWebRecluse.class)); + cards.add(new SetCardInfo("Fury", 126, Rarity.MYTHIC, mage.cards.f.Fury.class)); cards.add(new SetCardInfo("Gaea's Will", 162, Rarity.RARE, mage.cards.g.GaeasWill.class)); + cards.add(new SetCardInfo("Galvanic Relay", 127, Rarity.COMMON, mage.cards.g.GalvanicRelay.class)); + cards.add(new SetCardInfo("Gargadon", 128, Rarity.COMMON, mage.cards.g.Gargadon.class)); + cards.add(new SetCardInfo("Garth One-Eye", 197, Rarity.MYTHIC, mage.cards.g.GarthOneEye.class)); + cards.add(new SetCardInfo("General Ferrous Rokiric", 198, Rarity.RARE, mage.cards.g.GeneralFerrousRokiric.class)); + cards.add(new SetCardInfo("Geyadrone Dihada", 199, Rarity.MYTHIC, mage.cards.g.GeyadroneDihada.class)); + cards.add(new SetCardInfo("Ghost-Lit Drifter", 45, Rarity.UNCOMMON, mage.cards.g.GhostLitDrifter.class)); + cards.add(new SetCardInfo("Gilt-Blade Prowler", 86, Rarity.COMMON, mage.cards.g.GiltBladeProwler.class)); + cards.add(new SetCardInfo("Glimmer Bairn", 163, Rarity.COMMON, mage.cards.g.GlimmerBairn.class)); + cards.add(new SetCardInfo("Glimpse of Tomorrow", 129, Rarity.RARE, mage.cards.g.GlimpseOfTomorrow.class)); + cards.add(new SetCardInfo("Glinting Creeper", 164, Rarity.UNCOMMON, mage.cards.g.GlintingCreeper.class)); + cards.add(new SetCardInfo("Glorious Enforcer", 14, Rarity.UNCOMMON, mage.cards.g.GloriousEnforcer.class)); + cards.add(new SetCardInfo("Goblin Anarchomancer", 200, Rarity.COMMON, mage.cards.g.GoblinAnarchomancer.class)); cards.add(new SetCardInfo("Goblin Bombardment", 279, Rarity.RARE, mage.cards.g.GoblinBombardment.class)); + cards.add(new SetCardInfo("Goblin Traprunner", 130, Rarity.UNCOMMON, mage.cards.g.GoblinTraprunner.class)); cards.add(new SetCardInfo("Goldmire Bridge", 247, Rarity.COMMON, mage.cards.g.GoldmireBridge.class)); cards.add(new SetCardInfo("Gorilla Shaman", 280, Rarity.UNCOMMON, mage.cards.g.GorillaShaman.class)); + cards.add(new SetCardInfo("Gouged Zealot", 131, Rarity.COMMON, mage.cards.g.GougedZealot.class)); + cards.add(new SetCardInfo("Graceful Restoration", 201, Rarity.UNCOMMON, mage.cards.g.GracefulRestoration.class)); cards.add(new SetCardInfo("Greed", 274, Rarity.UNCOMMON, mage.cards.g.Greed.class)); cards.add(new SetCardInfo("Grief", 87, Rarity.MYTHIC, mage.cards.g.Grief.class)); + cards.add(new SetCardInfo("Guardian Kirin", 15, Rarity.COMMON, mage.cards.g.GuardianKirin.class)); + cards.add(new SetCardInfo("Hard Evidence", 46, Rarity.COMMON, mage.cards.h.HardEvidence.class)); + cards.add(new SetCardInfo("Harmonic Prodigy", 132, Rarity.RARE, mage.cards.h.HarmonicProdigy.class)); + cards.add(new SetCardInfo("Healer's Flock", 16, Rarity.UNCOMMON, mage.cards.h.HealersFlock.class)); + cards.add(new SetCardInfo("Hell Mongrel", 88, Rarity.COMMON, mage.cards.h.HellMongrel.class)); cards.add(new SetCardInfo("Herd Baloth", 165, Rarity.UNCOMMON, mage.cards.h.HerdBaloth.class)); + cards.add(new SetCardInfo("Hunting Pack", 284, Rarity.UNCOMMON, mage.cards.h.HuntingPack.class)); cards.add(new SetCardInfo("Ignoble Hierarch", 166, Rarity.RARE, mage.cards.i.IgnobleHierarch.class)); cards.add(new SetCardInfo("Imperial Recruiter", 281, Rarity.MYTHIC, mage.cards.i.ImperialRecruiter.class)); + cards.add(new SetCardInfo("Inevitable Betrayal", 47, Rarity.RARE, mage.cards.i.InevitableBetrayal.class)); cards.add(new SetCardInfo("Island", 483, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jade Avenger", 167, Rarity.COMMON, mage.cards.j.JadeAvenger.class)); + cards.add(new SetCardInfo("Jewel-Eyed Cobra", 168, Rarity.COMMON, mage.cards.j.JewelEyedCobra.class)); cards.add(new SetCardInfo("Junk Winder", 48, Rarity.UNCOMMON, mage.cards.j.JunkWinder.class)); + cards.add(new SetCardInfo("Kaldra Compleat", 227, Rarity.MYTHIC, mage.cards.k.KaldraCompleat.class)); + cards.add(new SetCardInfo("Kaleidoscorch", 133, Rarity.UNCOMMON, mage.cards.k.Kaleidoscorch.class)); cards.add(new SetCardInfo("Karmic Guide", 263, Rarity.RARE, mage.cards.k.KarmicGuide.class)); cards.add(new SetCardInfo("Kitchen Imp", 89, Rarity.COMMON, mage.cards.k.KitchenImp.class)); + cards.add(new SetCardInfo("Knighted Myr", 17, Rarity.COMMON, mage.cards.k.KnightedMyr.class)); cards.add(new SetCardInfo("Landscaper Colos", 18, Rarity.COMMON, mage.cards.l.LandscaperColos.class)); cards.add(new SetCardInfo("Late to Dinner", 19, Rarity.COMMON, mage.cards.l.LateToDinner.class)); + cards.add(new SetCardInfo("Lazotep Chancellor", 203, Rarity.UNCOMMON, mage.cards.l.LazotepChancellor.class)); cards.add(new SetCardInfo("Legion Vanguard", 90, Rarity.UNCOMMON, mage.cards.l.LegionVanguard.class)); + cards.add(new SetCardInfo("Lens Flare", 20, Rarity.COMMON, mage.cards.l.LensFlare.class)); + cards.add(new SetCardInfo("Lightning Spear", 134, Rarity.COMMON, mage.cards.l.LightningSpear.class)); + cards.add(new SetCardInfo("Liquimetal Torque", 228, Rarity.UNCOMMON, mage.cards.l.LiquimetalTorque.class)); + cards.add(new SetCardInfo("Loathsome Curator", 91, Rarity.COMMON, mage.cards.l.LoathsomeCurator.class)); + cards.add(new SetCardInfo("Lonis, Cryptozoologist", 204, Rarity.RARE, mage.cards.l.LonisCryptozoologist.class)); cards.add(new SetCardInfo("Lose Focus", 49, Rarity.COMMON, mage.cards.l.LoseFocus.class)); cards.add(new SetCardInfo("Lucid Dreams", 50, Rarity.UNCOMMON, mage.cards.l.LucidDreams.class)); + cards.add(new SetCardInfo("Magus of the Bridge", 92, Rarity.RARE, mage.cards.m.MagusOfTheBridge.class)); + cards.add(new SetCardInfo("Marble Gargoyle", 21, Rarity.COMMON, mage.cards.m.MarbleGargoyle.class)); cards.add(new SetCardInfo("Marsh Flats", 248, Rarity.RARE, mage.cards.m.MarshFlats.class)); + cards.add(new SetCardInfo("Master of Death", 205, Rarity.RARE, mage.cards.m.MasterOfDeath.class)); cards.add(new SetCardInfo("Mental Journey", 51, Rarity.COMMON, mage.cards.m.MentalJourney.class)); cards.add(new SetCardInfo("Millikin", 297, Rarity.UNCOMMON, mage.cards.m.Millikin.class)); + cards.add(new SetCardInfo("Mine Collapse", 135, Rarity.COMMON, mage.cards.m.MineCollapse.class)); cards.add(new SetCardInfo("Mirari's Wake", 291, Rarity.MYTHIC, mage.cards.m.MirarisWake.class)); cards.add(new SetCardInfo("Mishra's Factory", 302, Rarity.UNCOMMON, mage.cards.m.MishrasFactory.class)); cards.add(new SetCardInfo("Mistvault Bridge", 249, Rarity.COMMON, mage.cards.m.MistvaultBridge.class)); cards.add(new SetCardInfo("Misty Rainforest", 250, Rarity.RARE, mage.cards.m.MistyRainforest.class)); + cards.add(new SetCardInfo("Moderation", 206, Rarity.RARE, mage.cards.m.Moderation.class)); cards.add(new SetCardInfo("Mogg Salvage", 282, Rarity.UNCOMMON, mage.cards.m.MoggSalvage.class)); cards.add(new SetCardInfo("Monoskelion", 229, Rarity.UNCOMMON, mage.cards.m.Monoskelion.class)); + cards.add(new SetCardInfo("Mount Velus Manticore", 136, Rarity.COMMON, mage.cards.m.MountVelusManticore.class)); cards.add(new SetCardInfo("Mountain", 487, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Murktide Regent", 52, Rarity.MYTHIC, mage.cards.m.MurktideRegent.class)); + cards.add(new SetCardInfo("Myr Scrapling", 230, Rarity.COMMON, mage.cards.m.MyrScrapling.class)); cards.add(new SetCardInfo("Mystic Redaction", 53, Rarity.UNCOMMON, mage.cards.m.MysticRedaction.class)); + cards.add(new SetCardInfo("Necrogoyf", 93, Rarity.RARE, mage.cards.n.Necrogoyf.class)); cards.add(new SetCardInfo("Necromancer's Familiar", 94, Rarity.UNCOMMON, mage.cards.n.NecromancersFamiliar.class)); + cards.add(new SetCardInfo("Nested Shambler", 95, Rarity.COMMON, mage.cards.n.NestedShambler.class)); + cards.add(new SetCardInfo("Nettlecyst", 231, Rarity.RARE, mage.cards.n.Nettlecyst.class)); cards.add(new SetCardInfo("Nevinyrral's Disk", 298, Rarity.RARE, mage.cards.n.NevinyrralsDisk.class)); + cards.add(new SetCardInfo("Nykthos Paragon", 22, Rarity.RARE, mage.cards.n.NykthosParagon.class)); cards.add(new SetCardInfo("Obsidian Charmaw", 137, Rarity.RARE, mage.cards.o.ObsidianCharmaw.class)); cards.add(new SetCardInfo("Orchard Strider", 169, Rarity.COMMON, mage.cards.o.OrchardStrider.class)); + cards.add(new SetCardInfo("Ornithopter of Paradise", 232, Rarity.COMMON, mage.cards.o.OrnithopterOfParadise.class)); + cards.add(new SetCardInfo("Out of Time", 23, Rarity.RARE, mage.cards.o.OutOfTime.class)); + cards.add(new SetCardInfo("Parcel Myr", 54, Rarity.COMMON, mage.cards.p.ParcelMyr.class)); + cards.add(new SetCardInfo("Patchwork Gnomes", 299, Rarity.COMMON, mage.cards.p.PatchworkGnomes.class)); cards.add(new SetCardInfo("Patriarch's Bidding", 275, Rarity.RARE, mage.cards.p.PatriarchsBidding.class)); + cards.add(new SetCardInfo("Persist", 96, Rarity.RARE, mage.cards.p.Persist.class)); cards.add(new SetCardInfo("Phantasmal Dreadmaw", 55, Rarity.COMMON, mage.cards.p.PhantasmalDreadmaw.class)); + cards.add(new SetCardInfo("Piercing Rays", 24, Rarity.COMMON, mage.cards.p.PiercingRays.class)); + cards.add(new SetCardInfo("Piru, the Volatile", 207, Rarity.RARE, mage.cards.p.PiruTheVolatile.class)); cards.add(new SetCardInfo("Plains", 481, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Power Depot", 251, Rarity.UNCOMMON, mage.cards.p.PowerDepot.class)); cards.add(new SetCardInfo("Priest of Fell Rites", 208, Rarity.RARE, mage.cards.p.PriestOfFellRites.class)); cards.add(new SetCardInfo("Prismatic Ending", 25, Rarity.UNCOMMON, mage.cards.p.PrismaticEnding.class)); cards.add(new SetCardInfo("Profane Tutor", 97, Rarity.RARE, mage.cards.p.ProfaneTutor.class)); + cards.add(new SetCardInfo("Prophetic Titan", 209, Rarity.UNCOMMON, mage.cards.p.PropheticTitan.class)); cards.add(new SetCardInfo("Quirion Ranger", 285, Rarity.UNCOMMON, mage.cards.q.QuirionRanger.class)); + cards.add(new SetCardInfo("Radiant Epicure", 98, Rarity.UNCOMMON, mage.cards.r.RadiantEpicure.class)); + cards.add(new SetCardInfo("Ragavan, Nimble Pilferer", 138, Rarity.MYTHIC, mage.cards.r.RagavanNimblePilferer.class)); + cards.add(new SetCardInfo("Rakdos Headliner", 210, Rarity.UNCOMMON, mage.cards.r.RakdosHeadliner.class)); cards.add(new SetCardInfo("Ravenous Squirrel", 211, Rarity.UNCOMMON, mage.cards.r.RavenousSquirrel.class)); + cards.add(new SetCardInfo("Raving Visionary", 56, Rarity.UNCOMMON, mage.cards.r.RavingVisionary.class)); cards.add(new SetCardInfo("Razortide Bridge", 252, Rarity.COMMON, mage.cards.r.RazortideBridge.class)); + cards.add(new SetCardInfo("Recalibrate", 57, Rarity.COMMON, mage.cards.r.Recalibrate.class)); + cards.add(new SetCardInfo("Resurgent Belief", 26, Rarity.RARE, mage.cards.r.ResurgentBelief.class)); + cards.add(new SetCardInfo("Revolutionist", 139, Rarity.COMMON, mage.cards.r.Revolutionist.class)); cards.add(new SetCardInfo("Rift Sower", 170, Rarity.COMMON, mage.cards.r.RiftSower.class)); + cards.add(new SetCardInfo("Riptide Laboratory", 303, Rarity.RARE, mage.cards.r.RiptideLaboratory.class)); + cards.add(new SetCardInfo("Rise and Shine", 58, Rarity.RARE, mage.cards.r.RiseAndShine.class)); cards.add(new SetCardInfo("Rishadan Dockhand", 59, Rarity.RARE, mage.cards.r.RishadanDockhand.class)); + cards.add(new SetCardInfo("Road // Ruin", 212, Rarity.UNCOMMON, mage.cards.r.RoadRuin.class)); cards.add(new SetCardInfo("Rustvale Bridge", 253, Rarity.COMMON, mage.cards.r.RustvaleBridge.class)); + cards.add(new SetCardInfo("Said // Done", 60, Rarity.UNCOMMON, mage.cards.s.SaidDone.class)); + cards.add(new SetCardInfo("Sanctifier en-Vec", 27, Rarity.RARE, mage.cards.s.SanctifierEnVec.class)); + cards.add(new SetCardInfo("Sanctuary Raptor", 233, Rarity.UNCOMMON, mage.cards.s.SanctuaryRaptor.class)); cards.add(new SetCardInfo("Sanctum Prelate", 491, Rarity.MYTHIC, mage.cards.s.SanctumPrelate.class)); + cards.add(new SetCardInfo("Sanctum Weaver", 171, Rarity.RARE, mage.cards.s.SanctumWeaver.class)); cards.add(new SetCardInfo("Scalding Tarn", 254, Rarity.RARE, mage.cards.s.ScaldingTarn.class)); + cards.add(new SetCardInfo("Scion of Draco", 234, Rarity.MYTHIC, mage.cards.s.ScionOfDraco.class)); + cards.add(new SetCardInfo("Scour the Desert", 28, Rarity.UNCOMMON, mage.cards.s.ScourTheDesert.class)); cards.add(new SetCardInfo("Scurry Oak", 172, Rarity.UNCOMMON, mage.cards.s.ScurryOak.class)); cards.add(new SetCardInfo("Scuttletide", 61, Rarity.UNCOMMON, mage.cards.s.Scuttletide.class)); + cards.add(new SetCardInfo("Sea Drake", 268, Rarity.UNCOMMON, mage.cards.s.SeaDrake.class)); cards.add(new SetCardInfo("Seal of Cleansing", 264, Rarity.UNCOMMON, mage.cards.s.SealOfCleansing.class)); cards.add(new SetCardInfo("Seal of Removal", 269, Rarity.UNCOMMON, mage.cards.s.SealOfRemoval.class)); + cards.add(new SetCardInfo("Search the Premises", 29, Rarity.RARE, mage.cards.s.SearchThePremises.class)); + cards.add(new SetCardInfo("Serra's Emissary", 30, Rarity.MYTHIC, mage.cards.s.SerrasEmissary.class)); + cards.add(new SetCardInfo("Shardless Agent", 292, Rarity.RARE, mage.cards.s.ShardlessAgent.class)); + cards.add(new SetCardInfo("Shattered Ego", 62, Rarity.COMMON, mage.cards.s.ShatteredEgo.class)); cards.add(new SetCardInfo("Silverbluff Bridge", 255, Rarity.COMMON, mage.cards.s.SilverbluffBridge.class)); + cards.add(new SetCardInfo("Sinister Starfish", 99, Rarity.COMMON, mage.cards.s.SinisterStarfish.class)); cards.add(new SetCardInfo("Skirge Familiar", 276, Rarity.UNCOMMON, mage.cards.s.SkirgeFamiliar.class)); cards.add(new SetCardInfo("Skophos Reaver", 140, Rarity.COMMON, mage.cards.s.SkophosReaver.class)); + cards.add(new SetCardInfo("Skyblade's Boon", 31, Rarity.UNCOMMON, mage.cards.s.SkybladesBoon.class)); + cards.add(new SetCardInfo("Slag Strider", 141, Rarity.UNCOMMON, mage.cards.s.SlagStrider.class)); cards.add(new SetCardInfo("Slagwoods Bridge", 256, Rarity.COMMON, mage.cards.s.SlagwoodsBridge.class)); + cards.add(new SetCardInfo("Smell Fear", 173, Rarity.COMMON, mage.cards.s.SmellFear.class)); + cards.add(new SetCardInfo("So Shiny", 63, Rarity.COMMON, mage.cards.s.SoShiny.class)); + cards.add(new SetCardInfo("Sojourner's Companion", 235, Rarity.COMMON, mage.cards.s.SojournersCompanion.class)); + cards.add(new SetCardInfo("Sol Talisman", 236, Rarity.RARE, mage.cards.s.SolTalisman.class)); cards.add(new SetCardInfo("Solitary Confinement", 265, Rarity.RARE, mage.cards.s.SolitaryConfinement.class)); cards.add(new SetCardInfo("Solitude", 32, Rarity.MYTHIC, mage.cards.s.Solitude.class)); cards.add(new SetCardInfo("Soul Snare", 266, Rarity.UNCOMMON, mage.cards.s.SoulSnare.class)); + cards.add(new SetCardInfo("Soul of Migration", 33, Rarity.COMMON, mage.cards.s.SoulOfMigration.class)); + cards.add(new SetCardInfo("Specimen Collector", 64, Rarity.UNCOMMON, mage.cards.s.SpecimenCollector.class)); cards.add(new SetCardInfo("Spreading Insurrection", 142, Rarity.UNCOMMON, mage.cards.s.SpreadingInsurrection.class)); cards.add(new SetCardInfo("Squirrel Mob", 286, Rarity.RARE, mage.cards.s.SquirrelMob.class)); cards.add(new SetCardInfo("Squirrel Sanctuary", 174, Rarity.UNCOMMON, mage.cards.s.SquirrelSanctuary.class)); cards.add(new SetCardInfo("Squirrel Sovereign", 175, Rarity.UNCOMMON, mage.cards.s.SquirrelSovereign.class)); + cards.add(new SetCardInfo("Steel Dromedary", 237, Rarity.UNCOMMON, mage.cards.s.SteelDromedary.class)); + cards.add(new SetCardInfo("Steelfin Whale", 65, Rarity.COMMON, mage.cards.s.SteelfinWhale.class)); cards.add(new SetCardInfo("Step Through", 66, Rarity.COMMON, mage.cards.s.StepThrough.class)); cards.add(new SetCardInfo("Sterling Grove", 293, Rarity.RARE, mage.cards.s.SterlingGrove.class)); + cards.add(new SetCardInfo("Storm God's Oracle", 213, Rarity.COMMON, mage.cards.s.StormGodsOracle.class)); + cards.add(new SetCardInfo("Strike It Rich", 143, Rarity.UNCOMMON, mage.cards.s.StrikeItRich.class)); cards.add(new SetCardInfo("Subtlety", 67, Rarity.MYTHIC, mage.cards.s.Subtlety.class)); cards.add(new SetCardInfo("Sudden Edict", 100, Rarity.UNCOMMON, mage.cards.s.SuddenEdict.class)); + cards.add(new SetCardInfo("Suspend", 68, Rarity.RARE, mage.cards.s.Suspend.class)); + cards.add(new SetCardInfo("Svyelun of Sea and Sky", 69, Rarity.MYTHIC, mage.cards.s.SvyelunOfSeaAndSky.class)); cards.add(new SetCardInfo("Swamp", 485, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sweep the Skies", 70, Rarity.UNCOMMON, mage.cards.s.SweepTheSkies.class)); + cards.add(new SetCardInfo("Sword of Hearth and Home", 238, Rarity.MYTHIC, mage.cards.s.SwordOfHearthAndHome.class)); cards.add(new SetCardInfo("Sylvan Anthem", 176, Rarity.RARE, mage.cards.s.SylvanAnthem.class)); + cards.add(new SetCardInfo("Sythis, Harvest's Hand", 214, Rarity.RARE, mage.cards.s.SythisHarvestsHand.class)); cards.add(new SetCardInfo("Tanglepool Bridge", 257, Rarity.COMMON, mage.cards.t.TanglepoolBridge.class)); + cards.add(new SetCardInfo("Tavern Scoundrel", 144, Rarity.COMMON, mage.cards.t.TavernScoundrel.class)); + cards.add(new SetCardInfo("Terminal Agony", 215, Rarity.COMMON, mage.cards.t.TerminalAgony.class)); + cards.add(new SetCardInfo("Terramorph", 177, Rarity.UNCOMMON, mage.cards.t.Terramorph.class)); + cards.add(new SetCardInfo("Territorial Kavu", 216, Rarity.RARE, mage.cards.t.TerritorialKavu.class)); cards.add(new SetCardInfo("The Underworld Cookbook", 240, Rarity.UNCOMMON, mage.cards.t.TheUnderworldCookbook.class)); cards.add(new SetCardInfo("Thornglint Bridge", 258, Rarity.COMMON, mage.cards.t.ThornglintBridge.class)); + cards.add(new SetCardInfo("Thought Monitor", 71, Rarity.RARE, mage.cards.t.ThoughtMonitor.class)); + cards.add(new SetCardInfo("Thraben Watcher", 34, Rarity.UNCOMMON, mage.cards.t.ThrabenWatcher.class)); cards.add(new SetCardInfo("Thrasta, Tempest's Roar", 178, Rarity.MYTHIC, mage.cards.t.ThrastaTempestsRoar.class)); + cards.add(new SetCardInfo("Tide Shaper", 72, Rarity.UNCOMMON, mage.cards.t.TideShaper.class)); cards.add(new SetCardInfo("Timeless Dragon", 35, Rarity.RARE, mage.cards.t.TimelessDragon.class)); cards.add(new SetCardInfo("Timeless Witness", 179, Rarity.UNCOMMON, mage.cards.t.TimelessWitness.class)); + cards.add(new SetCardInfo("Tireless Provisioner", 180, Rarity.UNCOMMON, mage.cards.t.TirelessProvisioner.class)); + cards.add(new SetCardInfo("Titania, Protector of Argoth", 287, Rarity.MYTHIC, mage.cards.t.TitaniaProtectorOfArgoth.class)); + cards.add(new SetCardInfo("Tizerus Charger", 101, Rarity.COMMON, mage.cards.t.TizerusCharger.class)); cards.add(new SetCardInfo("Tormod's Cryptkeeper", 239, Rarity.COMMON, mage.cards.t.TormodsCryptkeeper.class)); cards.add(new SetCardInfo("Tourach's Canticle", 103, Rarity.COMMON, mage.cards.t.TourachsCanticle.class)); + cards.add(new SetCardInfo("Tourach, Dread Cantor", 102, Rarity.MYTHIC, mage.cards.t.TourachDreadCantor.class)); + cards.add(new SetCardInfo("Tragic Fall", 104, Rarity.COMMON, mage.cards.t.TragicFall.class)); + cards.add(new SetCardInfo("Unbounded Potential", 36, Rarity.COMMON, mage.cards.u.UnboundedPotential.class)); cards.add(new SetCardInfo("Underworld Hermit", 105, Rarity.UNCOMMON, mage.cards.u.UnderworldHermit.class)); + cards.add(new SetCardInfo("Unholy Heat", 145, Rarity.COMMON, mage.cards.u.UnholyHeat.class)); cards.add(new SetCardInfo("Unmarked Grave", 106, Rarity.RARE, mage.cards.u.UnmarkedGrave.class)); cards.add(new SetCardInfo("Upheaval", 270, Rarity.RARE, mage.cards.u.Upheaval.class)); cards.add(new SetCardInfo("Urban Daggertooth", 181, Rarity.COMMON, mage.cards.u.UrbanDaggertooth.class)); @@ -156,11 +315,21 @@ public final class ModernHorizons2 extends ExpansionSet { cards.add(new SetCardInfo("Vectis Gloves", 241, Rarity.UNCOMMON, mage.cards.v.VectisGloves.class)); cards.add(new SetCardInfo("Vedalken Infiltrator", 73, Rarity.UNCOMMON, mage.cards.v.VedalkenInfiltrator.class)); cards.add(new SetCardInfo("Verdant Catacombs", 260, Rarity.RARE, mage.cards.v.VerdantCatacombs.class)); + cards.add(new SetCardInfo("Verdant Command", 182, Rarity.RARE, mage.cards.v.VerdantCommand.class)); + cards.add(new SetCardInfo("Vermin Gorger", 107, Rarity.COMMON, mage.cards.v.VerminGorger.class)); + cards.add(new SetCardInfo("Viashino Lashclaw", 146, Rarity.COMMON, mage.cards.v.ViashinoLashclaw.class)); + cards.add(new SetCardInfo("Vile Entomber", 108, Rarity.UNCOMMON, mage.cards.v.VileEntomber.class)); cards.add(new SetCardInfo("Vindicate", 294, Rarity.RARE, mage.cards.v.Vindicate.class)); cards.add(new SetCardInfo("Void Mirror", 242, Rarity.RARE, mage.cards.v.VoidMirror.class)); + cards.add(new SetCardInfo("Wavesifter", 217, Rarity.COMMON, mage.cards.w.Wavesifter.class)); cards.add(new SetCardInfo("Wonder", 271, Rarity.RARE, mage.cards.w.Wonder.class)); cards.add(new SetCardInfo("World-Weary", 109, Rarity.COMMON, mage.cards.w.WorldWeary.class)); + cards.add(new SetCardInfo("Wren's Run Hydra", 183, Rarity.UNCOMMON, mage.cards.w.WrensRunHydra.class)); + cards.add(new SetCardInfo("Yavimaya Elder", 288, Rarity.UNCOMMON, mage.cards.y.YavimayaElder.class)); + cards.add(new SetCardInfo("Yavimaya, Cradle of Growth", 261, Rarity.RARE, mage.cards.y.YavimayaCradleOfGrowth.class)); + cards.add(new SetCardInfo("Young Necromancer", 110, Rarity.UNCOMMON, mage.cards.y.YoungNecromancer.class)); cards.add(new SetCardInfo("Yusri, Fortune's Flame", 218, Rarity.RARE, mage.cards.y.YusriFortunesFlame.class)); + cards.add(new SetCardInfo("Zabaz, the Glimmerwasp", 243, Rarity.RARE, mage.cards.z.ZabazTheGlimmerwasp.class)); cards.add(new SetCardInfo("Zuran Orb", 300, Rarity.UNCOMMON, mage.cards.z.ZuranOrb.class)); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/BatterskullTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/BatterskullTest.java index 8fbac1ca562..b329b52f15b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/BatterskullTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/BatterskullTest.java @@ -37,7 +37,7 @@ public class BatterskullTest extends CardTestPlayerBase { assertHandCount(playerA, 0); assertPermanentCount(playerA, "Batterskull", 1); - assertPermanentCount(playerA, "Germ", 1); - assertPowerToughness(playerA, "Germ", 4, 4); + assertPermanentCount(playerA, "Phyrexian Germ", 1); + assertPowerToughness(playerA, "Phyrexian Germ", 4, 4); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java index dc7b96b5d03..60523a47363 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PersistTest.java @@ -150,7 +150,7 @@ public class PersistTest extends CardTestPlayerBase { assertLife(playerB, 26); // +6 from lifelink of Wurmcoil assertPermanentCount(playerB, "Wurmcoil Engine", 0); - assertPermanentCount(playerB, "Wurm", 2); + assertPermanentCount(playerB, "Phyrexian Wurm", 2); assertPermanentCount(playerA, "Kitchen Finks", 2); assertPowerToughness(playerA, "Kitchen Finks", 2, 1, Filter.ComparisonScope.All); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/SplitSecondTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/SplitSecondTest.java new file mode 100644 index 00000000000..203cc9a6211 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/SplitSecondTest.java @@ -0,0 +1,51 @@ +package org.mage.test.cards.continuous; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class SplitSecondTest extends CardTestPlayerBase { + + @Test + public void testCounterSpell() { + addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 4); + addCard(Zone.HAND, playerA, "Sudden Shock"); + addCard(Zone.HAND, playerA, "Counterspell"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sudden Shock", playerB); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Counterspell", "Sudden Shock"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertHandCount(playerA, "Counterspell", 1); + assertGraveyardCount(playerA, "Sudden Shock", 1); + assertLife(playerB, 20 - 2); + } + + @Test + public void testCopiedSpell() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.HAND, playerA, "Doublecast"); + addCard(Zone.HAND, playerA, "Sudden Shock"); + addCard(Zone.HAND, playerA, "Raging Goblin"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Doublecast"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sudden Shock", playerB); + + // No split second spells are on the stack, effect should not apply anymore + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Raging Goblin"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertLife(playerB, 20 - 2 - 2); + assertPermanentCount(playerA, "Raging Goblin", 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/FlameshadowConjuringTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/FlameshadowConjuringTest.java index c44d26f8f1a..dcf3a6ad47e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/FlameshadowConjuringTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/FlameshadowConjuringTest.java @@ -79,7 +79,7 @@ public class FlameshadowConjuringTest extends CardTestPlayerBase { assertLife(playerB, 14); assertLife(playerA, 26); - assertPermanentCount(playerA, "Wurm", 2); + assertPermanentCount(playerA, "Phyrexian Wurm", 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java index a38051841fa..07afd1a14c7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/PhantasmalImageTest.java @@ -382,7 +382,7 @@ public class PhantasmalImageTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Wurmcoil Engine", 1); assertGraveyardCount(playerB, "Phantasmal Image", 1); - assertPermanentCount(playerB, "Wurm", 2); // if triggered ability did not work, the Titan would be in the graveyard instaed + assertPermanentCount(playerB, "Phyrexian Wurm", 2); // if triggered ability did not work, the Titan would be in the graveyard instaed } @@ -574,8 +574,8 @@ public class PhantasmalImageTest extends CardTestPlayerBase { assertGraveyardCount(playerA, "Phantasmal Image", 1); assertGraveyardCount(playerB, "Wurmcoil Engine", 1); - assertPermanentCount(playerA, "Wurm", 2); - assertPermanentCount(playerB, "Wurm", 2); + assertPermanentCount(playerA, "Phyrexian Wurm", 2); + assertPermanentCount(playerB, "Phyrexian Wurm", 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/AcademyManufactorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/AcademyManufactorTest.java new file mode 100644 index 00000000000..25af4cffbaa --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/AcademyManufactorTest.java @@ -0,0 +1,95 @@ +package org.mage.test.cards.replacement; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class AcademyManufactorTest extends CardTestPlayerBase { + + @Test + public void testAcademyManufactor() { + addCard(Zone.BATTLEFIELD, playerA, "Academy Manufactor"); + addCard(Zone.BATTLEFIELD, playerA, "Plains"); + addCard(Zone.HAND, playerA, "Thraben Inspector"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thraben Inspector"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertPermanentCount(playerA, "Plains", 1); + assertPermanentCount(playerA, "Academy Manufactor", 1); + assertPermanentCount(playerA, "Thraben Inspector", 1); + assertPermanentCount(playerA, "Clue", 1); + assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Treasure", 1); + } + + @Test + public void testMultipleReplacementEffect() { + addCard(Zone.BATTLEFIELD, playerA, "Academy Manufactor", 2); + addCard(Zone.BATTLEFIELD, playerA, "Anointed Procession"); + addCard(Zone.BATTLEFIELD, playerA, "Plains"); + addCard(Zone.HAND, playerA, "Thraben Inspector"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thraben Inspector"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertPermanentCount(playerA, "Plains", 1); + assertPermanentCount(playerA, "Academy Manufactor", 2); + assertPermanentCount(playerA, "Anointed Procession", 1); + assertPermanentCount(playerA, "Thraben Inspector", 1); + assertPermanentCount(playerA, "Clue", 6); + assertPermanentCount(playerA, "Food", 6); + assertPermanentCount(playerA, "Treasure", 6); + } + + @Test + public void testTokenLimit() { + addCard(Zone.BATTLEFIELD, playerA, "Academy Manufactor", 6); + addCard(Zone.BATTLEFIELD, playerA, "Plains"); + addCard(Zone.HAND, playerA, "Thraben Inspector"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thraben Inspector"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertPermanentCount(playerA, "Plains", 1); + assertPermanentCount(playerA, "Academy Manufactor", 6); + assertPermanentCount(playerA, "Thraben Inspector", 1); + + // 8 permanents above + 500 token limit + assertPermanentCount(playerA, 508); + } + + @Test + public void testGingerbruteToken() { + addCard(Zone.BATTLEFIELD, playerA, "Academy Manufactor", 2); + addCard(Zone.BATTLEFIELD, playerA, "Tundra", 5); + addCard(Zone.HAND, playerA, "Fractured Identity"); + + addCard(Zone.BATTLEFIELD, playerB, "Gingerbrute"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fractured Identity", "Gingerbrute"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertPermanentCount(playerA, "Tundra", 5); + assertPermanentCount(playerA, "Academy Manufactor", 2); + // Gingerbrute token copy becomes a regular Food + assertPermanentCount(playerA, "Gingerbrute", 0); + assertPermanentCount(playerB, "Gingerbrute", 0); + assertPermanentCount(playerA, "Clue", 3); + assertPermanentCount(playerA, "Food", 3); + assertPermanentCount(playerA, "Treasure", 3); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ChatterfangSquirrelGeneralTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ChatterfangSquirrelGeneralTest.java new file mode 100644 index 00000000000..f9912ba60eb --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/ChatterfangSquirrelGeneralTest.java @@ -0,0 +1,54 @@ +package org.mage.test.cards.replacement; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class ChatterfangSquirrelGeneralTest extends CardTestPlayerBase { + + private static final String chatterfang = "Chatterfang, Squirrel General"; + + @Test + public void testChatterfang() { + addCard(Zone.BATTLEFIELD, playerA, chatterfang); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.HAND, playerA, "Raise the Alarm"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Raise the Alarm"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertPermanentCount(playerA, "Plains", 2); + assertPermanentCount(playerA, chatterfang, 1); + assertPermanentCount(playerA, "Soldier", 2); + assertPermanentCount(playerA, "Squirrel", 2); + } + + @Test + public void testChatterfangPlusAcademyManufactor() { + addCard(Zone.BATTLEFIELD, playerA, chatterfang); + addCard(Zone.BATTLEFIELD, playerA, "Academy Manufactor"); + addCard(Zone.BATTLEFIELD, playerA, "Plains"); + addCard(Zone.HAND, playerA, "Thraben Inspector"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thraben Inspector"); + // Order Academy Manufactor replacement effect first + setChoice(playerA, "Academy Manufactor"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertPermanentCount(playerA, "Plains", 1); + assertPermanentCount(playerA, chatterfang, 1); + assertPermanentCount(playerA, "Academy Manufactor", 1); + assertPermanentCount(playerA, "Clue", 1); + assertPermanentCount(playerA, "Food", 1); + assertPermanentCount(playerA, "Treasure" ,1); + assertPermanentCount(playerA, "Squirrel", 3); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DamageEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DamageEffectsTest.java index 134f2d15f71..263cf64f91a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DamageEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/DamageEffectsTest.java @@ -42,7 +42,7 @@ public class DamageEffectsTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Ob Nixilis, the Fallen", 1); assertGraveyardCount(playerA, "Wurmcoil Engine", 1); - assertPermanentCount(playerA, "Wurm", 2); + assertPermanentCount(playerA, "Phyrexian Wurm", 2); assertLife(playerB, 20); assertLife(playerA, 29); // -2 from Ob Nixilis + 12 from double damage with lifelink from Wurmcoil Engine diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/SanctifierEnVecTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/SanctifierEnVecTest.java new file mode 100644 index 00000000000..40375e3fa98 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/SanctifierEnVecTest.java @@ -0,0 +1,142 @@ +package org.mage.test.cards.replacement; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class SanctifierEnVecTest extends CardTestPlayerBase { + + private static final String sanctifier = "Sanctifier en-Vec"; + private static final String painter = "Painter's Servant"; + private static final String jace = "Jace, the Mind Sculptor"; + + @Test + public void testEntersBattlefieldAbility() { + addCard(Zone.GRAVEYARD, playerA, "Divination"); + addCard(Zone.GRAVEYARD, playerA, "Lightning Bolt"); + addCard(Zone.GRAVEYARD, playerB, "Fatal Push"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.HAND, playerA, sanctifier); + setStrictChooseMode(true); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, sanctifier); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertPermanentCount(playerA, sanctifier, 1); + assertGraveyardCount(playerA, "Divination", 1); + assertExileCount(playerA, "Lightning Bolt", 1); + assertExileCount(playerB, "Fatal Push", 1); + } + + @Test + public void testReplacementEffect() { + addCard(Zone.HAND, playerA, "Lightning Bolt", 2); + addCard(Zone.HAND, playerA, "Divination"); + addCard(Zone.HAND, playerB, jace); + addCard(Zone.HAND, playerB, "Fatal Push"); + addCard(Zone.HAND, playerB, "One with Nothing"); + addCard(Zone.BATTLEFIELD, playerA, sanctifier); + addCard(Zone.BATTLEFIELD, playerB, "Midnight Reaper"); + addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1); + setStrictChooseMode(true); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Midnight Reaper"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Grizzly Bears"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Divination"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "One with Nothing"); + setStopAt(2, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + // Test that Midnight Reaper did not trigger + assertLife(playerA, 20); + assertLife(playerB, 20); + + assertPermanentCount(playerA, sanctifier, 1); + assertGraveyardCount(playerA, "Divination", 1); + assertGraveyardCount(playerB, "Grizzly Bears", 1); + assertExileCount(playerA, "Lightning Bolt", 2); + assertExileCount(playerB, "Midnight Reaper", 1); + + assertExileCount(playerB, "One with Nothing", 1); + assertGraveyardCount(playerB, jace, 1); + assertExileCount(playerB, "Fatal Push", 1); + } + + @Test + public void testEtbWithPaintersServant() { + addCard(Zone.GRAVEYARD, playerA, "Divination"); + addCard(Zone.GRAVEYARD, playerA, "Lightning Bolt"); + addCard(Zone.GRAVEYARD, playerB, "Fatal Push"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.HAND, playerA, sanctifier); + addCard(Zone.HAND, playerA, painter); + setStrictChooseMode(true); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, painter); + setChoice(playerA, "Black"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, sanctifier); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + assertPermanentCount(playerA, painter, 1); + assertPermanentCount(playerA, sanctifier, 1); + assertExileCount(playerA, "Divination", 1); + assertExileCount(playerA, "Lightning Bolt", 1); + assertExileCount(playerB, "Fatal Push", 1); + } + + @Test + public void testReplacementWithPaintersServant() { + addCard(Zone.HAND, playerA, "Lightning Bolt", 2); + addCard(Zone.HAND, playerA, "Divination"); + addCard(Zone.HAND, playerA, painter); + addCard(Zone.HAND, playerB, jace); + addCard(Zone.HAND, playerB, "Fatal Push"); + addCard(Zone.HAND, playerB, "One with Nothing"); + addCard(Zone.BATTLEFIELD, playerA, sanctifier); + addCard(Zone.BATTLEFIELD, playerB, "Midnight Reaper"); + addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears"); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.BATTLEFIELD, playerA, "Wastes", 2); + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 1); + setStrictChooseMode(true); + + // Tap correctly for painter + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {C}",2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, painter); + setChoice(playerA, "Red"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Midnight Reaper"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Grizzly Bears"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Divination"); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "One with Nothing"); + setStopAt(2, PhaseStep.END_TURN); + execute(); + + assertAllCommandsUsed(); + // Test that Midnight Reaper did not trigger + assertLife(playerA, 20); + assertLife(playerB, 20); + + assertPermanentCount(playerA, painter, 1); + assertPermanentCount(playerA, sanctifier, 1); + assertExileCount(playerB, jace, 1); + assertExileCount(playerA, "Divination", 1); + assertExileCount(playerB, "Grizzly Bears", 1); + assertExileCount(playerA, "Lightning Bolt", 2); + assertExileCount(playerB, "Midnight Reaper", 1); + + assertExileCount(playerB, "One with Nothing", 1); + assertExileCount(playerB, jace, 1); + assertExileCount(playerB, "Fatal Push", 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/cmr/ProfaneTransfusionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/cmr/ProfaneTransfusionTest.java index 74bf1b3060c..756a5258093 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/cmr/ProfaneTransfusionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/cmr/ProfaneTransfusionTest.java @@ -34,8 +34,8 @@ public class ProfaneTransfusionTest extends CardTestPlayerBase { assertLife(playerA, 16); assertLife(playerB, 24); - assertPermanentCount(playerA, "Horror", 1); - assertPowerToughness(playerA, "Horror", 24 - 16, 24 - 16); + assertPermanentCount(playerA, "Phyrexian Horror", 1); + assertPowerToughness(playerA, "Phyrexian Horror", 24 - 16, 24 - 16); assertGraveyardCount(playerA, transfusion, 1); } @@ -60,8 +60,8 @@ public class ProfaneTransfusionTest extends CardTestPlayerBase { assertLife(playerA, 24); assertLife(playerB, 16); - assertPermanentCount(playerA, "Horror", 1); - assertPowerToughness(playerA, "Horror", 24 - 16, 24 - 16); + assertPermanentCount(playerA, "Phyrexian Horror", 1); + assertPowerToughness(playerA, "Phyrexian Horror", 24 - 16, 24 - 16); assertGraveyardCount(playerA, transfusion, 1); } @@ -86,8 +86,8 @@ public class ProfaneTransfusionTest extends CardTestPlayerBase { assertLife(playerA, 16); assertLife(playerB, 32); - assertPermanentCount(playerA, "Horror", 1); - assertPowerToughness(playerA, "Horror", 32 - 16, 32 - 16); + assertPermanentCount(playerA, "Phyrexian Horror", 1); + assertPowerToughness(playerA, "Phyrexian Horror", 32 - 16, 32 - 16); assertGraveyardCount(playerA, transfusion, 1); } @@ -110,8 +110,8 @@ public class ProfaneTransfusionTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 17); - assertPermanentCount(playerA, "Horror", 1); - assertPowerToughness(playerA, "Horror", 20 - 17, 20 - 17); + assertPermanentCount(playerA, "Phyrexian Horror", 1); + assertPowerToughness(playerA, "Phyrexian Horror", 20 - 17, 20 - 17); assertGraveyardCount(playerA, transfusion, 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/GarthOneEyeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/GarthOneEyeTest.java new file mode 100644 index 00000000000..e78adbea829 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/GarthOneEyeTest.java @@ -0,0 +1,151 @@ +package org.mage.test.cards.single.mh2; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class GarthOneEyeTest extends CardTestPlayerBase { + + private static final String garth = "Garth One-Eye"; + private static final String disenchant = "Disenchant"; + private static final String braingeyser = "Braingeyser"; + private static final String terror = "Terror"; + private static final String dragon = "Shivan Dragon"; + private static final String regrowth = "Regrowth"; + private static final String lotus = "Black Lotus"; + private static final String courser = "Nyxborn Courser"; + + @Test + public void testDisenchant() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerA, garth); + addCard(Zone.BATTLEFIELD, playerA, courser); + + setChoice(playerA, disenchant); + setChoice(playerA, "Yes"); + addTarget(playerA, courser); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Choose"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertTapped(garth, true); + assertTapped("Plains", true); + assertPermanentCount(playerA, courser, 0); + assertGraveyardCount(playerA, disenchant, 0); + assertGraveyardCount(playerA, courser, 1); + } + + @Test + public void testBraingeyser() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 5); + addCard(Zone.BATTLEFIELD, playerA, garth); + + setChoice(playerA, braingeyser); + setChoice(playerA, "Yes"); + setChoice(playerA, "X=3"); + addTarget(playerA, playerA); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Choose"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertTapped(garth, true); + assertTapped("Island", true); + assertGraveyardCount(playerA, braingeyser, 0); + assertHandCount(playerA, 3); + } + + @Test + public void testTerror() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Zone.BATTLEFIELD, playerA, garth); + addCard(Zone.BATTLEFIELD, playerA, courser); + + setChoice(playerA, terror); + setChoice(playerA, "Yes"); + addTarget(playerA, courser); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Choose"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertTapped(garth, true); + assertTapped("Swamp", true); + assertPermanentCount(playerA, courser, 0); + assertGraveyardCount(playerA, terror, 0); + assertGraveyardCount(playerA, courser, 1); + } + + @Test + public void testShivanDragon() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6); + addCard(Zone.BATTLEFIELD, playerA, garth); + + setChoice(playerA, dragon); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Choose"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertTapped(garth, true); + assertTapped("Mountain", true); + Permanent permanent = getPermanent(dragon); + Assert.assertNotNull(dragon + " should be on the battlefield", permanent); + Assert.assertTrue(dragon + " should be a token", permanent instanceof PermanentToken); + } + + @Test + public void testRegrowth() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); + addCard(Zone.BATTLEFIELD, playerA, garth); + addCard(Zone.GRAVEYARD, playerA, courser); + + setChoice(playerA, regrowth); + setChoice(playerA, "Yes"); + addTarget(playerA, courser); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Choose"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertTapped(garth, true); + assertTapped("Forest", true); + assertHandCount(playerA, courser, 1); + assertGraveyardCount(playerA, regrowth, 0); + assertGraveyardCount(playerA, courser, 0); + } + + @Test + public void testBlackLotus() { + addCard(Zone.BATTLEFIELD, playerA, garth); + + setChoice(playerA, lotus); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Choose"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertTapped(garth, true); + Permanent permanent = getPermanent(lotus); + Assert.assertNotNull(lotus + " should be on the battlefield", permanent); + Assert.assertTrue(lotus + " should be a token", permanent instanceof PermanentToken); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/ZabazTheGlimmerwaspTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/ZabazTheGlimmerwaspTest.java new file mode 100644 index 00000000000..e9804cf25f0 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/ZabazTheGlimmerwaspTest.java @@ -0,0 +1,57 @@ +package org.mage.test.cards.single.mh2; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author TheElk801 + */ +public class ZabazTheGlimmerwaspTest extends CardTestPlayerBase { + + private static final String zabaz = "Zabaz, the Glimmerwasp"; + private static final String worker = "Arcbound Worker"; + private static final String atog = "Atog"; + + @Test + public void testModularETB() { + addCard(Zone.BATTLEFIELD, playerA, "Island"); + addCard(Zone.BATTLEFIELD, playerA, zabaz); + addCard(Zone.HAND, playerA, worker); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, worker); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPowerToughness(playerA, worker, 1, 1); + assertPowerToughness(playerA, zabaz, 1, 1); + } + + @Test + public void testModularDies() { + addCard(Zone.BATTLEFIELD, playerA, "Island"); + addCard(Zone.BATTLEFIELD, playerA, zabaz); + addCard(Zone.BATTLEFIELD, playerA, atog); + addCard(Zone.HAND, playerA, worker); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, worker); + + setChoice(playerA, worker); + addTarget(playerA, zabaz); + setChoice(playerA, "Yes"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Sacrifice"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, worker, 1); + assertPowerToughness(playerA, zabaz, 1 + 1 + 1, 1 + 1 + 1); + assertPowerToughness(playerA, atog, 1 + 2, 2 + 2); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderReplaceEffectTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderReplaceEffectTest.java index 1461804f897..732936901e6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderReplaceEffectTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/CommanderReplaceEffectTest.java @@ -45,8 +45,8 @@ public class CommanderReplaceEffectTest extends CardTestCommanderDuelBase { assertPermanentCount(playerA, "Daxos of Meletis", 0); assertGraveyardCount(playerA, "Daxos of Meletis", 0); - assertPermanentCount(playerB, "Horror", 1); - assertPowerToughness(playerB, "Horror", 1, 1); + assertPermanentCount(playerB, "Phyrexian Horror", 1); + assertPowerToughness(playerB, "Phyrexian Horror", 1, 1); } @Test @@ -74,8 +74,8 @@ public class CommanderReplaceEffectTest extends CardTestCommanderDuelBase { setStopAt(3, PhaseStep.UPKEEP); execute(); - assertPermanentCount(playerB, "Horror", 1); - assertPowerToughness(playerB, "Horror", 1, 1); + assertPermanentCount(playerB, "Phyrexian Horror", 1); + assertPowerToughness(playerB, "Phyrexian Horror", 1, 1); assertPermanentCount(playerA, "Daxos of Meletis", 1); assertPermanentCount(playerA, "Gift of Immortality", 1); diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index befcac06a88..98ae4703806 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -89,7 +89,6 @@ public class VerifyCardDataTest { skipListCreate(SKIP_LIST_PT); skipListAddName(SKIP_LIST_PT, "UST", "Garbage Elemental"); skipListAddName(SKIP_LIST_PT, "UST", "Infinity Elemental"); - skipListAddName(SKIP_LIST_PT, "MH2", "Archfiend of Sorrows"); // temporary // color skipListCreate(SKIP_LIST_COLOR); @@ -115,8 +114,6 @@ public class VerifyCardDataTest { // subtype skipListCreate(SKIP_LIST_SUBTYPE); skipListAddName(SKIP_LIST_SUBTYPE, "UGL", "Miss Demeanor"); - skipListAddName(SKIP_LIST_SUBTYPE, "MH2", "Squirrel Sovereign"); // temporary - subtypesToIgnore.add("Phyrexian"); // large errata incoming, adding this for now // number skipListCreate(SKIP_LIST_NUMBER); diff --git a/Mage/src/main/java/mage/abilities/common/DealsDamageToACreatureTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsDamageToACreatureTriggeredAbility.java index 5de73a3a578..8f780f2883b 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsDamageToACreatureTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsDamageToACreatureTriggeredAbility.java @@ -81,6 +81,7 @@ public class DealsDamageToACreatureTriggeredAbility extends TriggeredAbilityImpl sb.append("a creature, "); } else { sb.append(filter.getMessage()); + sb.append(", "); } sb.append(super.getRule()); return sb.toString(); diff --git a/Mage/src/main/java/mage/abilities/condition/common/ControllerDiscardedThisTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ControllerDiscardedThisTurnCondition.java new file mode 100644 index 00000000000..fad174e8ad0 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/ControllerDiscardedThisTurnCondition.java @@ -0,0 +1,23 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.game.Game; +import mage.watchers.common.DiscardedCardWatcher; + +/** + * @author TheElk801 + */ +public enum ControllerDiscardedThisTurnCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return DiscardedCardWatcher.checkPlayerDiscarded(source.getControllerId(), game); + } + + @Override + public String toString() { + return "you've discarded a card this turn"; + } +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllGraveyardsCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllGraveyardsCount.java index 72cd99216cb..4976affce1a 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllGraveyardsCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllGraveyardsCount.java @@ -1,23 +1,24 @@ package mage.abilities.dynamicvalue.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author North */ public class CardsInAllGraveyardsCount implements DynamicValue { - private FilterCard filter; + private final FilterCard filter; public CardsInAllGraveyardsCount() { - this(new FilterCard()); + this(StaticFilters.FILTER_CARD); } public CardsInAllGraveyardsCount(FilterCard filter) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileGraveyardAllPlayersEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileGraveyardAllPlayersEffect.java index b3d65f87753..0af1d8339bc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileGraveyardAllPlayersEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileGraveyardAllPlayersEffect.java @@ -64,7 +64,7 @@ public class ExileGraveyardAllPlayersEffect extends OneShotEffect { } Player player = game.getPlayer(playerId); if (player != null) { - toExile.addAll(player.getGraveyard()); + toExile.addAll(player.getGraveyard().getCards(filter, source.getSourceId(), source.getControllerId(), game)); } } controller.moveCards(toExile, Zone.EXILED, source, game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/FlipCoinEffect.java b/Mage/src/main/java/mage/abilities/effects/common/FlipCoinEffect.java index afa980f0390..21036b14f8b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/FlipCoinEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/FlipCoinEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.MageObject; @@ -13,7 +12,6 @@ import mage.game.Game; import mage.players.Player; /** - * * @author LevelX2 */ public class FlipCoinEffect extends OneShotEffect { @@ -21,6 +19,10 @@ public class FlipCoinEffect extends OneShotEffect { protected Effects executingEffectsWon = new Effects(); protected Effects executingEffectsLost = new Effects(); + public FlipCoinEffect() { + this((Effect) null); + } + public FlipCoinEffect(Effect effectWon) { this(effectWon, null); } @@ -58,19 +60,19 @@ public class FlipCoinEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getObject(source.getSourceId()); - if (controller != null && mageObject != null) { - boolean result = true; - for (Effect effect : controller.flipCoin(source, game, true) ? executingEffectsWon : executingEffectsLost) { - effect.setTargetPointer(this.targetPointer); - if (effect instanceof OneShotEffect) { - result &= effect.apply(game, source); - } else { - game.addEffect((ContinuousEffect) effect, source); - } - } - return result; + if (controller == null || mageObject == null) { + return false; } - return false; + boolean result = true; + for (Effect effect : controller.flipCoin(source, game, true) ? executingEffectsWon : executingEffectsLost) { + effect.setTargetPointer(this.targetPointer); + if (effect instanceof OneShotEffect) { + result &= effect.apply(game, source); + } else { + game.addEffect((ContinuousEffect) effect, source); + } + } + return result; } @Override @@ -78,7 +80,10 @@ public class FlipCoinEffect extends OneShotEffect { if (!staticText.isEmpty()) { return staticText; } - StringBuilder sb = new StringBuilder("Flip a coin. If you win the flip, ").append(executingEffectsWon.getText(mode)); + StringBuilder sb = new StringBuilder("flip a coin"); + if (!executingEffectsWon.isEmpty()) { + sb.append(". If you win the flip, ").append(executingEffectsWon.getText(mode)); + } if (!executingEffectsLost.isEmpty()) { sb.append(" If you lose the flip, ").append(executingEffectsLost.getText(mode)); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldWithCounterTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldWithCounterTargetEffect.java new file mode 100644 index 00000000000..05afdc49e84 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldWithCounterTargetEffect.java @@ -0,0 +1,113 @@ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.counters.Counter; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +public class ReturnFromGraveyardToBattlefieldWithCounterTargetEffect extends ReturnFromGraveyardToBattlefieldTargetEffect { + + private final Counter counter; + private final boolean additional; + + public ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(Counter counter) { + this(counter, false); + } + + public ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(Counter counter, boolean additional) { + super(); + this.counter = counter; + this.additional = additional; + } + + private ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(final ReturnFromGraveyardToBattlefieldWithCounterTargetEffect effect) { + super(effect); + this.counter = effect.counter; + this.additional = effect.additional; + } + + @Override + public ReturnFromGraveyardToBattlefieldWithCounterTargetEffect copy() { + return new ReturnFromGraveyardToBattlefieldWithCounterTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + AddCounterReplacementEffect counterEffect = new AddCounterReplacementEffect(counter); + game.addEffect(counterEffect, source); + return super.apply(game, source); + } + + @Override + public String getText(Mode mode) { + StringBuilder sb = new StringBuilder(super.getText(mode)); + sb.append(" with "); + if (additional) { + if (counter.getCount() == 1) { + sb.append("an"); + } else { + sb.append(counter.getCount()); + } + sb.append(" additional"); + } else if (counter.getCount() == 1) { + sb.append("a"); + } else { + sb.append(counter.getCount()); + } + sb.append(' '); + sb.append(counter.getName()); + sb.append(" counter"); + if (counter.getCount() != 1) { + sb.append('s'); + } + sb.append(" on it"); + return sb.toString(); + } +} + +class AddCounterReplacementEffect extends ReplacementEffectImpl { + + private final Counter counter; + + public AddCounterReplacementEffect(Counter counter) { + super(Duration.EndOfStep, Outcome.BoostCreature); + this.counter = counter; + } + + private AddCounterReplacementEffect(final AddCounterReplacementEffect effect) { + super(effect); + this.counter = effect.counter; + } + + @Override + public AddCounterReplacementEffect copy() { + return new AddCounterReplacementEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getTargetId().equals(getTargetPointer().getFirst(game, source)); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + if (creature == null) { + return false; + } + creature.addCounters(counter.copy(), source.getControllerId(), source, game, event.getAppliedEffects()); + discard(); + return false; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java index 423fa44b68c..73c77b3e930 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnToHandAttachedEffect.java @@ -36,7 +36,7 @@ public class ReturnToHandAttachedEffect extends OneShotEffect { return false; } Card card = permanent.getMainCard(); - if (permanent.getZoneChangeCounter(game) != card.getZoneChangeCounter(game) + 1) { + if (permanent.getZoneChangeCounter(game) + 1 != card.getZoneChangeCounter(game)) { return false; } return player.moveCards(card, Zone.HAND, source, game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddBasicLandTypeAllLandsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddBasicLandTypeAllLandsEffect.java new file mode 100644 index 00000000000..fb92836067d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddBasicLandTypeAllLandsEffect.java @@ -0,0 +1,89 @@ +package mage.abilities.effects.common.continuous; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.mana.*; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author Plopman, TheElk801 + */ +public class AddBasicLandTypeAllLandsEffect extends ContinuousEffectImpl { + + private final SubType subType; + + public AddBasicLandTypeAllLandsEffect(SubType subType) { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.AIDontUseIt); + this.subType = subType; + this.staticText = "Each land is " + subType.getIndefiniteArticle() + " " + + subType.getDescription() + " in addition to its other land types"; + switch (subType) { + case PLAINS: + this.dependencyTypes.add(DependencyType.BecomePlains); + break; + case ISLAND: + this.dependencyTypes.add(DependencyType.BecomeIsland); + break; + case SWAMP: + this.dependencyTypes.add(DependencyType.BecomeSwamp); + break; + case MOUNTAIN: + this.dependencyTypes.add(DependencyType.BecomeMountain); + break; + case FOREST: + this.dependencyTypes.add(DependencyType.BecomeForest); + break; + default: + throw new UnsupportedOperationException("Subtype should be a basic land type"); + } + } + + private AddBasicLandTypeAllLandsEffect(final AddBasicLandTypeAllLandsEffect effect) { + super(effect); + this.subType = effect.subType; + } + + @Override + public AddBasicLandTypeAllLandsEffect copy() { + return new AddBasicLandTypeAllLandsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Ability ability; + switch (subType) { + case PLAINS: + ability = new WhiteManaAbility(); + break; + case ISLAND: + ability = new BlueManaAbility(); + break; + case SWAMP: + ability = new BlackManaAbility(); + break; + case MOUNTAIN: + ability = new RedManaAbility(); + break; + case FOREST: + ability = new GreenManaAbility(); + break; + default: + ability = null; + } + for (Permanent land : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_LAND, source.getControllerId(), game + )) { + // 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 + // Lands have their mana ability intrinsically, so that is added in layer 4 + land.addSubType(game, subType); + if (ability != null && !land.getAbilities().containsRule(ability)) { + land.addAbility(ability, source.getSourceId(), game); + } + } + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/replacement/CreateTwiceThatManyTokensEffect.java b/Mage/src/main/java/mage/abilities/effects/common/replacement/CreateTwiceThatManyTokensEffect.java index d9942302275..ef77c25eec4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/replacement/CreateTwiceThatManyTokensEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/replacement/CreateTwiceThatManyTokensEffect.java @@ -5,6 +5,7 @@ import mage.abilities.effects.ReplacementEffectImpl; import mage.constants.Duration; import mage.constants.Outcome; import mage.game.Game; +import mage.game.events.CreateTokenEvent; import mage.game.events.GameEvent; /** @@ -39,7 +40,9 @@ public class CreateTwiceThatManyTokensEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - event.setAmount(event.getAmount() * 2); + if (event instanceof CreateTokenEvent) { + ((CreateTokenEvent) event).doubleTokens(); + } return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInGraveyardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInGraveyardEffect.java new file mode 100644 index 00000000000..090a7366b57 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInGraveyardEffect.java @@ -0,0 +1,44 @@ +package mage.abilities.effects.common.search; + +import mage.abilities.Ability; +import mage.abilities.effects.SearchEffect; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; + +/** + * @author TheElk801 + */ +public class SearchLibraryPutInGraveyardEffect extends SearchEffect { + + public SearchLibraryPutInGraveyardEffect() { + super(new TargetCardInLibrary(StaticFilters.FILTER_CARD), Outcome.Neutral); + staticText = "search your library for a card, put that card into your graveyard, then shuffle"; + } + + public SearchLibraryPutInGraveyardEffect(final SearchLibraryPutInGraveyardEffect effect) { + super(effect); + } + + @Override + public SearchLibraryPutInGraveyardEffect copy() { + return new SearchLibraryPutInGraveyardEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + if (controller.searchLibrary(target, source, game)) { + controller.moveCards(game.getCard(target.getFirstTarget()), Zone.GRAVEYARD, source, game); + } + controller.shuffleLibrary(source, game); + return true; + } + +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/hint/common/ControllerDiscardedHint.java b/Mage/src/main/java/mage/abilities/hint/common/ControllerDiscardedHint.java new file mode 100644 index 00000000000..213fb416184 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/common/ControllerDiscardedHint.java @@ -0,0 +1,28 @@ +package mage.abilities.hint.common; + +import mage.abilities.Ability; +import mage.abilities.condition.common.ControllerDiscardedThisTurnCondition; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.game.Game; + +/** + * @author TheElk801 + */ +public enum ControllerDiscardedHint implements Hint { + instance; + + private static final Hint hint = new ConditionHint( + ControllerDiscardedThisTurnCondition.instance, "You discarded a card this turn" + ); + + @Override + public String getText(Game game, Ability ability) { + return hint.getText(game, ability); + } + + @Override + public ControllerDiscardedHint copy() { + return instance; + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/ArtifactLandcyclingAbility.java b/Mage/src/main/java/mage/abilities/keyword/ArtifactLandcyclingAbility.java new file mode 100644 index 00000000000..2687b3c7a45 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/ArtifactLandcyclingAbility.java @@ -0,0 +1,30 @@ +package mage.abilities.keyword; + +import mage.abilities.costs.Cost; +import mage.constants.CardType; +import mage.filter.common.FilterLandCard; + +/** + * @author TheElk801 + */ +public class ArtifactLandcyclingAbility extends CyclingAbility { + + private static final FilterLandCard filter = new FilterLandCard("artifact land card"); + + static { + filter.add(CardType.ARTIFACT.getPredicate()); + } + + public ArtifactLandcyclingAbility(Cost cost) { + super(cost, filter, "Artifact landcycling"); + } + + private ArtifactLandcyclingAbility(final ArtifactLandcyclingAbility ability) { + super(ability); + } + + @Override + public ArtifactLandcyclingAbility copy() { + return new ArtifactLandcyclingAbility(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/LivingWeaponAbility.java b/Mage/src/main/java/mage/abilities/keyword/LivingWeaponAbility.java index 3ec2ea5bcde..624458a0c84 100644 --- a/Mage/src/main/java/mage/abilities/keyword/LivingWeaponAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/LivingWeaponAbility.java @@ -1,17 +1,13 @@ package mage.abilities.keyword; -import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.CreateTokenEffect; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.abilities.effects.common.CreateTokenAttachSourceEffect; import mage.game.permanent.token.GermToken; -import mage.players.Player; public class LivingWeaponAbility extends EntersBattlefieldTriggeredAbility { public LivingWeaponAbility() { - super(new LivingWeaponEffect()); + super(new CreateTokenAttachSourceEffect(new GermToken())); } public LivingWeaponAbility(final LivingWeaponAbility ability) { @@ -20,7 +16,8 @@ public class LivingWeaponAbility extends EntersBattlefieldTriggeredAbility { @Override public String getRule() { - return "Living weapon (When this Equipment enters the battlefield, create a 0/0 black Germ creature token, then attach this to it.)"; + return "Living weapon (When this Equipment enters the battlefield, " + + "create a 0/0 black Phyrexian Germ creature token, then attach this to it.)"; } @Override @@ -28,34 +25,3 @@ public class LivingWeaponAbility extends EntersBattlefieldTriggeredAbility { return new LivingWeaponAbility(this); } } - -class LivingWeaponEffect extends CreateTokenEffect { - - LivingWeaponEffect() { - super(new GermToken()); - } - - LivingWeaponEffect(final LivingWeaponEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (super.apply(game, source)) { - Permanent p = game.getPermanent(this.getLastAddedTokenId()); - if (p != null) { - p.addAttachment(source.getSourceId(), source, game); - return true; - } - } - } - return false; - } - - @Override - public LivingWeaponEffect copy() { - return new LivingWeaponEffect(this); - } -} diff --git a/Mage/src/main/java/mage/constants/SubType.java b/Mage/src/main/java/mage/constants/SubType.java index 81406cf6342..bced59b4181 100644 --- a/Mage/src/main/java/mage/constants/SubType.java +++ b/Mage/src/main/java/mage/constants/SubType.java @@ -287,6 +287,7 @@ public enum SubType { // R RABBIT("Rabbit", SubTypeSet.CreatureType), RAIDER("Raider", SubTypeSet.CreatureType, true), // Star Wars + RANGER("Ranger", SubTypeSet.CreatureType), RAT("Rat", SubTypeSet.CreatureType), REBEL("Rebel", SubTypeSet.CreatureType), REFLECTION("Reflection", SubTypeSet.CreatureType), @@ -403,6 +404,7 @@ public enum SubType { DAKKON("Dakkon", SubTypeSet.PlaneswalkerType), DARETTI("Daretti", SubTypeSet.PlaneswalkerType), DAVRIEL("Davriel", SubTypeSet.PlaneswalkerType), + DIHADA("Dihada", SubTypeSet.PlaneswalkerType), DOMRI("Domri", SubTypeSet.PlaneswalkerType), DOOKU("Dooku", SubTypeSet.PlaneswalkerType, true), // Star Wars DOVIN("Dovin", SubTypeSet.PlaneswalkerType), diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index 7bbfa35e0aa..3ae3ff8377a 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -12,6 +12,7 @@ import mage.game.Game; */ public enum CounterType { + ACORN("acorn"), AEGIS("aegis"), AGE("age"), AIM("aim"), @@ -30,6 +31,7 @@ public enum CounterType { CHIP("chip"), COIN("coin"), CORPSE("corpse"), + CORRUPTION("corruption"), CREDIT("credit"), CRYSTAL("crystal"), CUBE("cube"), @@ -166,6 +168,7 @@ public enum CounterType { VERSE("verse"), VIGILANCE("vigilance"), VITALITY("vitality"), + VOID("void"), VORTEX("vortex"), VOW("vow"), VOYAGE("voyage"), diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index c12d8fba34c..8e22f67d90d 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1965,11 +1965,14 @@ public abstract class GameImpl implements Game, Serializable { // (Isochron Scepter) 12/1/2004: If you don't want to cast the copy, you can choose not to; the copy ceases // to exist the next time state-based actions are checked. Zone zone = state.getZone(copiedCard.getMainCard().getId()); - if (zone == Zone.BATTLEFIELD || zone == Zone.STACK) { - continue; - } // TODO: remember LKI of copied cards here after LKI rework switch (zone) { + case BATTLEFIELD: + continue; + case STACK: + if (getStack().getStackObject(copiedCard.getId()) != null) { + continue; + } case GRAVEYARD: for (Player player : getPlayers().values()) { if (player.getGraveyard().contains(copiedCard.getId())) { diff --git a/Mage/src/main/java/mage/game/events/CoinFlippedEvent.java b/Mage/src/main/java/mage/game/events/CoinFlippedEvent.java index 554be49a9b0..b5d391449d5 100644 --- a/Mage/src/main/java/mage/game/events/CoinFlippedEvent.java +++ b/Mage/src/main/java/mage/game/events/CoinFlippedEvent.java @@ -40,4 +40,8 @@ public class CoinFlippedEvent extends GameEvent { public boolean isWinnable() { return winnable; } + + public boolean wasWon() { + return result == chosen; + } } diff --git a/Mage/src/main/java/mage/game/events/CreateTokenEvent.java b/Mage/src/main/java/mage/game/events/CreateTokenEvent.java index 9c73da08565..5b87a3d4778 100644 --- a/Mage/src/main/java/mage/game/events/CreateTokenEvent.java +++ b/Mage/src/main/java/mage/game/events/CreateTokenEvent.java @@ -3,22 +3,40 @@ package mage.game.events; import mage.abilities.Ability; import mage.game.permanent.token.Token; +import java.util.HashMap; +import java.util.Map; import java.util.UUID; public class CreateTokenEvent extends GameEvent { - private Token token; + private final Map tokens = new HashMap<>(); public CreateTokenEvent(Ability source, UUID controllerId, int amount, Token token) { super(GameEvent.EventType.CREATE_TOKEN, null, source, controllerId, amount, false); - this.token = token; + tokens.put(token, amount); } - public Token getToken() { - return token; + public Map getTokens() { + return tokens; } - public void setToken(Token token) { - this.token = token; + public void doubleTokens() { + for (Map.Entry entry : tokens.entrySet()) { + entry.setValue(entry.getValue() * 2); + } + } + + @Override + public int getAmount() { + int amount = 0; + for (Integer num : tokens.values()) { + amount += num; + } + return amount; + } + + @Override + public void setAmount(int amount) { + throw new UnsupportedOperationException("Do not use event.setAmount for tokens. Amount must be set individually in event.getTokens"); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java b/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java index 5ac97bf621f..0a429195b3c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java @@ -1,13 +1,13 @@ package mage.game.permanent.token; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import mage.MageInt; import mage.constants.CardType; import mage.constants.SubType; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + public final class BrudicladTelchorMyrToken extends TokenImpl { static final private List tokenImageSets = new ArrayList<>(); @@ -17,14 +17,10 @@ public final class BrudicladTelchorMyrToken extends TokenImpl { } public BrudicladTelchorMyrToken() { - this((String)null); - } - - public BrudicladTelchorMyrToken(String expansionSetCode) { - super("Myr", "2/1 blue Myr artifact creature token"); - this.setOriginalExpansionSetCode(expansionSetCode); + super("Phyrexian Myr", "2/1 blue Phyrexian Myr artifact creature token"); cardType.add(CardType.CREATURE); cardType.add(CardType.ARTIFACT); + subtype.add(SubType.PHYREXIAN); subtype.add(SubType.MYR); color.setBlue(true); power = new MageInt(2); diff --git a/Mage/src/main/java/mage/game/permanent/token/GermToken.java b/Mage/src/main/java/mage/game/permanent/token/GermToken.java index 7b8ed218af0..c665b8fffdd 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GermToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GermToken.java @@ -1,12 +1,12 @@ - package mage.game.permanent.token; +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import mage.MageInt; -import mage.constants.CardType; -import mage.constants.SubType; /** * @author spjspj @@ -28,11 +28,12 @@ public final class GermToken extends TokenImpl { } public GermToken(String setCode, int tokenType) { - super("Germ", "0/0 black Germ creature token"); + super("Phyrexian Germ", "0/0 black Phyrexian Germ creature token"); availableImageSetCodes = tokenImageSets; setOriginalExpansionSetCode(setCode); cardType.add(CardType.CREATURE); color.setBlack(true); + subtype.add(SubType.PHYREXIAN); subtype.add(SubType.GERM); power = new MageInt(0); toughness = new MageInt(0); diff --git a/Mage/src/main/java/mage/game/permanent/token/InsectInfectToken.java b/Mage/src/main/java/mage/game/permanent/token/InsectInfectToken.java index 7992ed37368..36b6ad9263a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/InsectInfectToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/InsectInfectToken.java @@ -1,22 +1,20 @@ - - package mage.game.permanent.token; -import mage.constants.CardType; -import mage.constants.SubType; import mage.MageInt; import mage.abilities.keyword.InfectAbility; +import mage.constants.CardType; +import mage.constants.SubType; /** - * * @author nantuko */ public final class InsectInfectToken extends TokenImpl { public InsectInfectToken() { - super("Insect", "1/1 green Insect creature token with infect"); + super("Phyrexian Insect", "1/1 green Phyrexian Insect creature token with infect"); cardType.add(CardType.CREATURE); color.setGreen(true); + subtype.add(SubType.PHYREXIAN); subtype.add(SubType.INSECT); power = new MageInt(1); toughness = new MageInt(1); @@ -31,4 +29,4 @@ public final class InsectInfectToken extends TokenImpl { public InsectInfectToken copy() { return new InsectInfectToken(this); } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/game/permanent/token/MinionToken.java b/Mage/src/main/java/mage/game/permanent/token/MinionToken.java index 950cb9a1b33..4a532e2cfa1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MinionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MinionToken.java @@ -17,9 +17,10 @@ public final class MinionToken extends TokenImpl { } public MinionToken(String setCode) { - super("Minion", "X/X black Minion creature token"); + super("Phyrexian Minion", "X/X black Phyrexian Minion creature token"); this.setOriginalExpansionSetCode(setCode); cardType.add(CardType.CREATURE); + subtype.add(SubType.PHYREXIAN); subtype.add(SubType.MINION); color.setBlack(true); power = new MageInt(0); diff --git a/Mage/src/main/java/mage/game/permanent/token/MyrToken.java b/Mage/src/main/java/mage/game/permanent/token/MyrToken.java index a1914b0c904..e9386436eb3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MyrToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MyrToken.java @@ -23,8 +23,8 @@ public final class MyrToken extends TokenImpl { public MyrToken(String expansionSetCode) { super("Myr", "1/1 colorless Myr artifact creature token"); this.setOriginalExpansionSetCode(expansionSetCode); - cardType.add(CardType.CREATURE); cardType.add(CardType.ARTIFACT); + cardType.add(CardType.CREATURE); subtype.add(SubType.MYR); power = new MageInt(1); toughness = new MageInt(1); diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianBeastToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianBeastToken.java new file mode 100644 index 00000000000..6e8fef520e1 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianBeastToken.java @@ -0,0 +1,30 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class PhyrexianBeastToken extends TokenImpl { + + public PhyrexianBeastToken() { + super("Phyrexian Beast", "4/4 green Phyrexian Beast creature token"); + cardType.add(CardType.CREATURE); + color.setGreen(true); + subtype.add(SubType.PHYREXIAN); + subtype.add(SubType.BEAST); + power = new MageInt(4); + toughness = new MageInt(4); + } + + public PhyrexianBeastToken(final PhyrexianBeastToken token) { + super(token); + } + + @Override + public PhyrexianBeastToken copy() { + return new PhyrexianBeastToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianGoblinToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianGoblinToken.java new file mode 100644 index 00000000000..3bb54a71dff --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianGoblinToken.java @@ -0,0 +1,36 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.HasteAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.Arrays; + +/** + * @author TheElk801 + */ +public final class PhyrexianGoblinToken extends TokenImpl { + + public PhyrexianGoblinToken() { + super("Phyrexian Goblin", "1/1 red Phyrexian Goblin creature token with haste"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.PHYREXIAN); + subtype.add(SubType.GOBLIN); + color.setRed(true); + power = new MageInt(1); + toughness = new MageInt(1); + + addAbility(HasteAbility.getInstance()); + + availableImageSetCodes = Arrays.asList("NPH"); + } + + public PhyrexianGoblinToken(final PhyrexianGoblinToken token) { + super(token); + } + + public PhyrexianGoblinToken copy() { + return new PhyrexianGoblinToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianGolemToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianGolemToken.java new file mode 100644 index 00000000000..bded6b25ff3 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianGolemToken.java @@ -0,0 +1,38 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.Arrays; + +/** + * @author TheElk801 + */ +public final class PhyrexianGolemToken extends TokenImpl { + + public PhyrexianGolemToken() { + super("Phyrexian Golem", "3/3 colorless Phyrexian Golem artifact creature token"); + cardType.add(CardType.ARTIFACT); + cardType.add(CardType.CREATURE); + subtype.add(SubType.PHYREXIAN); + subtype.add(SubType.GOLEM); + power = new MageInt(3); + toughness = new MageInt(3); + + availableImageSetCodes = Arrays.asList("MM2", "NPH", "SOM", "MH1", "M20", "CMR"); + } + + public PhyrexianGolemToken(final PhyrexianGolemToken token) { + super(token); + } + + public PhyrexianGolemToken copy() { + return new PhyrexianGolemToken(this); + } + + @Override + public void setExpansionSetCodeForImage(String code) { + super.setExpansionSetCodeForImage(code); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianMyrToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianMyrToken.java new file mode 100644 index 00000000000..852325af146 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianMyrToken.java @@ -0,0 +1,26 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +public final class PhyrexianMyrToken extends TokenImpl { + + public PhyrexianMyrToken() { + super("Phyrexian Myr", "1/1 colorless Phyrexian Myr artifact creature token"); + cardType.add(CardType.ARTIFACT); + cardType.add(CardType.CREATURE); + subtype.add(SubType.PHYREXIAN); + subtype.add(SubType.MYR); + power = new MageInt(1); + toughness = new MageInt(1); + } + + public PhyrexianMyrToken(final PhyrexianMyrToken token) { + super(token); + } + + public PhyrexianMyrToken copy() { + return new PhyrexianMyrToken(this); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianRebirthHorrorToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianRebirthHorrorToken.java index ef7fbf537d3..aaa4c51e60d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PhyrexianRebirthHorrorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianRebirthHorrorToken.java @@ -12,9 +12,10 @@ import java.util.Arrays; public final class PhyrexianRebirthHorrorToken extends TokenImpl { public PhyrexianRebirthHorrorToken(int power, int toughness) { - super("Horror", "X/X colorless Horror artifact creature token"); + super("Phyrexian Horror", "X/X colorless Phyrexian Horror artifact creature token"); this.cardType.add(CardType.ARTIFACT); this.cardType.add(CardType.CREATURE); + this.subtype.add(SubType.PHYREXIAN); this.subtype.add(SubType.HORROR); this.power = new MageInt(power); this.toughness = new MageInt(toughness); diff --git a/Mage/src/main/java/mage/game/permanent/token/PhyrexianZombieToken.java b/Mage/src/main/java/mage/game/permanent/token/PhyrexianZombieToken.java new file mode 100644 index 00000000000..dd34ca13a25 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/PhyrexianZombieToken.java @@ -0,0 +1,34 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.Arrays; + +/** + * @author TheElk801 + */ +public final class PhyrexianZombieToken extends TokenImpl { + + public PhyrexianZombieToken() { + super("Phyrexian Zombie", "2/2 black Phyrexian Zombie creature token"); + cardType.add(CardType.CREATURE); + color.setBlack(true); + subtype.add(SubType.PHYREXIAN); + subtype.add(SubType.ZOMBIE); + power = new MageInt(2); + toughness = new MageInt(2); + + availableImageSetCodes = Arrays.asList("MBS"); + } + + public PhyrexianZombieToken(final PhyrexianZombieToken token) { + super(token); + } + + @Override + public PhyrexianZombieToken copy() { + return new PhyrexianZombieToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/RedWhiteGolemToken.java b/Mage/src/main/java/mage/game/permanent/token/RedWhiteGolemToken.java new file mode 100644 index 00000000000..f57f1c7945f --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/RedWhiteGolemToken.java @@ -0,0 +1,27 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +public class RedWhiteGolemToken extends TokenImpl { + + public RedWhiteGolemToken() { + super("Golem", "4/4 red and white Golem artifact creature token"); + cardType.add(CardType.ARTIFACT); + cardType.add(CardType.CREATURE); + subtype.add(SubType.GOLEM); + color.setRed(true); + color.setWhite(true); + power = new MageInt(4); + toughness = new MageInt(4); + } + + private RedWhiteGolemToken(final RedWhiteGolemToken token) { + super(token); + } + + public RedWhiteGolemToken copy() { + return new RedWhiteGolemToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java b/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java index e2a9d18e990..fd73338f47b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java +++ b/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java @@ -14,10 +14,8 @@ import mage.game.permanent.PermanentToken; import mage.players.Player; import mage.util.RandomUtil; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.UUID; +import java.util.*; + import mage.abilities.SpellAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.AttachEffect; @@ -184,13 +182,24 @@ public abstract class TokenImpl extends MageObjectImpl implements Token { if (!created || !game.replaceEvent(event)) { int currentTokens = game.getBattlefield().countTokens(event.getPlayerId()); int tokenSlots = Math.max(MAX_TOKENS_PER_GAME - currentTokens, 0); - if (event.getAmount() > tokenSlots) { + int amountToRemove = event.getAmount() - tokenSlots; + if (amountToRemove > 0) { game.informPlayers( "The token limit per player is " + MAX_TOKENS_PER_GAME + ", " + controller.getName() + " will only create " + tokenSlots + " tokens." ); + Iterator> it = event.getTokens().entrySet().iterator(); + while (it.hasNext() && amountToRemove > 0) { + Map.Entry entry = it.next(); + int newValue = entry.getValue() - amountToRemove; + if (newValue > 0) { + entry.setValue(newValue); + break; + } + amountToRemove -= entry.getValue(); + it.remove(); + } } - event.setAmount(Math.min(event.getAmount(), tokenSlots)); putOntoBattlefieldHelper(event, game, source, tapped, attacking, attackedPlayer, created); return true; } @@ -203,129 +212,131 @@ public abstract class TokenImpl extends MageObjectImpl implements Token { return; } - Token token = event.getToken(); - int amount = event.getAmount(); - String setCode = token instanceof TokenImpl ? ((TokenImpl) token).getSetCode(game, event.getSourceId()) : null; + for (Map.Entry entry : event.getTokens().entrySet()) { + Token token = entry.getKey(); + int amount = entry.getValue(); + String setCode = token instanceof TokenImpl ? ((TokenImpl) token).getSetCode(game, event.getSourceId()) : null; - List needTokens = new ArrayList<>(); - List allowedTokens = new ArrayList<>(); + List needTokens = new ArrayList<>(); + List allowedTokens = new ArrayList<>(); - // prepare tokens to enter - for (int i = 0; i < amount; i++) { - // use event.getPlayerId() as controller cause it can be replaced by replacement effect - PermanentToken newPermanent = new PermanentToken(token, event.getPlayerId(), setCode, game); - game.getState().addCard(newPermanent); - needTokens.add(newPermanent); - game.getPermanentsEntering().put(newPermanent.getId(), newPermanent); - newPermanent.setTapped(tapped); + // prepare tokens to enter + for (int i = 0; i < amount; i++) { + // use event.getPlayerId() as controller cause it can be replaced by replacement effect + PermanentToken newPermanent = new PermanentToken(token, event.getPlayerId(), setCode, game); + game.getState().addCard(newPermanent); + needTokens.add(newPermanent); + game.getPermanentsEntering().put(newPermanent.getId(), newPermanent); + newPermanent.setTapped(tapped); - ZoneChangeEvent emptyEvent = new ZoneChangeEvent(newPermanent, newPermanent.getControllerId(), Zone.OUTSIDE, Zone.BATTLEFIELD); - // tokens zcc must simulate card's zcc too keep copied card/spell settings - // (example: etb's kicker ability of copied creature spell, see tests with Deathforge Shaman) - newPermanent.updateZoneChangeCounter(game, emptyEvent); - } + ZoneChangeEvent emptyEvent = new ZoneChangeEvent(newPermanent, newPermanent.getControllerId(), Zone.OUTSIDE, Zone.BATTLEFIELD); + // tokens zcc must simulate card's zcc too keep copied card/spell settings + // (example: etb's kicker ability of copied creature spell, see tests with Deathforge Shaman) + newPermanent.updateZoneChangeCounter(game, emptyEvent); + } - // check ETB effects - game.setScopeRelevant(true); - for (Permanent permanent : needTokens) { - if (permanent.entersBattlefield(source, game, Zone.OUTSIDE, true)) { - allowedTokens.add(permanent); - } else { + // check ETB effects + game.setScopeRelevant(true); + for (Permanent permanent : needTokens) { + if (permanent.entersBattlefield(source, game, Zone.OUTSIDE, true)) { + allowedTokens.add(permanent); + } else { + game.getPermanentsEntering().remove(permanent.getId()); + } + } + game.setScopeRelevant(false); + + // put allowed tokens to play + int createOrder = game.getState().getNextPermanentOrderNumber(); + for (Permanent permanent : allowedTokens) { + game.addPermanent(permanent, createOrder); + permanent.setZone(Zone.BATTLEFIELD, game); game.getPermanentsEntering().remove(permanent.getId()); - } - } - game.setScopeRelevant(false); - // put allowed tokens to play - int createOrder = game.getState().getNextPermanentOrderNumber(); - for (Permanent permanent : allowedTokens) { - game.addPermanent(permanent, createOrder); - permanent.setZone(Zone.BATTLEFIELD, game); - game.getPermanentsEntering().remove(permanent.getId()); - - // keep tokens ids - if (token instanceof TokenImpl) { - ((TokenImpl) token).lastAddedTokenIds.add(permanent.getId()); - ((TokenImpl) token).lastAddedTokenId = permanent.getId(); - } - - // created token events - ZoneChangeEvent zccEvent = new ZoneChangeEvent(permanent, permanent.getControllerId(), Zone.OUTSIDE, Zone.BATTLEFIELD); - game.addSimultaneousEvent(zccEvent); - if (permanent instanceof PermanentToken && created) { - game.addSimultaneousEvent(new CreatedTokenEvent(source, (PermanentToken) permanent)); - } - - // handle auras coming into the battlefield - // code refactored from CopyPermanentEffect - if (permanent.getSubtype().contains(SubType.AURA)) { - Outcome auraOutcome = Outcome.BoostCreature; - Target auraTarget = null; - - // attach - search effect in spell ability (example: cast Utopia Sprawl, cast Estrid's Invocation on it) - for (Ability ability : permanent.getAbilities()) { - if (!(ability instanceof SpellAbility)) { - continue; - } - auraOutcome = ability.getEffects().getOutcome(ability); - for (Effect effect : ability.getEffects()) { - if (!(effect instanceof AttachEffect)) { - continue; - } - if (permanent.getSpellAbility().getTargets().size() > 0) { - auraTarget = permanent.getSpellAbility().getTargets().get(0); - } - } + // keep tokens ids + if (token instanceof TokenImpl) { + ((TokenImpl) token).lastAddedTokenIds.add(permanent.getId()); + ((TokenImpl) token).lastAddedTokenId = permanent.getId(); } - // enchant - search in all abilities (example: cast Estrid's Invocation on enchanted creature by Estrid, the Masked second ability, cast Estrid's Invocation on it) - if (auraTarget == null) { + // created token events + ZoneChangeEvent zccEvent = new ZoneChangeEvent(permanent, permanent.getControllerId(), Zone.OUTSIDE, Zone.BATTLEFIELD); + game.addSimultaneousEvent(zccEvent); + if (permanent instanceof PermanentToken && created) { + game.addSimultaneousEvent(new CreatedTokenEvent(source, (PermanentToken) permanent)); + } + + // handle auras coming into the battlefield + // code refactored from CopyPermanentEffect + if (permanent.getSubtype().contains(SubType.AURA)) { + Outcome auraOutcome = Outcome.BoostCreature; + Target auraTarget = null; + + // attach - search effect in spell ability (example: cast Utopia Sprawl, cast Estrid's Invocation on it) for (Ability ability : permanent.getAbilities()) { - if (!(ability instanceof EnchantAbility)) { + if (!(ability instanceof SpellAbility)) { continue; } auraOutcome = ability.getEffects().getOutcome(ability); - if (ability.getTargets().size() > 0) { // Animate Dead don't have targets - auraTarget = ability.getTargets().get(0); + for (Effect effect : ability.getEffects()) { + if (!(effect instanceof AttachEffect)) { + continue; + } + if (permanent.getSpellAbility().getTargets().size() > 0) { + auraTarget = permanent.getSpellAbility().getTargets().get(0); + } } } + + // enchant - search in all abilities (example: cast Estrid's Invocation on enchanted creature by Estrid, the Masked second ability, cast Estrid's Invocation on it) + if (auraTarget == null) { + for (Ability ability : permanent.getAbilities()) { + if (!(ability instanceof EnchantAbility)) { + continue; + } + auraOutcome = ability.getEffects().getOutcome(ability); + if (ability.getTargets().size() > 0) { // Animate Dead don't have targets + auraTarget = ability.getTargets().get(0); + } + } + } + + // if this is a copy of a copy, the copy's target has been copied and needs to be cleared + if (auraTarget == null) { + break; + } + // clear selected target + if (auraTarget.getFirstTarget() != null) { + auraTarget.remove(auraTarget.getFirstTarget()); + } + + // select new target + auraTarget.setNotTarget(true); + if (!controller.choose(auraOutcome, auraTarget, source.getSourceId(), game)) { + break; + } + UUID targetId = auraTarget.getFirstTarget(); + Permanent targetPermanent = game.getPermanent(targetId); + Player targetPlayer = game.getPlayer(targetId); + if (targetPermanent != null) { + targetPermanent.addAttachment(permanent.getId(), source, game); + } else if (targetPlayer != null) { + targetPlayer.addAttachment(permanent.getId(), source, game); + } + } + // end of aura code : just remove this line if everything works out well + + // must attack + if (attacking && game.getCombat() != null && game.getActivePlayerId().equals(permanent.getControllerId())) { + game.getCombat().addAttackingCreature(permanent.getId(), game, attackedPlayer); } - // if this is a copy of a copy, the copy's target has been copied and needs to be cleared - if (auraTarget == null) { - break; + // game logs + if (created) { + game.informPlayers(controller.getLogName() + " creates a " + permanent.getLogName() + " token"); + } else { + game.informPlayers(permanent.getLogName() + " enters the battlefield as a token under " + controller.getLogName() + "'s control'"); } - // clear selected target - if (auraTarget.getFirstTarget() != null) { - auraTarget.remove(auraTarget.getFirstTarget()); - } - - // select new target - auraTarget.setNotTarget(true); - if (!controller.choose(auraOutcome, auraTarget, source.getSourceId(), game)) { - break; - } - UUID targetId = auraTarget.getFirstTarget(); - Permanent targetPermanent = game.getPermanent(targetId); - Player targetPlayer = game.getPlayer(targetId); - if (targetPermanent != null) { - targetPermanent.addAttachment(permanent.getId(), source, game); - } else if (targetPlayer != null) { - targetPlayer.addAttachment(permanent.getId(), source, game); - } - } - // end of aura code : just remove this line if everything works out well - - // must attack - if (attacking && game.getCombat() != null && game.getActivePlayerId().equals(permanent.getControllerId())) { - game.getCombat().addAttackingCreature(permanent.getId(), game, attackedPlayer); - } - - // game logs - if (created) { - game.informPlayers(controller.getLogName() + " creates a " + permanent.getLogName() + " token"); - } else { - game.informPlayers(permanent.getLogName() + " enters the battlefield as a token under " + controller.getLogName() + "'s control'"); } } game.getState().applyEffects(game); // Needed to do it here without LKIReset i.e. do get SwordOfTheMeekTest running correctly. diff --git a/Mage/src/main/java/mage/game/permanent/token/WurmWithDeathtouchToken.java b/Mage/src/main/java/mage/game/permanent/token/WurmWithDeathtouchToken.java index 4f55a1bcc69..6908ef89ef0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WurmWithDeathtouchToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WurmWithDeathtouchToken.java @@ -13,9 +13,10 @@ import java.util.Arrays; public final class WurmWithDeathtouchToken extends TokenImpl { public WurmWithDeathtouchToken() { - super("Wurm", "3/3 colorless Wurm artifact creature token with deathtouch"); + super("Phyrexian Wurm", "3/3 colorless Phyrexian Wurm artifact creature token with deathtouch"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); + subtype.add(SubType.PHYREXIAN); subtype.add(SubType.WURM); power = new MageInt(3); toughness = new MageInt(3); diff --git a/Mage/src/main/java/mage/game/permanent/token/WurmWithLifelinkToken.java b/Mage/src/main/java/mage/game/permanent/token/WurmWithLifelinkToken.java index 8ecc9cad321..8db4b8b82fa 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WurmWithLifelinkToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WurmWithLifelinkToken.java @@ -13,9 +13,10 @@ import java.util.Arrays; public final class WurmWithLifelinkToken extends TokenImpl { public WurmWithLifelinkToken() { - super("Wurm", "3/3 colorless Wurm artifact creature token with lifelink"); + super("Phyrexian Wurm", "3/3 colorless Phyrexian Wurm artifact creature token with lifelink"); cardType.add(CardType.ARTIFACT); cardType.add(CardType.CREATURE); + subtype.add(SubType.PHYREXIAN); subtype.add(SubType.WURM); power = new MageInt(3); toughness = new MageInt(3); diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 3d9287d60b0..1dc9de3119e 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -257,19 +257,22 @@ public class Spell extends StackObjectImpl implements Card { card.addSubType(game, SubType.AURA); } } - UUID permId = null; - boolean flag = false; - if (!isCopy()) { - permId = card.getId(); - flag = controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null); - } else { + UUID permId; + boolean flag; + if (isCopy()) { EmptyToken token = new EmptyToken(); CardUtil.copyTo(token).from(card, game, this); // The token that a resolving copy of a spell becomes isn’t said to have been “created.” (2020-09-25) if (token.putOntoBattlefield(1, game, ability, getControllerId(), false, false, null, false)) { permId = token.getLastAddedToken(); flag = true; + } else { + permId = null; + flag = false; } + } else { + permId = card.getId(); + flag = controller.moveCards(card, Zone.BATTLEFIELD, ability, game, false, faceDown, false, null); } if (flag) { if (bestow) { diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 1767a9962ec..389b9d9c2e7 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -1177,6 +1177,9 @@ public abstract class PlayerImpl implements Player, Serializable { logger.error("Got no spell from stack. ability: " + ability.getRule()); return false; } + if (card.isCopy()) { + spell.setCopy(true, null); + } // Update the zcc to the stack ability.setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(ability.getSourceId())); diff --git a/Mage/src/main/java/mage/watchers/common/DiscardedCardWatcher.java b/Mage/src/main/java/mage/watchers/common/DiscardedCardWatcher.java new file mode 100644 index 00000000000..a6483f67819 --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/DiscardedCardWatcher.java @@ -0,0 +1,45 @@ +package mage.watchers.common; + +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class DiscardedCardWatcher extends Watcher { + + private final Map playerMap = new HashMap<>(); + + public DiscardedCardWatcher() { + super(WatcherScope.GAME); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DISCARDED_CARD) { + playerMap.compute(event.getPlayerId(), (u, i) -> i == null ? 1 : Integer.sum(i, 1)); + } + } + + @Override + public void reset() { + playerMap.clear(); + super.reset(); + } + + public static boolean checkPlayerDiscarded(UUID playerId, Game game) { + DiscardedCardWatcher watcher = game.getState().getWatcher(DiscardedCardWatcher.class); + return watcher != null && watcher.playerMap.getOrDefault(playerId, 0) > 0; + } + + public static int getDiscarded(UUID playerId, Game game) { + DiscardedCardWatcher watcher = game.getState().getWatcher(DiscardedCardWatcher.class); + return watcher == null ? 0 : watcher.playerMap.getOrDefault(playerId, 0); + } +} diff --git a/Utils/gen-card.pl b/Utils/gen-card.pl index 582c7ab13bf..4a16b843837 100755 --- a/Utils/gen-card.pl +++ b/Utils/gen-card.pl @@ -249,6 +249,9 @@ foreach my $ability (@abilities) { } elsif ($keywords{$kw} eq 'number') { $ability =~ m/(\b\d+?\b)/g; $vars{'abilities'} .= "\n this.addAbility(new " . $kw . 'Ability(' . $1 . '));'; + } elsif ($keywords{$kw} eq 'card, number') { + $ability =~ m/(\b\d+?\b)/g; + $vars{'abilities'} .= "\n this.addAbility(new " . $kw . 'Ability(this, ' . $1 . '));'; } elsif ($keywords{$kw} eq 'cost') { $ability =~ m/({.*})/g; $vars{'abilities'} .= "\n this.addAbility(new " . $kw . 'Ability(new ManaCostsImpl<>("' . fixCost($1) . '")));'; @@ -260,7 +263,11 @@ foreach my $ability (@abilities) { $ability =~ m/({.*})/g; $vars{'abilities'} .= "\n this.addAbility(new " . $kw . 'Ability(this, new ManaCostsImpl<>("' . fixCost($1) . '")));'; $vars{'abilitiesImports'} .= "\nimport mage.abilities.costs.mana.ManaCostsImpl;"; - } elsif ($keywords{$kw} eq 'cost, card') { + } elsif ($keywords{$kw} eq 'number, cost, card') { + $ability =~ m/({.*})/g; + $vars{'abilities'} .= "\n this.addAbility(new " . $kw . 'Ability(_, new ManaCostsImpl<>("' . fixCost($1) . '"), this));'; + $vars{'abilitiesImports'} .= "\nimport mage.abilities.costs.mana.ManaCostsImpl;"; + } elsif ($keywords{$kw} eq 'cost, card') { $ability =~ m/({.*})/g; $vars{'abilities'} .= "\n this.addAbility(new " . $kw . 'Ability(new ManaCostsImpl<>("' . fixCost($1) . '"), this));'; $vars{'abilitiesImports'} .= "\nimport mage.abilities.costs.mana.ManaCostsImpl;"; diff --git a/Utils/keywords.txt b/Utils/keywords.txt index 74d6b1364bd..d40f5a9e688 100644 --- a/Utils/keywords.txt +++ b/Utils/keywords.txt @@ -31,7 +31,7 @@ Enchant|type| Encore|cost| Entwine|manaString| Eternalize|cost, card| -Evoke|card, manaString| +Evoke|manaString| Evolve|new| Exalted|new| Exploit|new| @@ -65,6 +65,7 @@ Melee|new| Menace|new| Mentor|new| Miracle|cost| +Modular|card, number| Mountaincycling|cost| Mountainwalk|new| Morph|card, cost| @@ -94,6 +95,7 @@ Skulk|new| Spectacle|card, cost| Storm|new| Sunburst|new| +Suspend|number, cost, card| Swampcycling|cost| Swampwalk|new| Totem armor|new| diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index f32349b4444..2aefba99082 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -41334,116 +41334,242 @@ Swamp|Adventures in the Forgotten Realms|273|C||Basic Land - Swamp|||({T}: Add { Mountain|Adventures in the Forgotten Realms|277|C||Basic Land - Mountain|||({T}: Add {R}.)| Forest|Adventures in the Forgotten Realms|281|C||Basic Land - Forest|||({T}: Add {G}.)| Abiding Grace|Modern Horizons 2|1|U|{2}{W}|Enchantment|||At the beginning of your end step, choose one —$• You gain 1 life.$• Return target creature card with mana value 1 from your graveyard to the battlefield.| +Arcbound Javelineer|Modern Horizons 2|2|U|{W}|Artifact Creature - Soldier|0|1|{T}, Remove X +1/+1 counters from Arcbound Javelineer: It deals X damage to target attacking or blocking creature.$Modular 1| Arcbound Mouser|Modern Horizons 2|3|C|{W}|Artifact Creature - Cat|0|0|Lifelink$Modular 1| +Arcbound Prototype|Modern Horizons 2|4|C|{1}{W}|Artifact Creature - Assembly-Worker|0|0|Modular 2| +Barbed Spike|Modern Horizons 2|5|U|{1}{W}|Artifact - Equipment|||When Barbed Spike enters the battlefield, create a 1/1 colorless Thopter artifact creature token with flying and attach Barbed Spike to it.$Equipped creature gets +1/+0.$Equip {2}| +Blacksmith's Skill|Modern Horizons 2|6|C|{W}|Instant|||Target permanent gains hexproof and indestructible until end of turn. If it's an artifact creature, it gets +2/+2 until end of turn.| +Blossoming Calm|Modern Horizons 2|7|U|{W}|Instant|||You gain hexproof until your next turn. You gain 2 life.$Rebound| Break Ties|Modern Horizons 2|8|C|{2}{W}|Instant|||Choose one —$• Destroy target artifact.$• Destroy target enchantment.$• Exile target card from a graveyard.$Reinforce 1—{W}| +Caprichrome|Modern Horizons 2|9|U|{3}{W}|Artifact Creature - Goat|2|2|Flash$Vigilance$Devour artifact 1| Constable of the Realm|Modern Horizons 2|10|U|{4}{W}|Creature - Giant Soldier|3|3|Renown 2$Whenever one or more +1/+1 counters are put on Constable of the Realm, exile up to one other target nonland permanent until Constable of the Realm leaves the battlefield.| +Disciple of the Sun|Modern Horizons 2|11|C|{4}{W}|Creature - Human Cleric|3|3|Lifelink$When Disciple of the Sun enters the battlefield, return target permanent card with mana value 3 or less from your graveyard to your hand.| Esper Sentinel|Modern Horizons 2|12|R|{W}|Artifact Creature - Human Soldier|1|1|Whenever an opponent casts their first noncreature spell each turn, draw a card unless that player pays {X}, where X is Esper Sentinel's power.| +Fairgrounds Patrol|Modern Horizons 2|13|C|{1}{W}|Creature - Human Soldier|2|1|{1}{W}, Exile Fairgrounds Patrol from your graveyard: Create a 1/1 colorless Thopter creature token with flying. Activate only as a sorcery.| Glorious Enforcer|Modern Horizons 2|14|U|{5}{W}{W}|Creature - Angel|5|5|Flying, lifelink$At the beginning of each combat, if you have more life than an opponent, Glorious Enforcer gains double strike until end of turn.| +Guardian Kirin|Modern Horizons 2|15|C|{3}{W}|Creature - Kirin|2|3|Flying$Whenever another creature you control dies, put a +1/+1 counter on Guardian Kirin.| +Healer's Flock|Modern Horizons 2|16|U|{W}{W}{W}|Creature - Bird|3|3|Flying, lifelink| +Knighted Myr|Modern Horizons 2|17|C|{2}{W}|Artifact Creature - Myr Knight|2|2|{2}{W}: Adapt 1.$Whenever one or more +1/+1 counters are put on Knighted Myr, it gains double strike until end of turn.| Landscaper Colos|Modern Horizons 2|18|C|{5}{W}|Creature - Goat Beast|4|6|When Landscaper Colos enters the battlefield, put target card from an opponent's graveyard on the bottom of their library.$Basic landcycling {1}{W}| Late to Dinner|Modern Horizons 2|19|C|{3}{W}|Sorcery|||Return target creature card from your graveyard to the battlefield. Create a Food token.| +Lens Flare|Modern Horizons 2|20|C|{4}{W}|Instant|||Affinity for artifacts$"Lens Flare" deals 5 damage to target attacking or blocking creature.| +Marble Gargoyle|Modern Horizons 2|21|C|{2}{W}|Artifact Creature - Gargoyle|2|2|Flying${W}: Marble Gargoyle gets +0/+1 until end of turn.| +Nykthos Paragon|Modern Horizons 2|22|R|{4}{W}{W}|Enchantment Creature - Human Soldier|4|6|Whenever you gain life, you may put that many +1/+1 counters on each creature you control. You may do this only once each turn.| Out of Time|Modern Horizons 2|23|R|{1}{W}{W}|Enchantment|||When Out of Time enters the battlefield, untap all creatures, then phase them out until Out of Time leaves the battlefield. Put a time counter on Out of Time for each creature phased out this way.$Vanishing| +Piercing Rays|Modern Horizons 2|24|C|{1}{W}|Sorcery|||Exile target tapped creature.$Forecast—{2}{W}, Reveal Piercing Rays from your hand: Tap target untapped creature.| Prismatic Ending|Modern Horizons 2|25|U|{X}{W}|Sorcery|||Converge — Exile target nonland permanent if its mana value is less than or equal to the number of colors of mana spent to cast this spell.| +Resurgent Belief|Modern Horizons 2|26|R||Sorcery|||Suspend 2—{1}{W}$Return all enchantment cards from your graveyard to the battlefield.| Sanctifier en-Vec|Modern Horizons 2|27|R|{W}{W}|Creature - Human Cleric|2|2|Protection from black and from red$When Sanctifier en-Vec enters the battlefield, exile all cards that are black and red from all graveyards.$If a black or red permanent, spell, or card not on the battlefield would be put into a graveyard, exile it instead.| +Scour the Desert|Modern Horizons 2|28|U|{3}{W}{W}|Sorcery|||Exile target creature card from your graveyard. Create X 1/1 white Bird creature tokens with flying, where X is the exiled card's toughness.| +Search the Premises|Modern Horizons 2|29|R|{3}{W}|Enchantment|||Whenever a creature attacks you or a planeswalker you control, investigate.| +Serra's Emissary|Modern Horizons 2|30|M|{4}{W}{W}{W}|Creature - Angel|7|7|Flying$As Serra's Emissary enters the battlefield, choose a card type.$You and creatures you control have protection from the chosen card type.| +Skyblade's Boon|Modern Horizons 2|31|U|{1}{W}|Enchantment - Aura|||Enchant creature$Enchanted creature gets +1/+1 and has flying.${2}{W}: Return Skyblade's Boon to its owner's hand. Activate only if Skyblade's Boon is on the battlefield or in your graveyard.| Solitude|Modern Horizons 2|32|M|{3}{W}{W}|Creature - Elemental Incarnation|3|2|Flash$Lifelink$When Solitude enters the battlefield, exile up to one other target creature. That creature's controller gains life equal to its power.$Evoke—Exile a white card from your hand.| +Soul of Migration|Modern Horizons 2|33|C|{5}{W}{W}|Creature - Elemental|2|4|Flying$When Soul of Migration enters the battlefield, create two 1/1 white Bird creature tokens with flying.$Evoke {3}{W}| +Thraben Watcher|Modern Horizons 2|34|U|{2}{W}{W}|Creature - Angel|2|2|Flying, vigilance$Other nontoken creatures you control get +1/+1 and have vigilance.| Timeless Dragon|Modern Horizons 2|35|R|{3}{W}{W}|Creature - Dragon|5|5|Flying$Plainscycling {2}$Eternalize {2}{W}{W}| +Unbounded Potential|Modern Horizons 2|36|C|{1}{W}|Instant|||Choose one —$• Put a +1/+1 counter on each of up to two target creatures.$• Proliferate.$Entwine {3}{W}| Aeromoeba|Modern Horizons 2|37|C|{3}{U}|Creature - Elemental Beast|2|4|Flying$Discard a card: Switch Aeromoeba's power and toughness until end of turn.| +Burdened Aerialist|Modern Horizons 2|38|C|{2}{U}|Creature - Human Pirate|3|1|When Burdened Aerialist enters the battlefield, create a Treasure token.$Whenever you sacrifice a token, Burdened Aerialist gains flying until end of turn.| Dress Down|Modern Horizons 2|39|R|{1}{U}|Enchantment|||Flash$When Dress Down enters the battlefield, draw a card.$Creatures lose all abilities.$At the beginning of the end step, sacrifice Dress Down.| +Etherium Spinner|Modern Horizons 2|40|C|{2}{U}|Artifact Creature - Human Wizard|2|1|Whenever you cast a spell with mana value 4 or greater, create a 1/1 colorless Thopter artifact creature token with flying.| +Filigree Attendant|Modern Horizons 2|41|U|{2}{U}{U}|Artifact Creature - Homunculus|*|3|Flying$Filigree Attendant's power is equal to the number of artifacts you control.| +Floodhound|Modern Horizons 2|42|C|{U}|Creature - Elemental Dog|1|2|{3}, {T}: Investigate.| +Foul Watcher|Modern Horizons 2|43|C|{1}{U}|Creature - Nightmare Bird|1|2|Flying$When Foul Watcher enters the battlefield, surveil 1.$Delirium — Foul Watcher gets +1/+0 as long as there are four more card types among cards in your graveyard.| Fractured Sanity|Modern Horizons 2|44|R|{U}{U}{U}|Sorcery|||Each opponent mills fourteen cards.$Cycling {1}{U}$When you cycle Fractured Sanity, each opponent mills four cards.| +Ghost-Lit Drifter|Modern Horizons 2|45|U|{2}{U}|Creature - Spirit|2|2|Flying${2}{U}: Another target creature gains flying until end of turn.$Channel — {X}{U}, Discard Ghost-Lit Drifter: X target creatures gain flying until end of turn.| +Hard Evidence|Modern Horizons 2|46|C|{U}|Sorcery|||Create a 0/3 blue Crab creature token.$Investigate.| +Inevitable Betrayal|Modern Horizons 2|47|R||Sorcery|||Suspend 3—{1}{U}{U}$Search target opponent's library for a creature card and put that card onto the battlefield under your control. Then that player shuffles.| Junk Winder|Modern Horizons 2|48|U|{5}{U}{U}|Creature - Serpent|5|6|Affinity for tokens$Whenever a token enters the battlefield under your control, tap target nonland permanent an opponent controls. It doesn't untap during its controller's next untap step.| Lose Focus|Modern Horizons 2|49|C|{1}{U}|Instant|||Replicate {U}$Counter target spell unless its controller pays {2}.| Lucid Dreams|Modern Horizons 2|50|U|{3}{U}{U}|Sorcery|||Draw X cards, where X is the number of card types among cards in your graveyard.| Mental Journey|Modern Horizons 2|51|C|{4}{U}{U}|Instant|||Draw three cards.$Basic landcycling {1}{U}| +Murktide Regent|Modern Horizons 2|52|M|{5}{U}{U}|Creature - Dragon|3|3|Delve$Flying$Murktide Regent enters the battlefield with a +1/+1 counter on it for each instant or sorcery card exiled with it.$Whenever an instant or sorcery card leaves your graveyard, put a +1/+1 counter on Murktide Regent.| Mystic Redaction|Modern Horizons 2|53|U|{2}{U}|Enchantment|||At the beginning of your upkeep, scry 1.$Whenever you discard a card, each opponent mills two cards.| +Parcel Myr|Modern Horizons 2|54|C|{1}{U}|Artifact Creature - Clue Myr|2|1|{2}, Sacrifice Parcel Myr: Draw a card.| Phantasmal Dreadmaw|Modern Horizons 2|55|C|{2}{U}{U}|Creature - Dinosaur Illusion|6|6|Trample$When Phantasmal Dreadmaw becomes the target of a spell or ability, sacrifice it.| +Raving Visionary|Modern Horizons 2|56|U|{1}{U}|Creature - Merfolk Wizard|1|1|{U}, {T}: Draw a card, then discard a card.$Delirium — {2}{U}, {T}: Draw a card. Activate only if there are four or more card types among cards in your graveyard.| +Recalibrate|Modern Horizons 2|57|C|{1}{U}|Instant|||Return target creature to its owner's hand. If you've discarded a card this turn, draw a card.| Rise and Shine|Modern Horizons 2|58|R|{1}{U}|Sorcery|||Target noncreature artifact you control becomes a 0/0 artifact creature. Put four +1/+1 counters on each artifact that became a creature this way.$Overload {4}{U}{U}| Rishadan Dockhand|Modern Horizons 2|59|R|{U}|Creature - Merfolk|1|2|Islandwalk${1}, {T}: Tap target land.| +Said // Done|Modern Horizons 2|60|U|{2}{U}|Sorcery|||Return target instant or sorcery card from your graveyard to your hand.$Done${3}{U}$Instant$Tap up to two target creatures. They don't untap during their controllers' next untap step.| Scuttletide|Modern Horizons 2|61|U|{1}{U}|Enchantment|||{1}, Discard a card: Create a 0/3 blue Crab creature token.$Delirium — Crabs you control get +1/+1 as long as there are four or more card types among cards in your graveyard.| Shattered Ego|Modern Horizons 2|62|C|{U}|Enchantment - Aura|||Enchant creature$Enchanted creature gets -3/-0.${3}{U}{U}: Put enchanted creature into its owner's library third from the top.| So Shiny|Modern Horizons 2|63|C|{2}{U}|Enchantment - Aura|||Enchant creature$When So Shiny enters the battlefield, if you control a token, tap enchanted creature, then scry 2.$Enchanted creature doesn't untap during its controller's untap step.| +Specimen Collector|Modern Horizons 2|64|U|{4}{U}|Creature - Vedalken Wizard|2|1|When Specimen Collector enters the battlefield, create a 1/1 green Squirrel creature token and a 0/3 blue Crab creature token.$When Specimen Collector dies, create a token that's a copy of target token you control.| +Steelfin Whale|Modern Horizons 2|65|C|{5}{U}|Creature - Whale|3|4|Affinity for artifacts$Whenever an artifact enters the battlefield under your control, untap Steelfin Whale.| Step Through|Modern Horizons 2|66|C|{3}{U}{U}|Sorcery|||Return two target creatures to their owners' hands.$Wizardcycling {2}| Subtlety|Modern Horizons 2|67|M|{2}{U}{U}|Creature - Elemental Incarnation|3|3|Flash$Flying$When Subtlety enters the battlefield, choose up to one target creature spell or planeswalker spell. Its owner puts it on the top or bottom of their library.$Evoke—Exile a blue card from your hand.| Suspend|Modern Horizons 2|68|R|{U}|Instant|||Exile target creature and put two time counters on it. If it doesn't have suspend, it gains suspend.| +Svyelun of Sea and Sky|Modern Horizons 2|69|M|{1}{U}{U}|Legendary Creature - Merfolk God|3|4|Svyelun of Sea and Sky has indestructible as long as you control at least two other Merfolk.$Whenever Svyelun attacks, draw a card.$Other Merfolk you control have ward {1}.| Sweep the Skies|Modern Horizons 2|70|U|{X}{U}{U}|Sorcery|||Converge — Create a 1/1 colorless Thopter artifact creature token with flying for each color of mana spent to cast this spell.| +Thought Monitor|Modern Horizons 2|71|R|{6}{U}|Artifact Creature - Construct|2|2|Affinity for artifacts$Flying$When Thought Monitor enters the battlefield, draw two cards.| +Tide Shaper|Modern Horizons 2|72|U|{U}|Creature - Merfolk Wizard|1|1|Kicker {1}$When Tide Shaper enters the battlefield, if it was kicked, target land becomes an Island for as long as Tide Shaper remains on the battlefield.$Tide Shaper gets +1/+1 as long as an opponent controls an Island.| Vedalken Infiltrator|Modern Horizons 2|73|U|{1}{U}|Creature - Vedalken Rogue|1|3|Vedalken Infiltrator can't be blocked.$Metalcraft — Vedalken Infiltrator gets +1/+0 as long as you control three or more artifacts.| Archfiend of Sorrows|Modern Horizons 2|74|U|{5}{B}{B}|Creature - Demon|4|5|Flying$When Archfiend of Sorrows enters the battlefield, creatures your opponents control get -2/-2 until end of turn.$Unearth {3}{B}{B}| +Archon of Cruelty|Modern Horizons 2|75|M|{6}{B}{B}|Creature - Archon|6|6|Flying$Whenever Archon of Cruelty enters the battlefield or attacks, target opponent sacrifices a creature or planeswalker, discards a card, and loses 3 life. You draw a card and gain 3 life.| Bone Shards|Modern Horizons 2|76|C|{B}|Sorcery|||As an additional cost to cast this spell, sacrifice a creature or discard a card.$Destroy target creature or planeswalker.| +Break the Ice|Modern Horizons 2|77|U|{B}{B}|Sorcery|||Destroy target land that is snow or could produce {C}.$Overload {4}{B}{B}| +Cabal Initiate|Modern Horizons 2|78|C|{1}{B}|Creature - Human Warlock|2|1|Discard a card: Cabal Initiate gains lifelink until end of turn.$Threshold — Cabal Initiate get +1/+2 as long as seven or more cards are in your graveyard.| Clattering Augur|Modern Horizons 2|79|U|{1}{B}|Creature - Skeleton Shaman|1|1|Clattering Augur can't block.$When Clattering Augur enters the battlefield, you draw a card and you lose 1 life.${2}{B}{B}: Return Clattering Augur from your graveyard to your hand.| Damn|Modern Horizons 2|80|R|{B}{B}|Sorcery|||Destroy target creature. A creature destroyed this way can't be regenerated.$Overload {2}{W}{W}| +Dauthi Voidwalker|Modern Horizons 2|81|R|{B}{B}|Creature - Dauthi Rogue|3|2|Shadow$If a card would be put into an opponent's graveyard from anywhere, instead exile it with a void counter on it.${T}, Sacrifice Dauthi Voidwalker: Choose an exiled card an opponent owns with a void counter on it. You may play it this turn without paying its mana cost.| Discerning Taste|Modern Horizons 2|82|C|{2}{B}|Sorcery|||Look at the top four cards of your library. Put one of them into your hand and the rest into your graveyard. You gain life equal to the greatest power among creature cards put into your graveyard this way.| -Fast of Sanity|Modern Horizons 2|84|U|{3}{B}|Enchantment|||Whenever you discard a card, Fast of Sanity deals 1 damage to any target and you gain 1 life.| +Echoing Return|Modern Horizons 2|83|C|{B}|Sorcery|||Return target creature card and all other cards with the same name as that card from your graveyard to your hand.| +Feast of Sanity|Modern Horizons 2|84|U|{3}{B}|Enchantment|||Whenever you discard a card, Feast of Sanity deals 1 damage to any target and you gain 1 life.| Flay Essence|Modern Horizons 2|85|U|{1}{B}{B}|Sorcery|||Exile target creature or planeswalker. You gain life equal to the number of counters on it.| +Gilt-Blade Prowler|Modern Horizons 2|86|C|{2}{B}|Creature - Human Rogue|2|3|{1}, {T}, Pay 1 life: Draw a card. Activate only if you've discarded a card this turn.| Grief|Modern Horizons 2|87|M|{2}{B}{B}|Creature - Elemental Incarnation|3|2|Menace$When Grief enters the battlefield, target opponent reveals their hand. You choose a nonland card from it. That player discards that card.$Evoke—Exile a black card from your hand.| +Hell Mongrel|Modern Horizons 2|88|C|{3}{B}|Creature - Nightmare Dog|4|3|Discard a card: Hell Mongrel gets +1/+1 until end of turn.$Madness {2}{B}| Kitchen Imp|Modern Horizons 2|89|C|{3}{B}|Creature - Imp|2|2|Flying, haste$Madness {B}| Legion Vanguard|Modern Horizons 2|90|U|{1}{B}|Creature - Vampire Soldier|2|2|{1}, Sacrifice another creature: Legion Vanguard explores.| +Loathsome Curator|Modern Horizons 2|91|C|{4}{B}|Creature - Gorgon Wizard|5|4|Exploit$Menace$When Loathsome Curator exploits a creature, destroy target creature you don't control with mana value 3 or less.| +Magus of the Bridge|Modern Horizons 2|92|R|{B}{B}{B}|Creature - Human Wizard|4|4|Whenever a nontoken creature is put into your graveyard from the battlefield, create a 2/2 black Zombie creature token.$When a creature is put into an opponent's graveyard from the battlefield, exile Magus of the Bridge.| +Necrogoyf|Modern Horizons 2|93|R|{3}{B}{B}|Creature - Lhurgoyf|*|4|Necrogoyf's power is equal to the number of creature cards in all graveyards.$At the beginning of each player's upkeep, that player discards a card.$Madness {1}{B}{B}| Necromancer's Familiar|Modern Horizons 2|94|U|{3}{B}|Creature - Bird Spirit|3|1|Flying$Hellbent — Necromancer's Familiar has lifelink as long as you have no cards in hand.${B}, Discard a card: Necromancer's Familiar gains indestructible until end of turn. Tap it.| +Nested Shambler|Modern Horizons 2|95|C|{B}|Creature - Zombie|1|1|When Nested Shambler dies, create X tapped 1/1 green Squirrel creature tokens, where X is Nested Shambler's power.| +Persist|Modern Horizons 2|96|R|{1}{B}|Sorcery|||Return target nonlegendary creature card from your graveyard to the battlefield with a -1/-1 counter on it.| Profane Tutor|Modern Horizons 2|97|R||Sorcery|||Suspend 2—{1}{B}$Search your library for a card, put that card into your hand, then shuffle.| +Radiant Epicure|Modern Horizons 2|98|U|{4}{B}|Creature - Vampire Wizard|5|5|Converge — When Radiant Epicure enters the battlefield, each opponent loses X life and you gain X life, where X is the number of colors of mana spent to cast this spell.| +Sinister Starfish|Modern Horizons 2|99|C|{1}{B}|Creature - Starfish|0|3|{T}: Surveil 1.| Sudden Edict|Modern Horizons 2|100|U|{1}{B}|Instant|||Split second$Target player sacrifices a creature.| +Tizerus Charger|Modern Horizons 2|101|C|{2}{B}|Creature - Pegasus|3|2|Escape—{4}{B}, Exile five other cards from your graveyard.$Tizerus Charger escapes with your choice of a +1/+1 counter or a flying counter on it.| +Tourach, Dread Cantor|Modern Horizons 2|102|M|{1}{B}|Legendary Creature - Human Cleric|2|1|Kicker {B}{B}$Protection from white$Whenever an opponent discards a card, put a +1/+1 counter on Tourach, Dread Cantor.$When Tourach enters the battelfield, if it was kicked, target opponent discards two cards at random.| Tourach's Canticle|Modern Horizons 2|103|C|{3}{B}|Sorcery|||Target opponent reveals their hand. You choose a card from it. That player discards that card, then discards a card at random.| +Tragic Fall|Modern Horizons 2|104|C|{1}{B}|Instant|||Target creature gets -3/-3 until end of turn.$Hellbent — That creature gets -13/-13 until end of turn instead if you have no cards in hand.| Underworld Hermit|Modern Horizons 2|105|U|{4}{B}{B}|Creature - Human Peasant|3|3|When Underworld Hermit enters the battlefield, create a number of 1/1 green Squirrel creature tokens equal to your devotion to black.| Unmarked Grave|Modern Horizons 2|106|R|{1}{B}|Sorcery|||Search your library for a nonlegendary card, put that card into your graveyard, then shuffle.| +Vermin Gorger|Modern Horizons 2|107|C|{1}{B}|Creature - Vampire|2|2|{T}, Sacrifice another creature: Each opponent loses 2 life and you gain 2 life.| +Vile Entomber|Modern Horizons 2|108|U|{2}{B}{B}|Creature - Zombie Warlock|2|2|Deathtouch$When Vile Entomber enters the battlefield, search your library for a card, put that card into your graveyard, then shuffle.| World-Weary|Modern Horizons 2|109|C|{3}{B}{B}|Enchantment - Aura|||Enchant creature$Enchanted creature gets -4/-4.$Basic landcycling {1}{B}| +Young Necromancer|Modern Horizons 2|110|U|{4}{B}|Creature - Human Warlock|2|3|When Young Necromancer enters the battlefield, you may exile two cards from your graveyard. When you do, return target creature card from your graveyard to the battlefield.| +Arcbound Slasher|Modern Horizons 2|111|C|{4}{R}|Artifact Creature - Cat|0|0|Modular 4$Riot| +Arcbound Tracker|Modern Horizons 2|112|C|{2}{R}|Artifact Creature - Dog|0|0|Menace$Modular 2$Whenever you cast a spell other than your first spell each turn, put a +1/+1 counter on Arcbound Tracker.| Arcbound Whelp|Modern Horizons 2|113|U|{3}{R}|Artifact Creature - Dragon|0|0|Flying${R}: Arcbound Whelp gets +1/+0 until end of turn.$Modular 2| Battle Plan|Modern Horizons 2|114|C|{3}{R}|Enchantment|||At the beginning of combat on your turn, target creature you control gets +2/+0 until end of turn.$Basic landcycling {1}{R}| -Blazing Rootwalla|Modern Horizons 2|115|U|{R}|Creature - Lizard|1|1|{R}: Gets +2/+0 until end of turn. Activate only once each turn.$Madness {0}| +Blazing Rootwalla|Modern Horizons 2|115|U|{R}|Creature - Lizard|1|1|{R}: Blazing Rootwalla gets +2/+0 until end of turn. Activate only once each turn.$Madness {0}| +Bloodbraid Marauder|Modern Horizons 2|116|R|{1}{R}|Creature - Human Berserker|3|1|Bloodbraid Marauder can't block.$Delirium — This spell has cascade as long as there are four or more card types among cards in your graveyard.| Breya's Apprentice|Modern Horizons 2|117|R|{2}{R}|Artifact Creature - Human Artificer|2|3|When Breya's Apprentice enters the battlefield, create a 1/1 colorless Thopter artifact creature token with flying.${T}, Sacrifice an artifact: Choose one —$• Exile the top card of your library. Until the end of your next turn, you may play that card.$• Target creature gets +2/+0 until end of turn.| Calibrated Blast|Modern Horizons 2|118|R|{2}{R}|Instant|||Reveal cards from the top of your library until you reveal a nonland card. Put the revealed cards on the bottom of your library in a random order. When you reveal a nonland card this way, Calibrated Blast deals damage equal to that card's mana value to any target.$Flashback {3}{R}{R}| +Captain Ripley Vance|Modern Horizons 2|119|U|{2}{R}|Legendary Creature - Human Pirate|3|2|Whenever you cast your third spell each turn, put a +1/+1 counter on Captain Ripley Vance, then it deals damage equal to its power to any target.| Chef's Kiss|Modern Horizons 2|120|R|{1}{R}{R}|Instant|||Gain control of target spell that targets only a single permanent or player. Copy it, then reselect the targets at random for the spell and the copy. The new targets can't be you or a permanent you control.| Dragon's Rage Channeler|Modern Horizons 2|121|U|{R}|Creature - Human Shaman|1|1|Whenever you cast a noncreature spell, surveil 1.$Delirium — As long as there are four or more card types among cards in your graveyard, Dragon's Rage Channeler gets +2/+2, has flying, and attacks each combat if able.| +Faithless Salvaging|Modern Horizons 2|122|C|{1}{R}|Instant|||Discard a card, then draw a card.$Rebound| +Fast // Furious|Modern Horizons 2|123|U|{2}{R}|Instant|||Discard a card, then draw two cards.$Furious${3}{R}{R}$Sorcery$Furious deals 3 damage to each creature without flying.| Flame Blitz|Modern Horizons 2|124|U|{R}|Enchantment|||At the beginning of your end step, Flame Blitz deals 5 damage to each planeswalker.$Cycling {2}| Flametongue Yearling|Modern Horizons 2|125|U|{R}{R}|Creature - Kavu|2|1|Multikicker {2}$Flametongue Yearling enters the battlefield with a +1/+1 counter on it for each time it was kicked.$When Flametongue Yearling enters the battlefield, it deals damage equal to its power to target creature.| +Fury|Modern Horizons 2|126|M|{3}{R}{R}|Creature - Elemental Incarnation|3|3|Double strike$When Fury enters the battlefield, it deals 4 damage divided as you choose among any number of target creatures and/or planeswalkers.$Evoke—Exile a red card from your hand.| Galvanic Relay|Modern Horizons 2|127|C|{2}{R}|Sorcery|||Exile the top card of your library. During your next turn, you may play that card.$Storm| +Gargadon|Modern Horizons 2|128|C|{5}{R}{R}|Creature - Beast|7|5|Trample$Suspend 4—{1}{R}| Glimpse of Tomorrow|Modern Horizons 2|129|R||Sorcery|||Suspend 3—{R}{R}$Shuffle all permanents you own into your library, then reveal that many cards from the top of your library. Put all non-Aura permanent cards revealed this way onto the battlefield, then do the same for Aura cards, then put the rest on the bottom of your library in a random order.| +Goblin Traprunner|Modern Horizons 2|130|U|{3}{R}|Creature - Goblin|4|2|Whenever Goblin Traprunner attacks, flip three coins. For each flip you win, create a 1/1 red Goblin creature token that's tapped and attacking.| +Gouged Zealot|Modern Horizons 2|131|C|{3}{R}|Creature - Cyclops Berserker|4|3|Reach$Delirium — Whenever Gouged Zealot attacks, if there are four or more card types among cards in your graveyard, Gouged Zealot deals 1 damage to each creature defending player controls.| Harmonic Prodigy|Modern Horizons 2|132|R|{1}{R}|Creature - Human Wizard|1|3|Prowess$If an ability of a Shaman or another Wizard you control triggers, that ability triggers an additional time.| +Kaleidoscorch|Modern Horizons 2|133|U|{1}{R}|Sorcery|||Converge — Kaleidoscorch deals X damage to any target, where X is the number of colors of mana spent to cast this spell.$Flashback {4}{R}| +Lightning Spear|Modern Horizons 2|134|C|{1}{R}|Artifact - Equipment|||Equipped creature gets +1/+0 and has trample.${2}{R}, Sacrifice Lightning Spear: It deals 3 damage to any target.$Equip {1}| +Mine Collapse|Modern Horizons 2|135|C|{3}{R}|Instant|||If it's your turn, you may sacrifice a Mountain rater than pay this spell's mana cost.$Mine Collapse deals 5 damage to target creature or planeswalker.| +Mount Velus Manticore|Modern Horizons 2|136|C|{2}{R}{R}|Enchantment Creature - Manticore|3|4|At the beginning of combat on your turn, you may discard a card. When you do, Mount Velus Manticore deals X damage to any target, where X is the number of card types the discarded card has.| Obsidian Charmaw|Modern Horizons 2|137|R|{3}{R}{R}|Creature - Dragon|4|4|This spell costs {1} less to cast for each land your opponents control that could produce {C}.$Flying$When Obsidian Charmaw enters the battlefield, destroy target nonbasic land an opponent controls.| Ragavan, Nimble Pilferer|Modern Horizons 2|138|M|{R}|Legendary Creature - Monkey Pirate|2|1|Whenever Ragavan, Nimble Pilferer deals combat damage to a player, create a Treasure token and exile the top card of that player's library. Until end of turn, you may cast that card.$Dash {1}{R}| +Revolutionist|Modern Horizons 2|139|C|{5}{R}|Creature - Human Wizard|3|3|When Revolutionist enters the battlefield, return target instant or sorcery card from your graveyard to your hand.$Madness {3}{R}| Skophos Reaver|Modern Horizons 2|140|C|{2}{R}|Creature - Minotaur Warrior|2|3|As long as it's your turn, Skophos Reaver gets +2/+0.$Madness {1}{R}| +Slag Strider|Modern Horizons 2|141|U|{5}{R}{R}|Creature - Elemental|3|3|Affinity for artifacts${1}, Sacrifice an artifact: Slag Strider deals 1 damage to any target.| Spreading Insurrection|Modern Horizons 2|142|U|{4}{R}|Sorcery|||Gain control of target creature you don't control until end of turn. Untap that creature. It gains haste until end of turn.$Storm| +Strike It Rich|Modern Horizons 2|143|U|{R}|Sorcery|||Create a Treasure token.$Flashback {2}{R}| +Tavern Scoundrel|Modern Horizons 2|144|C|{1}{R}|Creature - Human Rogue|1|3|Whenever you win a coin flip, create two Treasure tokens.${1}, {T}, Sacrifice another permanent: Flip a coin.| +Unholy Heat|Modern Horizons 2|145|C|{R}|Instant|||Unholy Heat deals 2 damage to target creature or planeswalker.$Delirium — Unholy Heat deals 6 damage instead if there are four or more card types among cards in your graveyard.| +Viashino Lashclaw|Modern Horizons 2|146|C|{1}{R}|Creature - Viashino Warrior|2|2|{T}, Discard a card: Creatures you control gain haste until end of turn.| Abundant Harvest|Modern Horizons 2|147|C|{G}|Sorcery|||Choose land or nonland. Reveal cards from the top of your library until you reveal a card of the chosen kind. Put that card into your hand and the rest on the bottom of your library in a random order.| -Aeve, Progenitor Ooze|Modern Horizons 2|148|R|{2}{G}{G}{G}|Legendary Creature - Ooze|2|2|Storm$Aeve, Progenitor Ooze isn't legendary as long as it's a token.$Aeve enters the battlefield with a +1/+1 counter on it for each Ooze you control.| +Aeve, Progenitor Ooze|Modern Horizons 2|148|R|{2}{G}{G}{G}|Legendary Creature - Ooze|2|2|Storm$Aeve, Progenitor Ooze isn't legendary as long as it's a token.$Aeve enters the battlefield with a +1/+1 counter on it for each other Ooze you control.| +Bannerhide Krushok|Modern Horizons 2|149|C|{3}{G}|Creature - Beast|4|4|Trample$Reinforce 2—{1}{G}$Scavenge {5}{G}{G}| +Blessed Respite|Modern Horizons 2|150|U|{1}{G}|Instant|||Target player shuffles their graveyard into their library. Prevent all combat damage that would be dealt this turn.| Chatterfang, Squirrel General|Modern Horizons 2|151|M|{2}{G}|Legendary Creature - Squirrel Warrior|3|3|Forestwalk$If one or more tokens would be created under your control, those tokens plus that many 1/1 green Squirrel creature tokens are created instead.${B}, Sacrifice X Squirrels: Target creature gets +X/-X until end of turn.| Chatterstorm|Modern Horizons 2|152|C|{1}{G}|Sorcery|||Create a 1/1 green Squirrel creature token.$Storm| +Chitterspitter|Modern Horizons 2|153|R|{2}{G}|Artifact|||At the beginning of your upkeep, you may sacrifice a token. If you do, put an acorn counter on Chitterspitter.$Squirrels you control get +1/+1 for each acorn counter on Chitterspitter.${G}, {T}: Create a 1/1 green Squirrel creature token.| +Crack Open|Modern Horizons 2|154|C|{2}{G}|Sorcery|||Destroy target artifact or enchantment. Create a Treasure token.| +Deepwood Denizen|Modern Horizons 2|155|C|{2}{G}|Creature - Elf Warrior|3|2|Vigilance${5}{G}, {T}: Draw a card. This ability costs {1} less to activate for each +1/+1 counter on creatures you control.| +Duskshell Crawler|Modern Horizons 2|156|C|{1}{G}|Creature - Insect|0|3|When Duskshell Crawler enters the battlefield, put a +1/+1 counter on target creature.$Each creature you control with a +1/+1 counter on it has trample.| Endurance|Modern Horizons 2|157|M|{1}{G}{G}|Creature - Elemental Incarnation|3|4|Flash$Reach$When Endurance enters the battlefield, up to one target player puts all the cards from their graveyard on the bottom of their library in a random order.$Evoke—Exile a green card from your hand.| -Gaea's Will|Modern Horizons 2|162|R||Sorcery|||Suspend 4—{G}$Until end of turn, you may play land cards and cast spells from your graveyard.$If a card would be put into your graveyard from anywhere this turn, exile that card instead.| +Fae Offering|Modern Horizons 2|158|U|{2}{G}|Enchantment|||At the beginning of each end step, if you've cast both a creature spell and a noncreature spell this turn, create a Clue token, a Food token, and a Treasure token.| +Flourishing Strike|Modern Horizons 2|159|C|{1}{G}|Instant|||Choose one —$• Flourishing Strike deals 5 damage to target creature with flying.$• Target creature gets +3/+3 until end of turn.$Entwine {2}{G}| +Foundation Breaker|Modern Horizons 2|160|U|{3}{G}|Creature - Elemental|2|2|When Foundation Breaker enters the battlefield, you may destroy target artifact or enchantment.$Evoke {1}{G}| +Funnel-Web Recluse|Modern Horizons 2|161|C|{4}{G}|Creature - Spider|3|5|Reach$Morbid — When Funnel-Web Recluse enters the battlefield, if a creature died this turn, investigate.| +Gaea's Will|Modern Horizons 2|162|R||Sorcery|||Suspend 4—{G}$Until end of turn, you may play lands and cast spells from your graveyard.$If a card would be put into your graveyard from anywhere this turn, exile that card instead.| +Glimmer Bairn|Modern Horizons 2|163|C|{G}|Creature - Ouphe|1|2|Sacrifice a token: Glimmer Bairn gets +2/+2 until end of turn.| +Glinting Creeper|Modern Horizons 2|164|U|{4}{G}|Creature - Plant|0|0|Converge — Glinting Creeper enters the battlefield with two +1/+1 counters on it for each color of mana spent to cast it.$Glinting Creeper can't be blocked by creatures with power 2 or less.| Herd Baloth|Modern Horizons 2|165|U|{3}{G}{G}|Creature - Beast|4|4|Whenever one or more +1/+1 counters are put on Herd Baloth, you may create a 4/4 green Beast creature token.| Ignoble Hierarch|Modern Horizons 2|166|R|{G}|Creature - Goblin Shaman|0|1|Exalted${T}: Add {B}, {R}, or {G}.| +Jade Avenger|Modern Horizons 2|167|C|{1}{G}|Creature - Frog Samurai|2|2|Bushido 2| +Jewel-Eyed Cobra|Modern Horizons 2|168|C|{2}{G}|Creature - Snake|3|1|Deathtouch$When Jewel-Eyed Cobra dies, create a Treasure token.| Orchard Strider|Modern Horizons 2|169|C|{4}{G}{G}|Creature - Treefolk|6|4|When Orchard Strider enters the battlefield, create two Food tokens.$Basic landcycling {1}{G}| Rift Sower|Modern Horizons 2|170|C|{2}{G}|Creature - Elf Druid|1|3|{T}: Add one mana of any color.$Suspend 2—{G}| Sanctum Weaver|Modern Horizons 2|171|R|{1}{G}|Enchantment Creature - Dryad|0|2|{T}: Add X mana of any one color, where X is the number of enchantments you control.| Scurry Oak|Modern Horizons 2|172|U|{2}{G}|Creature - Treefolk|1|2|Evolve$Whenever one or more +1/+1 counters are put on Scurry Oak, you may create a 1/1 green Squirrel creature token.| +Smell Fear|Modern Horizons 2|173|C|{1}{G}|Sorcery|||Proliferate.$Target creature you control fights up to one target creature you don't control.| Squirrel Sanctuary|Modern Horizons 2|174|U|{G}|Enchantment|||When Squirrel Sanctuary enters the battlefield, create a 1/1 green Squirrel creature token.$Whenever a nontoken creature you control dies, you may pay {1}. If you do, return Squirrel Sanctuary to its owner's hand.| Squirrel Sovereign|Modern Horizons 2|175|U|{1}{G}|Creature - Squirrel Noble|2|2|Other Squirrels you control get +1/+1.| Sylvan Anthem|Modern Horizons 2|176|R|{G}{G}|Enchantment|||Green creatures you control get +1/+1.$Whenever a green creature enters the battlefield under your control, scry 1.| +Terramorph|Modern Horizons 2|177|U|{3}{G}|Sorcery|||Search your library for a basic land card, put it onto the battlefield, then shuffle.$Rebound| Thrasta, Tempest's Roar|Modern Horizons 2|178|M|{10}{G}{G}|Legendary Creature - Dinosaur|7|7|This spell costs {3} less to cast for each other spell cast this turn.$Trample, haste$Trample over planeswalkers$Thrasta, Tempest's Roar has hexproof as long as it entered the battlefield this turn.| -Timeless Witness|Modern Horizons 2|179|U|{2}{G}{G}|Creature - Human Shaman|2|1|When Timeless Witness enters the battlefield, you may return target card from your graveyard to your hand.$Eternalize {5}{G}{G}| +Timeless Witness|Modern Horizons 2|179|U|{2}{G}{G}|Creature - Human Shaman|2|1|When Timeless Witness enters the battlefield, return target card from your graveyard to your hand.$Eternalize {5}{G}{G}| +Tireless Provisioner|Modern Horizons 2|180|U|{2}{G}|Creature - Elf Scout|3|2|Landfall — Whenever a land enters the battelfield under your control, create a Food token or a Treasure token.| Urban Daggertooth|Modern Horizons 2|181|C|{2}{G}{G}|Creature - Dinosaur|4|3|Vigilance$Enrage — Whenever Urban Daggertooth is dealt damage, proliferate.| Verdant Command|Modern Horizons 2|182|R|{1}{G}|Instant|||Choose two —$• Target player creates two tapped 1/1 green Squirrel creature tokens.$• Counter target loyalty ability of a planeswalker.$• Exile target card from a graveyard.$• Target player gains 3 life.| -Arcbound Shikari|Modern Horizons 2|184|U|{1}{R}{W}|Artifact Creature - Cat Soldier|0|0|First Strike$When Arcbound Shikari enters the battlefield, put a +1/+1 counter on each other artifact creature you control.$Modular 2| +Wren's Run Hydra|Modern Horizons 2|183|U|{X}{G}|Creature - Hydra|0|0|Reach$Wren's Run Hydra enters the battlefield with X +1/+1 counters on it.$Reinforce X—{X}{G}{G}| +Arcbound Shikari|Modern Horizons 2|184|U|{1}{R}{W}|Artifact Creature - Cat Soldier|0|0|First strike$When Arcbound Shikari enters the battlefield, put a +1/+1 counter on each other artifact creature you control.$Modular 2| +Arcus Acolyte|Modern Horizons 2|185|U|{G}{W}|Creature - Human Cleric Archer|2|2|Reach, lifelink$Outlast {G/W}$Each other creature you control without a +1/+1 counter on it has outlast {G/W}.| Asmoranomardicadaistinaculdacar|Modern Horizons 2|186|R||Legendary Creature - Human Wizard|3|3|As long as you've discarded a card this turn, you may pay {B/R} to cast this spell.$When Asmoranomardicadaistinaculdacar enters the battlefield, you may search your library for a card named The Underworld Cookbook, reveal it, put it into your hand, then shuffle.$Sacrifice two Foods: Target creature deals 6 damage to itself.| +Breathless Knight|Modern Horizons 2|187|C|{1}{W}{B}|Creature - Spirit Knight|2|2|Flying, lifelink$Whenever Breathless Knight or another creature enters the battlefield under your control, if that creature entered from a graveyard or you cast it from a graveyard, put a +1/+1 counter on Breathless Knight.| +Captured by Lagacs|Modern Horizons 2|188|C|{1}{G}{W}|Enchantment - Aura|||Enchant creature$Enchanted creature can't attack or block.$When Captured by Lagacs enters the battlefield, support 2.| Carth the Lion|Modern Horizons 2|189|R|{2}{B}{G}|Legendary Creature - Human Warrior|3|5|Whenever Carth the Lion enters the battlefield or a planeswalker you control dies, look at the top seven cards of your library. You may reveal a planeswalker card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.$Planeswalkers' loyalty abilities you activate cost an additional {+1} to activate.| +Chrome Courier|Modern Horizons 2|190|C|{1}{W}{U}|Artifact Creature - Thopter|1|1|Flying$When Chrome Courier enters the battlefield, reveal the top two cards of your library. Put one of them into your hand and the other into your graveyard. If you put an artifact card into your hand this way, you gain 3 life.| +Combine Chrysalis|Modern Horizons 2|191|U|{G}{U}|Artifact|||Creature tokens you control have flying.${2}{G}{U}, {T}, Sacrifice a token: Create a 4/4 green Beast creature token. Activate only as a sorcery.| Dakkon, Shadow Slayer|Modern Horizons 2|192|M|{W}{U}{B}|Legendary Planeswalker - Dakkon|0|Dakkon, Shadow Slayer enters the battlefield with a number of loyalty counters on him equal to the number of lands you control.$+1: Surveil 2.$−3: Exile target creature.$−6: You may put an artifact card from your hand or graveyard onto the battlefield.| +Dihada's Ploy|Modern Horizons 2|193|C|{1}{U}{B}|Instant|||Draw two cards, then discard a card. You gain life equal to the number of cards you've discarded this turn.$Jump-start| Drey Keeper|Modern Horizons 2|194|C|{3}{B}{G}|Creature - Elf Druid|2|2|When Drey Keeper enters the battlefield, create two 1/1 green Squirrel creature tokens.${3}{B}: Squirrels you control get +1/+0 and gain menace until end of turn.| -Garth One-Eye|Modern Horizons 2|197|M|{W}{U}{B}{R}{G}|Legendary Creature - Human Wizard|5|5|{T}: Choose a card name that hasn't been chosen from among Disenchant, Braingeyser, Terror, Shivan Dragon, Regrowth, or Black Lotus. Create a copy of the card with the chosen name. You may cast the copy.| -Geyadrone Dihada|Modern Horizons 2|199|M|{1}{U}{B}{R}|Legendary Planeswalker - Dihada|4|Protection from permanents with corruption counters on them.$+1: Each opponent loses 2 life and you gain 2 life. Put a corruption counter on up to one other target creature or planeswalker.$−3: Gain control of target creature or planeswalker until end of tun. Untap it and put a corruption counter on it. It gains haste until end of turn.$−7: Gain control of each permanent with a corruption counter on it.| +Ethersworn Sphinx|Modern Horizons 2|195|U|{7}{W}{U}|Artifact Creature - Sphinx|4|4|Affinity for artifacts$Flying$Cascade| +Foundry Helix|Modern Horizons 2|196|C|{1}{R}{W}|Instant|||As an additional cost to cast this spell, sacrifice a permanent.$Foundry Helix deals 4 damage to any target. If the sacrificed permanent was an artifact, you gain 4 life.| +Garth One-Eye|Modern Horizons 2|197|M|{W}{U}{B}{R}{G}|Legendary Creature - Human Wizard|5|5|{T}: Choose a card name that hasn't been chosen from among Disenchant, Braingeyser, Terror, Shivan Dragon, Regrowth, and Black Lotus. Create a copy of the card with the chosen name. You may cast the copy.| +General Ferrous Rokiric|Modern Horizons 2|198|R|{1}{R}{W}|Legendary Creature - Human Soldier|3|1|Hexproof from monocolored$Whenever you cast a multicolored spell, create a 4/4 red and white Golem artifact creature token.| +Geyadrone Dihada|Modern Horizons 2|199|M|{1}{U}{B}{R}|Legendary Planeswalker - Dihada|4|Protection from permanents with corruption counters on them$+1: Each opponent loses 2 life and you gain 2 life. Put a corruption counter on up to one other target creature or planeswalker.$−3: Gain control of target creature or planeswalker until end of tun. Untap it and put a corruption counter on it. It gains haste until end of turn.$−7: Gain control of each permanent with a corruption counter on it.| +Goblin Anarchomancer|Modern Horizons 2|200|C|{R}{G}|Creature - Goblin Shaman|2|2|Each spell you cast that's red or green costs {1} less to cast.| Graceful Restoration|Modern Horizons 2|201|U|{3}{W}{B}|Sorcery|||Choose one —$• Return target creature card from your graveyard to the battlefield with an additional +1/+1 counter on it.$• Return up to two target creature cards with power 2 or less from your graveyard to the battlefield.| Grist, the Hunger Tide|Modern Horizons 2|202|M|{1}{B}{G}|Legendary Planeswalker - Grist|3|As long as Grist, the Hunger Tide isn't on the battlefield, it's a 1/1 Insect creature in addition to its other types.$+1: Create a 1/1 black and green Insect creature token, then mill a card. If an Insect card was milled this way, put a loyalty counter on Grist and repeat this process.$−2: You may sacrifice a creature. When you do, destroy target creature or planeswalker.$−5: Each opponent loses life equal to the number of creature cards in your graveyard.| +Lazotep Chancellor|Modern Horizons 2|203|U|{U}{B}|Creature - Zombie Wizard|1|3|Whenever you discard a card, you may pay {1}. If you do, amass 2.| Lonis, Cryptozoologist|Modern Horizons 2|204|R|{G}{U}|Legendary Creature - Snake Elf Scout|1|2|Whenever another nontoken creature enters the battlefield under your control, investigate.${T}, Sacrifice X Clues: Target opponent reveals the top X cards of their library. You may put a nonland permanent card with mana value X or less from among them onto the battlefield under your control. That player puts the rest on the bottom of their library in a random order.| Master of Death|Modern Horizons 2|205|R|{1}{U}{B}|Creature - Zombie Wizard|3|1|When Master of Death enters the battlefield, surveil 2.$At the beginning of your upkeep, if Master of Death is in your graveyard, you may pay 1 life. If you do, return it to your hand.| +Moderation|Modern Horizons 2|206|R|{1}{W}{U}|Enchantment|||You can't cast more than one spell each turn.$Whenever you cast a spell, draw a card.| Piru, the Volatile|Modern Horizons 2|207|R|{2}{R}{R}{W}{W}{B}{B}|Legendary Creature - Elder Dragon|7|7|Flying, lifelink$At the beginning of your upkeep, sacrifice Piru, the Volatile unless you pay {R}{W}{B}.$When Piru dies, it deals 7 damage to each nonlegendary creature.| Priest of Fell Rites|Modern Horizons 2|208|R|{W}{B}|Creature - Human Warlock|2|2|{T}, Pay 3 life, Sacrifice Priest of Fell Rites: Return target creature card from your graveyard to the battlefield. Activate only as a sorcery.$Unearth {3}{W}{B}| -Prophetic Titan|Modern Horizons 2|209|U|{4}{U}{R}|Creature - Giant Wizard|4|4|Delirium — When Prophetic Titan enters the battlefield, choose one. If there are four or more card types among cards in your graveyard, choose both.$• Prophetic Titan deals 4 damage to any target.$• Look at the top four cards of your library. Put one in your hand and the rest on the bottom of your library in a random order.| +Prophetic Titan|Modern Horizons 2|209|U|{4}{U}{R}|Creature - Giant Wizard|4|4|Delirium — When Prophetic Titan enters the battlefield, choose one. If there are four or more card types among cards in your graveyard, choose both instead.$• Prophetic Titan deals 4 damage to any target.$• Look at the top four cards of your library. Put one of them into your hand and the rest on the bottom of your library in a random order.| +Rakdos Headliner|Modern Horizons 2|210|U|{B}{R}|Creature - Devil|3|3|Haste$Echo—Discard a card.| Ravenous Squirrel|Modern Horizons 2|211|U|{B/G}|Creature - Squirrel|1|1|Whenever you sacrifice an artifact or creature, put a +1/+1 counter on Ravenous Squirrel.${1}{B}{G}, Sacrifice an artifact or creature: You gain 1 life and draw a card.| Road // Ruin|Modern Horizons 2|212|U|{2}{G}|Instant|||Search your library for a basic land card, put it onto the battlefield tapped, then shuffle.$Ruin${1}{R}{R}$Sorcery$Aftermath$Ruin deals damage to target creature equal to the number of lands you control.| +Storm God's Oracle|Modern Horizons 2|213|C|{1}{U}{R}|Enchantment Creature - Human Shaman|1|3|{1}: Storm God's Oracle gets +1/-1 until end of turn.$When Storm God's Oracle dies, it deals 3 damage to any target.| +Sythis, Harvest's Hand|Modern Horizons 2|214|R|{G}{W}|Legendary Enchantment Creature - Nymph|1|2|Whenever you cast an enchantment spell, you gain 1 life and draw a card.| +Terminal Agony|Modern Horizons 2|215|C|{2}{B}{R}|Sorcery|||Destroy target creature.$Madness {B}{R}| Territorial Kavu|Modern Horizons 2|216|R|{R}{G}|Creature - Kavu|*|*|Domain — Territorial Kavu's power and toughness are each equal to the number of basic land types among lands you control.$Whenever Territorial Kavu attacks, choose one —$• Discard a card. If you do, draw a card.$• Exile up to one target card from a graveyard.| +Wavesifter|Modern Horizons 2|217|C|{3}{G}{U}|Creature - Elemental|3|2|Flying$When Wavesifter enters the battlefield, investigate twice.$Evoke {G}{U}| Yusri, Fortune's Flame|Modern Horizons 2|218|R|{1}{U}{R}|Legendary Creature - Efreet|2|3|Flying$Whenever Yusri, Fortune's Flame attacks, choose a number between 1 and 5. Flip that many coins. For each flip you win, draw a card. For each flip you lose, Yursi deals 2 damage to you. If you won five flips this way, you may cast spells from your hand this turn without paying their mana costs.| Academy Manufactor|Modern Horizons 2|219|R|{3}|Artifact Creature - Assembly-Worker|1|3|If you would create a Clue, Food, or Treasure token, instead create one of each.| Altar of the Goyf|Modern Horizons 2|220|U|{5}|Tribal Artifact - Lhurgoyf|||Whenever a creature you control attacks alone, it gets +X/+X until end of turn, where X is the number of card types among cards in all graveyard.$Lhurgoyf creatures you control have trample.| +Batterbone|Modern Horizons 2|221|U|{2}|Artifact - Equipment|||Living weapon$Equipped creature gets +1/+1 and has vigilance and lifelink.$Equip {5}| Bottle Golems|Modern Horizons 2|222|C|{4}|Artifact Creature - Golem|3|3|Trample$When Bottle Golems dies, you gain life equal to its power.| Brainstone|Modern Horizons 2|223|U|{1}|Artifact|||{2},{T}, Sacrifice Brainstone: Draw three cards, then put two cards from your hand on top of your library in any order.| Dermotaxi|Modern Horizons 2|224|R|{2}|Artifact - Vehicle|0|0|Imprint — As Dermotaxi enters the battlefield, exile a creature card from a graveyard.$Tap two untapped creatures you control: Until end of turn, Dermotaxi becomes a copy of the imprinted card, except it's a Vehicle artifact in addition to its other types.| Diamond Lion|Modern Horizons 2|225|R|{2}|Artifact Creature - Cat|2|2|{T}, Discard your hand, Sacrifice Diamond Lion: Add three mana of any one color. Activate only as an instant.| +Fodder Tosser|Modern Horizons 2|226|C|{3}|Artifact|||{T}, Discard a card: Fodder Tosser deals 2 damage to target player or planeswalker.| Kaldra Compleat|Modern Horizons 2|227|M|{7}|Legendary Artifact - Equipment|||Living weapon$Indestructible$Equipped creature gets +5/+5 and has first strike, trample, indestructible, haste, and "Whenever this creature deals combat damage to a creature, exile that creature."$Equip {7}| +Liquimetal Torque|Modern Horizons 2|228|U|{2}|Artifact|||{T}: Add {C}.${T}: Target nonland permanent becomes an artifact in addition to its other types until end of turn.| Monoskelion|Modern Horizons 2|229|U|{2}|Artifact Creature - Construct|1|1|Monoskelion enters the battlefield with a +1/+1 counter on it.${1}, Remove a +1/+1 counter from Monoskelion: Monoskelion deals 1 damage to any target.| +Myr Scrapling|Modern Horizons 2|230|C|{1}|Artifact Creature - Myr|1|1|Sacrifice Myr Scrapling: Put a +1/+1 counter on target creature.| +Nettlecyst|Modern Horizons 2|231|R|{3}|Artifact - Equipment|||Living weapon$Equipped creature gets +1/+1 for each artifact and/or enchantment you control.$Equip {2}| +Ornithopter of Paradise|Modern Horizons 2|232|C|{2}|Artifact Creature - Thopter|0|2|Flying${T}: Add one mana of any color.| Sanctuary Raptor|Modern Horizons 2|233|U|{3}|Artifact Creature - Bird|2|1|Flying$Whenever Sanctuary Raptor attacks, if you control three or more tokens, Sanctuary Raptor gets +2/+0 and gains first strike until end of turn.| +Scion of Draco|Modern Horizons 2|234|M|{12}|Artifact Creature - Dragon|4|4|Domain — This spell costs {2} less to cast for each basic land type among lands you control.$Flying$Each creature you control has vigilance if it's white, hexproof if it's blue, lifelink if it's black, first strike if it's red, and trample if it's green.| +Sojourner's Companion|Modern Horizons 2|235|C|{7}|Artifact Creature - Salamander|4|4|Affinity for artifacts$Artifact landcycling {2}| +Sol Talisman|Modern Horizons 2|236|R||Artifact|||Suspend 3—{1}${T}: Add {C}{C}.| +Steel Dromedary|Modern Horizons 2|237|U|{3}|Artifact Creature - Camel|2|2|Steel Dromedary enters the battlefield tapped with two +1/+1 counters on it.$Steel Dromedary doesn't untap during your untap step if it has a +1/+1 counter on it.$At the beginning of combat on your turn, you may move a +1/+1 counter from Steel Dromedary onto target creature.| Sword of Hearth and Home|Modern Horizons 2|238|M|{3}|Artifact - Equipment|||Equipped creature gets +2/+2 and has protection from green and from white.$Whenever equipped creature deals combat damage to a player, exile up to one target creature you own, then search your library for a basic land card. Put both cards onto the battlefield under your control, then shuffle.$Equip {2}| Tormod's Cryptkeeper|Modern Horizons 2|239|C|{3}|Artifact Creature - Golem|3|2|Vigilance${T}, Sacrifice Tormod's Cryptkeeper: Exile all cards from target player's graveyard.| The Underworld Cookbook|Modern Horizons 2|240|U|{1}|Artifact|||{T}, Discard a card: Create a Food token.${4}, {T}, Sacrifice The Underworld Cookbook: Return target creature card from your graveyard to your hand.| @@ -41457,6 +41583,7 @@ Goldmire Bridge|Modern Horizons 2|247|C||Artifact Land|||Goldmire Bridge enters Marsh Flats|Modern Horizons 2|248|R||Land|||{T}, Pay 1 life, Sacrifice Marsh Flats: Search your library for a Plains or Swamp card, put it onto the battlefield, then shuffle.| Mistvault Bridge|Modern Horizons 2|249|C||Artifact Land|||Mistvault Bridge enters the battlefield tapped.$Indestructible${T}: Add {U} or {B}.| Misty Rainforest|Modern Horizons 2|250|R||Land|||{T}, Pay 1 life, Sacrifice Misty Rainforest: Search your library for a Forest or Island card, put it onto the battlefield, then shuffle.| +Power Depot|Modern Horizons 2|251|U||Artifact Land|||Power Depot enters the battlefield tapped.${T}: Add {C}.${T}: Add one mana of any color. Spend this mana only to cast artifact spells or activate abilities of artifacts.$Modular 1| Razortide Bridge|Modern Horizons 2|252|C||Artifact Land|||Razortide Bridge enters the battlefield tapped.$Indestructible${T}: Add {W} or {U}.| Rustvale Bridge|Modern Horizons 2|253|C||Artifact Land|||Rustvale Bridge enters the battlefield tapped.$Indestructible${T}: Add {R} or {W}.| Scalding Tarn|Modern Horizons 2|254|R||Land|||{T}, Pay 1 life, Sacrifice Scalding Tarn: Search your library for an Island or Mountain card, put it onto the battlefield, then shuffle.| @@ -41466,11 +41593,14 @@ Tanglepool Bridge|Modern Horizons 2|257|C||Artifact Land|||Tanglepool Bridge ent Thornglint Bridge|Modern Horizons 2|258|C||Artifact Land|||Thornglint Bridge enters the battlefield tapped.$Indestructible${T}: Add {G} or {W}.| Urza's Saga|Modern Horizons 2|259|R||Enchantment Land - Urza’s Saga|||(As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)$I — Urza's Saga gains "{T}: Add {C}."$II — Urza's Saga gains "{2}, {T}: Create a 0/0 colorless Construct artifact creature token with 'This creature gets +1/+1 for each artifact you control.'"$III — Search your library for an artifact card with mana cost {0} or {1}, put it onto the battlefield, then shuffle.| Verdant Catacombs|Modern Horizons 2|260|R||Land|||{T}, Pay 1 life, Sacrifice Verdant Catacombs: Search your library for a Swamp or Forest card, put it onto the battlefield, then shuffle.| +Yavimaya, Cradle of Growth|Modern Horizons 2|261|R||Legendary Land|||Each land is a Forest in addition to its other land types.| +Angelic Curator|Modern Horizons 2|262|U|{1}{W}|Creature - Angel Spirit|1|1|Flying, protection from artifacts| Karmic Guide|Modern Horizons 2|263|R|{3}{W}{W}|Creature - Angel Spirit|2|2|Flying, protection from black$Echo {3}{W}{W}$When Karmic Guide enters the battlefield, return target creature card from your graveyard to the battlefield.| Seal of Cleansing|Modern Horizons 2|264|U|{1}{W}|Enchantment|||Sacrifice Seal of Cleansing: Destroy target artifact or enchantment.| Solitary Confinement|Modern Horizons 2|265|R|{2}{W}|Enchantment|||At the beginning of your upkeep, sacrifice Solitary Confinement unless you discard a card.$Skip your draw step.$You have shroud.$Prevent all damage that would be dealt to you.| Soul Snare|Modern Horizons 2|266|U|{W}|Enchantment|||{W}, Sacrifice Soul Snare: Exile target creature that's attacking you or a planeswalker you control.| Counterspell|Modern Horizons 2|267|U|{U}{U}|Instant|||Counter target spell.| +Sea Drake|Modern Horizons 2|268|U|{2}{U}|Creature - Drake|4|3|Flying$When Sea Drake enters the battlefield, return two target lands you control to their owner's hand.| Seal of Removal|Modern Horizons 2|269|U|{U}|Enchantment|||Sacrifice Seal of Removal: Return target creature to its owner's hand.| Upheaval|Modern Horizons 2|270|R|{4}{U}{U}|Sorcery|||Return all permanents to their owners' hands.| Wonder|Modern Horizons 2|271|R|{3}{U}|Creature - Incarnation|2|2|Flying$As long as Wonder is in your graveyard and you control an Island, creatures you control have flying.| @@ -41486,19 +41616,26 @@ Gorilla Shaman|Modern Horizons 2|280|U|{R}|Creature - Ape Shaman|1|1|{X}{X}{1}: Imperial Recruiter|Modern Horizons 2|281|M|{2}{R}|Creature - Human Advisor|1|1|When Imperial Recruiter enters the battlefield, search your library for a creature card with power 2 or less, reveal it, put it into your hand, then shuffle.| Mogg Salvage|Modern Horizons 2|282|U|{2}{R}|Instant|||If an opponent controls an Island and you control a Mountain, you may cast this spell without paying its mana cost.$Destroy target artifact.| Enchantress's Presence|Modern Horizons 2|283|R|{2}{G}|Enchantment|||Whenever you cast an enchantment spell, draw a card.| +Hunting Pack|Modern Horizons 2|284|U|{5}{G}{G}|Instant|||Create a 4/4 green Beast creature token.$Storm| Quirion Ranger|Modern Horizons 2|285|U|{G}|Creature - Elf|1|1|Return a Forest you control to its owner's hand: Untap target creature. Activate only once each turn.| Squirrel Mob|Modern Horizons 2|286|R|{1}{G}{G}|Creature - Squirrel|2|2|Squirrel Mob gets +1/+1 for each other Squirrel on the battlefield.| +Titania, Protector of Argoth|Modern Horizons 2|287|M|{3}{G}{G}|Legendary Creature - Elemental|5|3|When Titania, Protector of Argoth enters the battlefield, return target land card from your graveyard to the battlefield.$Whenever a land you control is put into a graveyard from the battlefield, create a 5/3 green Elemental creature token.| +Yavimaya Elder|Modern Horizons 2|288|U|{1}{G}{G}|Creature - Human Druid|2|1|When Yavimaya Elder dies, you may search your library for up to two basic land cards, reveal them, put them into your hand, then shuffle.${2}, Sacrifice Yavimaya Elder: Draw a card.| +Chainer, Nightmare Adept|Modern Horizons 2|289|R|{2}{B}{R}|Legendary Creature - Human Minion|3|2|Discard a card: You may cast a creature spell from your graveyard this turn. Activate only once each turn.$Whenever a nontoken creature enters the battlefield under your control, if you didn't cast it from your hand, it gains haste until your next turn.| Fire // Ice|Modern Horizons 2|290|R|{1}{R}|Instant|||Fire deals 2 damage divided as you choose among one or two targets.$Ice${1}{U}$Instant$Tap target permanent.$Draw a card.| Mirari's Wake|Modern Horizons 2|291|M|{3}{G}{W}|Enchantment|||Creatures you control get +1/+1.$Whenever you tap a land for mana, add one mana of any type that land produced.| +Shardless Agent|Modern Horizons 2|292|R|{1}{G}{U}|Artifact Creature - Human Rogue|2|2|Cascade| Sterling Grove|Modern Horizons 2|293|R|{G}{W}|Enchantment|||Other enchantments you control have shroud.${1}, Sacrifice Sterling Grove: Search your library for an enchantment card, reveal it, then shuffle and put the card on top.| Vindicate|Modern Horizons 2|294|R|{1}{W}{B}|Sorcery|||Destroy target permanent.| +Cursed Totem|Modern Horizons 2|295|R|{2}|Artifact|||Activated abilities of creatures can't be activated.| Extruder|Modern Horizons 2|296|U|{4}|Artifact Creature - Juggernaut|4|3|Echo {4}$Sacrifice an artifact: Put a +1/+1 counter on target creature.| Millikin|Modern Horizons 2|297|U|{2}|Artifact Creature - Construct|0|1|{T}, Mill a card: Add {C}.| Nevinyrral's Disk|Modern Horizons 2|298|R|{4}|Artifact|||Nevinyrral's Disk enters the battlefield tapped.${1}, {T}: Destroy all artifacts, creatures, and enchantments.| +Patchwork Gnomes|Modern Horizons 2|299|C|{3}|Artifact Creature - Gnome|2|1|Discard a card: Regenerate Patchwork Gnomes.| Zuran Orb|Modern Horizons 2|300|U|{0}|Artifact|||Sacrifice a land: You gain 2 life.| Cabal Coffers|Modern Horizons 2|301|M||Land|||{2}, {T}: Add {B} for each Swamp you control.| Mishra's Factory|Modern Horizons 2|302|U||Land|||{T}: Add {C}.${1}: Mishra's Factory becomes a 2/2 Assembly-Worker artifact creature until end of turn. It's still a land.${T}: Target Assembly-Worker creature gets +1/+1 until end of turn.| -Persist|Modern Horizons 2|430|R|{1}{B}|Sorcery|||Return target nonlegendary creature card from your graveyard to the battlefield with a -1/-1 counter on it.| +Riptide Laboratory|Modern Horizons 2|303|R||Land|||{T}: Add {C}.${1}{U}, {T}: Return target Wizard you control to its owner's hand.| Plains|Modern Horizons 2|481|C||Basic Land - Plains|||({T}: Add {W}.)| Island|Modern Horizons 2|483|C||Basic Land - Island|||({T}: Add {U}.)| Swamp|Modern Horizons 2|485|C||Basic Land - Swamp|||({T}: Add {B}.)|