diff --git a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java index 30a275a5abf..57bca32e01b 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java @@ -1,25 +1,17 @@ package mage.cards.a; -import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.ChooseCreatureTypeEffect; -import mage.cards.Card; +import mage.abilities.effects.common.continuous.AddCreatureSubTypeAllMultiZoneEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.game.Game; -import mage.game.command.CommandObject; -import mage.game.command.Commander; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; -import mage.game.stack.StackObject; -import mage.players.Player; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreatureSpell; +import mage.filter.common.FilterOwnedCreatureCard; -import java.util.List; import java.util.UUID; /** @@ -27,6 +19,9 @@ import java.util.UUID; */ public final class ArcaneAdaptation extends CardImpl { + public static final FilterControlledCreatureSpell filterSpells = new FilterControlledCreatureSpell("creature spells you control"); + public static final FilterOwnedCreatureCard filterCards = new FilterOwnedCreatureCard("creature cards you own"); + public ArcaneAdaptation(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); @@ -34,7 +29,11 @@ public final class ArcaneAdaptation extends CardImpl { this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.Neutral))); // Creatures you control are the chosen type in addition to their other types. The same is true for creature spells you control and creature cards you own that aren't on the battlefield. - this.addAbility(new SimpleStaticAbility(new ArcaneAdaptationEffect())); + this.addAbility(new SimpleStaticAbility(new AddCreatureSubTypeAllMultiZoneEffect( + StaticFilters.FILTER_CONTROLLED_CREATURES, + filterSpells, + filterCards + ))); } private ArcaneAdaptation(final ArcaneAdaptation card) { @@ -45,96 +44,4 @@ public final class ArcaneAdaptation extends CardImpl { public ArcaneAdaptation copy() { return new ArcaneAdaptation(this); } -} - -class ArcaneAdaptationEffect extends ContinuousEffectImpl { - - ArcaneAdaptationEffect() { - super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); - staticText = "Creatures you control are the chosen type in addition to their other types. " + - "The same is true for creature spells you control and creature cards you own that aren't on the battlefield"; - } - - private ArcaneAdaptationEffect(final ArcaneAdaptationEffect effect) { - super(effect); - } - - @Override - public ArcaneAdaptationEffect copy() { - return new ArcaneAdaptationEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); - if (controller == null || subType == null) { - return false; - } - // Creature cards you own that aren't on the battlefield - // in graveyard - for (UUID cardId : controller.getGraveyard()) { - Card card = game.getCard(cardId); - if (card != null && card.isCreature(game) && !card.hasSubtype(subType, game)) { - game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); - } - } - // on Hand - for (UUID cardId : controller.getHand()) { - Card card = game.getCard(cardId); - if (card != null && card.isCreature(game) && !card.hasSubtype(subType, game)) { - game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); - } - } - // in Exile - for (Card card : game.getState().getExile().getAllCards(game, source.getControllerId())) { - if (card.isCreature(game) && !card.hasSubtype(subType, game)) { - game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); - } - } - // in Library (e.g. for Mystical Teachings) - for (Card card : controller.getLibrary().getCards(game)) { - if (card.isOwnedBy(controller.getId()) && card.isCreature(game) && !card.hasSubtype(subType, game)) { - game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); - } - } - // commander in command zone - for (CommandObject commandObject : game.getState().getCommand()) { - if (commandObject instanceof Commander) { - Card card = game.getCard((commandObject).getId()); - if (card != null && card.isOwnedBy(controller.getId()) - && card.isCreature(game) && !card.hasSubtype(subType, game)) { - game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); - } - } - } - - // creature spells you control - for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell - && stackObject.isControlledBy(source.getControllerId()) - && stackObject.isCreature(game) - && !stackObject.hasSubtype(subType, game)) { - Card card = ((Spell) stackObject).getCard(); - game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); - } - } - // creatures you control - List creatures = game.getBattlefield().getAllActivePermanents( - new FilterControlledCreaturePermanent(), source.getControllerId(), game); - for (Permanent creature : creatures) { - if (creature != null) { - creature.addSubType(game, subType); - } - } - return true; - - } - - private void setCreatureSubtype(MageObject object, SubType subtype, Game game) { - if (object == null) { - return; - } - game.getState().getCreateMageObjectAttribute(object, game).getSubtype().add(subtype); - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RukarumelBiologist.java b/Mage.Sets/src/mage/cards/r/RukarumelBiologist.java new file mode 100644 index 00000000000..cfc4cb971b2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RukarumelBiologist.java @@ -0,0 +1,78 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.ActivatedAbility; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.AddCreatureSubTypeAllMultiZoneEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.*; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.SliverToken; + +import java.util.UUID; + +/** + * @author Susucr + */ +public final class RukarumelBiologist extends CardImpl { + + public static final FilterControlledCreaturePermanent filterCreatures = + new FilterControlledCreaturePermanent("Slivers you control and nontoken creatures you control"); + public static final FilterControlledCreatureSpell filterSpells = new FilterControlledCreatureSpell("creature spells you control"); + public static final FilterOwnedCreatureCard filterCards = new FilterOwnedCreatureCard("creature cards you own"); + + static { + filterCreatures.add(Predicates.or( + SubType.SLIVER.getPredicate(), + TokenPredicate.FALSE + )); + } + + public RukarumelBiologist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // As Rukarumel, Biologist enters the battlefield, choose a creature type. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.Neutral))); + + // Slivers you control and nontoken creatures you control are the chosen type in addition to their other creature types. The same is true for creature spells you control and creature cards you own that aren't on the battlefield. + this.addAbility(new SimpleStaticAbility(new AddCreatureSubTypeAllMultiZoneEffect( + filterCreatures, + filterSpells, + filterCards + ))); + + // {3}, {T}: Create a 1/1 colorless Sliver creature token. + ActivatedAbility activated = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new CreateTokenEffect(new SliverToken()), + new ManaCostsImpl<>("{3}") + ); + activated.addCost(new TapSourceCost()); + + this.addAbility(activated); + } + + private RukarumelBiologist(final RukarumelBiologist card) { + super(card); + } + + @Override + public RukarumelBiologist copy() { + return new RukarumelBiologist(this); + } +} diff --git a/Mage.Sets/src/mage/sets/CommanderMasters.java b/Mage.Sets/src/mage/sets/CommanderMasters.java index 31f2cde14cc..28fb8b9cf16 100644 --- a/Mage.Sets/src/mage/sets/CommanderMasters.java +++ b/Mage.Sets/src/mage/sets/CommanderMasters.java @@ -526,6 +526,7 @@ public final class CommanderMasters extends ExpansionSet { cards.add(new SetCardInfo("Ruby Medallion", 405, Rarity.RARE, mage.cards.r.RubyMedallion.class)); cards.add(new SetCardInfo("Rugged Prairie", 1022, Rarity.RARE, mage.cards.r.RuggedPrairie.class)); cards.add(new SetCardInfo("Ruins of Oran-Rief", 1023, Rarity.RARE, mage.cards.r.RuinsOfOranRief.class)); + cards.add(new SetCardInfo("Rukarumel, Biologist", 711, Rarity.MYTHIC, mage.cards.r.RukarumelBiologist.class)); cards.add(new SetCardInfo("Rune-Scarred Demon", 184, Rarity.RARE, mage.cards.r.RuneScarredDemon.class)); cards.add(new SetCardInfo("Saheeli, Sublime Artificer", 935, Rarity.UNCOMMON, mage.cards.s.SaheeliSublimeArtificer.class)); cards.add(new SetCardInfo("Sai, Master Thopterist", 118, Rarity.RARE, mage.cards.s.SaiMasterThopterist.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCreatureSubTypeAllMultiZoneEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCreatureSubTypeAllMultiZoneEffect.java new file mode 100644 index 00000000000..7cc0aabe1cf --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/AddCreatureSubTypeAllMultiZoneEffect.java @@ -0,0 +1,121 @@ +package mage.abilities.effects.common.continuous; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.ChooseCreatureTypeEffect; +import mage.cards.Card; +import mage.constants.*; +import mage.filter.common.*; +import mage.game.Game; +import mage.game.command.CommandObject; +import mage.game.command.Commander; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; +import mage.players.Player; + +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801, Susucr + */ +public class AddCreatureSubTypeAllMultiZoneEffect extends ContinuousEffectImpl { + private final FilterControlledCreaturePermanent filterPermanent; + private final FilterControlledCreatureSpell filterSpell; + private final FilterOwnedCreatureCard filterCard; + + public AddCreatureSubTypeAllMultiZoneEffect( + FilterControlledCreaturePermanent filterPermanent, + FilterControlledCreatureSpell filterSpell, + FilterOwnedCreatureCard filterCard + ) { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Benefit); + + this.filterPermanent = filterPermanent; + this.filterSpell = filterSpell; + this.filterCard = filterCard; + + staticText = filterPermanent.getMessage() + " are the chosen type in addition to their other types. " + + "The same is true for " + filterSpell.getMessage() + + " and " + filterCard.getMessage() + " that aren't on the battlefield"; + } + + private AddCreatureSubTypeAllMultiZoneEffect(final AddCreatureSubTypeAllMultiZoneEffect effect) { + super(effect); + this.filterPermanent = effect.filterPermanent; + this.filterSpell = effect.filterSpell; + this.filterCard = effect.filterCard; + } + + @Override + public AddCreatureSubTypeAllMultiZoneEffect copy() { + return new AddCreatureSubTypeAllMultiZoneEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID controllerId = source.getControllerId(); + Player controller = game.getPlayer(controllerId); + SubType subType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); + if (controller == null || subType == null) { + return false; + } + + // creatures cards you own that aren't on the battlefield + // in graveyard + for (UUID cardId : controller.getGraveyard()) { + Card card = game.getCard(cardId); + if (filterCard.match(card, controllerId, source, game) && !card.hasSubtype(subType, game)) { + game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); + } + } + // on Hand + for (UUID cardId : controller.getHand()) { + Card card = game.getCard(cardId); + if (filterCard.match(card, controllerId, source, game) && !card.hasSubtype(subType, game)) { + game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); + } + } + // in Exile + for (Card card : game.getState().getExile().getAllCards(game, controllerId)) { + if (filterCard.match(card, controllerId, source, game) && !card.hasSubtype(subType, game)) { + game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); + } + } + // in Library (e.g. for Mystical Teachings) + for (Card card : controller.getLibrary().getCards(game)) { + if (filterCard.match(card, controllerId, source, game) && !card.hasSubtype(subType, game)) { + game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); + } + } + // commander in command zone + for (CommandObject commandObject : game.getState().getCommand()) { + if (commandObject instanceof Commander) { + Card card = game.getCard((commandObject).getId()); + if (filterCard.match(card, controllerId, source, game) && !card.hasSubtype(subType, game)) { + game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); + } + } + } + + // creature spells you control + for (StackObject stackObject : game.getStack()) { + if (stackObject instanceof Spell + && filterSpell.match(stackObject, controllerId, source, game) + && !stackObject.hasSubtype(subType, game)) { + Card card = ((Spell) stackObject).getCard(); + game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); + } + } + // creatures you control + List creatures = game.getBattlefield().getAllActivePermanents( + filterPermanent, controllerId, game); + for (Permanent creature : creatures) { + if (creature != null) { + creature.addSubType(game, subType); + } + } + return true; + } +} diff --git a/Mage/src/main/java/mage/filter/common/FilterControlledCreatureSpell.java b/Mage/src/main/java/mage/filter/common/FilterControlledCreatureSpell.java new file mode 100644 index 00000000000..003edbe0101 --- /dev/null +++ b/Mage/src/main/java/mage/filter/common/FilterControlledCreatureSpell.java @@ -0,0 +1,31 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package mage.filter.common; + +import mage.constants.TargetController; + +/** + * @author LevelX2 + */ +public class FilterControlledCreatureSpell extends FilterCreatureSpell { + + public FilterControlledCreatureSpell() { + this("creature spell"); + } + + public FilterControlledCreatureSpell(String name) { + super(name); + this.add(TargetController.YOU.getControllerPredicate()); + } + + public FilterControlledCreatureSpell(final FilterControlledCreatureSpell filter) { + super(filter); + } + + @Override + public FilterControlledCreatureSpell copy() { + return new FilterControlledCreatureSpell(this); + } +} diff --git a/Mage/src/main/java/mage/filter/common/FilterCreatureSpell.java b/Mage/src/main/java/mage/filter/common/FilterCreatureSpell.java index 846bc146b9f..5e6968a833d 100644 --- a/Mage/src/main/java/mage/filter/common/FilterCreatureSpell.java +++ b/Mage/src/main/java/mage/filter/common/FilterCreatureSpell.java @@ -22,4 +22,12 @@ public class FilterCreatureSpell extends FilterSpell { this.add(CardType.CREATURE.getPredicate()); } + public FilterCreatureSpell(final FilterCreatureSpell filter) { + super(filter); + } + + @Override + public FilterCreatureSpell copy() { + return new FilterCreatureSpell(this); + } } diff --git a/Mage/src/main/java/mage/filter/common/FilterOwnedCreatureCard.java b/Mage/src/main/java/mage/filter/common/FilterOwnedCreatureCard.java new file mode 100644 index 00000000000..e4be7e6a973 --- /dev/null +++ b/Mage/src/main/java/mage/filter/common/FilterOwnedCreatureCard.java @@ -0,0 +1,30 @@ + + +package mage.filter.common; + + +import mage.constants.CardType; + +/** + * @author Susucr + */ +public class FilterOwnedCreatureCard extends FilterOwnedCard { + + public FilterOwnedCreatureCard() { + this("creature card"); + } + + public FilterOwnedCreatureCard(String name) { + super(name); + this.add(CardType.CREATURE.getPredicate()); + } + + public FilterOwnedCreatureCard(final FilterOwnedCreatureCard filter) { + super(filter); + } + + @Override + public FilterOwnedCreatureCard copy() { + return new FilterOwnedCreatureCard(this); + } +}