diff --git a/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java b/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java index 60f889a0828..230c09afaa0 100644 --- a/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java +++ b/Mage.Sets/src/mage/cards/m/MuragandaPetroglyphs.java @@ -1,23 +1,14 @@ package mage.cards.m; -import mage.MageObject; -import mage.abilities.Abilities; -import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.BoostAllEffect; -import mage.abilities.keyword.special.JohanVigilanceAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicate; -import mage.game.Game; +import mage.filter.predicate.mageobject.NoAbilityPredicate; -import java.util.Objects; import java.util.UUID; /** @@ -26,18 +17,20 @@ import java.util.UUID; public final class MuragandaPetroglyphs extends CardImpl { private static final FilterCreaturePermanent filterNoAbilities - = new FilterCreaturePermanent("Creatures with no ability"); + = new FilterCreaturePermanent("creatures with no abilities"); static { - filterNoAbilities.add(new NoAbilityPredicate()); + filterNoAbilities.add(NoAbilityPredicate.instance); } public MuragandaPetroglyphs(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); // Creatures with no abilities get +2/+2. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect( - 2, 2, Duration.WhileOnBattlefield, filterNoAbilities, false))); + this.addAbility(new SimpleStaticAbility(new BoostAllEffect( + 2, 2, Duration.WhileOnBattlefield, + filterNoAbilities, false + ))); } private MuragandaPetroglyphs(final MuragandaPetroglyphs card) { @@ -49,56 +42,3 @@ public final class MuragandaPetroglyphs extends CardImpl { return new MuragandaPetroglyphs(this); } } - -class NoAbilityPredicate implements Predicate { - - // Muraganda Petroglyphs gives a bonus only to creatures that have no rules text at all. This includes true vanilla - // creatures (such as Grizzly Bears), face-down creatures, many tokens, and creatures that have lost their abilities - // (due to Ovinize, for example). Any ability of any kind, whether or not the ability functions in the on the - // battlefield zone, including things like “Cycling {2}” means the creature doesn’t get the bonus. - // (2007-05-01) - - @Override - public boolean apply(MageObject input, Game game) { - boolean isFaceDown = false; - Abilities abilities; - if (input instanceof Card) { - abilities = ((Card) input).getAbilities(game); - isFaceDown = ((Card) input).isFaceDown(game); - } else { - abilities = input.getAbilities(); - } - if (isFaceDown) { - // Some Auras and Equipment grant abilities to creatures, meaning the affected creature would no longer - // get the +2/+2 bonus. For example, Flight grants flying to the enchanted creature. Other Auras and - // Equipment do not, meaning the affected creature would continue to get the +2/+2 bonus. For example, - // Dehydration states something now true about the enchanted creature, but doesn’t give it any abilities. - // Auras and Equipment that grant abilities will use the words “gains” or “has,” and they’ll list a keyword - // ability or an ability in quotation marks. - // (2007-05-01) - - for (Ability ability : abilities) { - if (ability.getWorksFaceDown()) { - // inner face down abilities like turn up and becomes creature - continue; - } - if (!Objects.equals(ability.getClass(), SpellAbility.class) && !ability.getClass().equals(JohanVigilanceAbility.class)) { - return false; - } - } - return true; - } - - for (Ability ability : abilities) { - if (!Objects.equals(ability.getClass(), SpellAbility.class) && !ability.getClass().equals(JohanVigilanceAbility.class)) { - return false; - } - } - return true; - } - - @Override - public String toString() { - return "with no abilities"; - } -} diff --git a/Mage.Sets/src/mage/cards/r/RuxaPatientProfessor.java b/Mage.Sets/src/mage/cards/r/RuxaPatientProfessor.java new file mode 100644 index 00000000000..23c1f5c425a --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RuxaPatientProfessor.java @@ -0,0 +1,106 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.NoAbilityPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RuxaPatientProfessor extends CardImpl { + + private static final FilterCard filter + = new FilterCreatureCard("creature card with no abilities from your graveyard"); + private static final FilterCreaturePermanent filter2 + = new FilterCreaturePermanent("creatures you control with no abilities"); + + static { + filter.add(NoAbilityPredicate.instance); + filter2.add(NoAbilityPredicate.instance); + filter2.add(TargetController.YOU.getControllerPredicate()); + } + + public RuxaPatientProfessor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.BEAR); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Whenever Ruxa, Patient Professor enters the battlefield or attacks, return target creature card with no abilities from your graveyard to your hand. + Ability ability = new EntersBattlefieldOrAttacksSourceTriggeredAbility(new ReturnFromGraveyardToHandTargetEffect()); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + + // Creatures you control with no abilities get +1/+1. + this.addAbility(new SimpleStaticAbility(new BoostAllEffect( + 1, 1, Duration.WhileOnBattlefield, filter2, false + ))); + + // You may have creatures you control with no abilities assign their combat damage as though they weren't blocked. + this.addAbility(new SimpleStaticAbility(new RuxaPatientProfessorEffect())); + } + + private RuxaPatientProfessor(final RuxaPatientProfessor card) { + super(card); + } + + @Override + public RuxaPatientProfessor copy() { + return new RuxaPatientProfessor(this); + } +} + +class RuxaPatientProfessorEffect extends AsThoughEffectImpl { + + RuxaPatientProfessorEffect() { + super(AsThoughEffectType.DAMAGE_NOT_BLOCKED, Duration.WhileOnBattlefield, Outcome.Damage); + this.staticText = "you may have creatures you control with no abilities " + + "assign their combat damage as though they weren't blocked"; + } + + private RuxaPatientProfessorEffect(RuxaPatientProfessorEffect effect) { + super(effect); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(sourceId); + return controller != null + && permanent != null + && permanent.isControlledBy(controller.getId()) + && NoAbilityPredicate.instance.apply(permanent, game) + && controller.chooseUse(Outcome.Damage, "Have " + permanent.getLogName() + + " assign damage as though it weren't blocked?", source, game); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public RuxaPatientProfessorEffect copy() { + return new RuxaPatientProfessorEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/Commander2021Edition.java b/Mage.Sets/src/mage/sets/Commander2021Edition.java index 06a26fb559a..07f9a6a8f10 100644 --- a/Mage.Sets/src/mage/sets/Commander2021Edition.java +++ b/Mage.Sets/src/mage/sets/Commander2021Edition.java @@ -187,6 +187,7 @@ public final class Commander2021Edition extends ExpansionSet { cards.add(new SetCardInfo("Rousing Refrain", 56, Rarity.RARE, mage.cards.r.RousingRefrain.class)); cards.add(new SetCardInfo("Rout", 101, Rarity.RARE, mage.cards.r.Rout.class)); cards.add(new SetCardInfo("Ruin Grinder", 57, Rarity.RARE, mage.cards.r.RuinGrinder.class)); + cards.add(new SetCardInfo("Ruxa, Patient Professor", 66, Rarity.RARE, mage.cards.r.RuxaPatientProfessor.class)); cards.add(new SetCardInfo("Sanctum Gargoyle", 102, Rarity.COMMON, mage.cards.s.SanctumGargoyle.class)); cards.add(new SetCardInfo("Scavenger Grounds", 314, Rarity.RARE, mage.cards.s.ScavengerGrounds.class)); cards.add(new SetCardInfo("Scrap Trawler", 260, Rarity.RARE, mage.cards.s.ScrapTrawler.class)); diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java new file mode 100644 index 00000000000..fe450dc5a35 --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/NoAbilityPredicate.java @@ -0,0 +1,69 @@ +package mage.filter.predicate.mageobject; + +import mage.MageObject; +import mage.abilities.Abilities; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.keyword.special.JohanVigilanceAbility; +import mage.cards.Card; +import mage.filter.predicate.Predicate; +import mage.game.Game; + +import java.util.Objects; + +/** + * @author anonymous + */ +public enum NoAbilityPredicate implements Predicate { + instance; + + // Muraganda Petroglyphs gives a bonus only to creatures that have no rules text at all. This includes true vanilla + // creatures (such as Grizzly Bears), face-down creatures, many tokens, and creatures that have lost their abilities + // (due to Ovinize, for example). Any ability of any kind, whether or not the ability functions in the on the + // battlefield zone, including things like “Cycling {2}” means the creature doesn’t get the bonus. + // (2007-05-01) + + @Override + public boolean apply(MageObject input, Game game) { + boolean isFaceDown = false; + Abilities abilities; + if (input instanceof Card) { + abilities = ((Card) input).getAbilities(game); + isFaceDown = ((Card) input).isFaceDown(game); + } else { + abilities = input.getAbilities(); + } + if (isFaceDown) { + // Some Auras and Equipment grant abilities to creatures, meaning the affected creature would no longer + // get the +2/+2 bonus. For example, Flight grants flying to the enchanted creature. Other Auras and + // Equipment do not, meaning the affected creature would continue to get the +2/+2 bonus. For example, + // Dehydration states something now true about the enchanted creature, but doesn’t give it any abilities. + // Auras and Equipment that grant abilities will use the words “gains” or “has,” and they’ll list a keyword + // ability or an ability in quotation marks. + // (2007-05-01) + + for (Ability ability : abilities) { + if (ability.getWorksFaceDown()) { + // inner face down abilities like turn up and becomes creature + continue; + } + if (!Objects.equals(ability.getClass(), SpellAbility.class) && !ability.getClass().equals(JohanVigilanceAbility.class)) { + return false; + } + } + return true; + } + + for (Ability ability : abilities) { + if (!Objects.equals(ability.getClass(), SpellAbility.class) && !ability.getClass().equals(JohanVigilanceAbility.class)) { + return false; + } + } + return true; + } + + @Override + public String toString() { + return "with no abilities"; + } +}