diff --git a/Mage.Sets/src/mage/cards/c/CorpseHarvester.java b/Mage.Sets/src/mage/cards/c/CorpseHarvester.java index 561815377df..55d9260b7d0 100644 --- a/Mage.Sets/src/mage/cards/c/CorpseHarvester.java +++ b/Mage.Sets/src/mage/cards/c/CorpseHarvester.java @@ -1,29 +1,27 @@ - package mage.cards.c; -import java.util.UUID; 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.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SubTypeAssignment; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.*; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; -import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; - +import mage.filter.predicate.Predicates; import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; + /** - * * @author jeffwadsworth */ public final class CorpseHarvester extends CardImpl { @@ -37,7 +35,9 @@ public final class CorpseHarvester extends CardImpl { this.toughness = new MageInt(3); // {1}{B}, {tap}, Sacrifice a creature: Search your library for a Zombie card and a Swamp card, reveal them, and put them into your hand. Then shuffle your library. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CorpseHarvesterEffect(), new ManaCostsImpl("{1}{B}")); + Ability ability = new SimpleActivatedAbility(new SearchLibraryPutInHandEffect( + new KrosanVergeTarget(), true + ), new ManaCostsImpl("{1}{B}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); this.addAbility(ability); @@ -53,46 +53,48 @@ public final class CorpseHarvester extends CardImpl { } } -class CorpseHarvesterEffect extends OneShotEffect { +class KrosanVergeTarget extends TargetCardInLibrary { - CorpseHarvesterEffect() { - super(Outcome.DrawCard); - staticText = "Search your library for a Zombie card and a Swamp card, reveal them, and put them into your hand. Then shuffle your library"; + private static final FilterCard filter + = new FilterCard("a Zombie card and a Swamp card"); + + static { + filter.add(Predicates.or( + SubType.ZOMBIE.getPredicate(), + SubType.SWAMP.getPredicate() + )); } - CorpseHarvesterEffect(final CorpseHarvesterEffect effect) { - super(effect); + private static final SubTypeAssignment subTypeAssigner + = new SubTypeAssignment(SubType.ZOMBIE, SubType.SWAMP); + + KrosanVergeTarget() { + super(0, 2, filter); + } + + private KrosanVergeTarget(final KrosanVergeTarget target) { + super(target); } @Override - public boolean apply(Game game, Ability source) { - Player you = game.getPlayer(source.getControllerId()); - if (you == null) { + public KrosanVergeTarget copy() { + return new KrosanVergeTarget(this); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { return false; } - Cards cards = new CardsImpl(); - searchCard(you, source, game, cards, "Zombie"); - searchCard(you, source, game, cards, "Swamp"); - you.revealCards("Corpse Harvester", cards, game); - you.shuffleLibrary(source, game); - return true; - } - - private void searchCard(Player player, Ability source, Game game, Cards cards, String subtype) { - FilterCard filter = new FilterCard(subtype); - filter.add(SubType.byDescription(subtype).getPredicate()); - TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, source, game)) { - Card card = player.getLibrary().remove(target.getFirstTarget(), game); - if (card != null) { - card.moveToZone(Zone.HAND, source.getSourceId(), game, false); - cards.add(card); - } + Card card = game.getCard(id); + if (card == null) { + return false; } - } - - @Override - public CorpseHarvesterEffect copy() { - return new CorpseHarvesterEffect(this); + if (this.getTargets().isEmpty()) { + return true; + } + Cards cards = new CardsImpl(this.getTargets()); + cards.add(card); + return subTypeAssigner.getRoleCount(cards, game) >= cards.size(); } } diff --git a/Mage.Sets/src/mage/cards/g/GemOfBecoming.java b/Mage.Sets/src/mage/cards/g/GemOfBecoming.java index fba4d34f878..54393b9dbad 100644 --- a/Mage.Sets/src/mage/cards/g/GemOfBecoming.java +++ b/Mage.Sets/src/mage/cards/g/GemOfBecoming.java @@ -1,35 +1,37 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.SubTypeAssignment; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.*; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterLandCard; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author North */ public final class GemOfBecoming extends CardImpl { public GemOfBecoming(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // {3}, {tap}, Sacrifice Gem of Becoming: Search your library for an Island card, a Swamp card, and a Mountain card. // Reveal those cards and put them into your hand. Then shuffle your library. - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GemOfBecomingEffect(), new GenericManaCost(3)); + Ability ability = new SimpleActivatedAbility( + new SearchLibraryPutInHandEffect( + new GemOfBecomingTarget(), true + ), new GenericManaCost(3) + ); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); @@ -45,51 +47,52 @@ public final class GemOfBecoming extends CardImpl { } } -class GemOfBecomingEffect extends OneShotEffect { +class GemOfBecomingTarget extends TargetCardInLibrary { - public GemOfBecomingEffect() { - super(Outcome.DrawCard); - this.staticText = "Search your library for an Island card, a Swamp card, and a Mountain card. Reveal those cards and put them into your hand. Then shuffle your library"; + private static final FilterCard filter + = new FilterCard("an Island card, a Swamp card, and a Mountain card"); + + static { + filter.add(Predicates.or( + SubType.ISLAND.getPredicate(), + SubType.SWAMP.getPredicate(), + SubType.MOUNTAIN.getPredicate() + )); } - public GemOfBecomingEffect(final GemOfBecomingEffect effect) { - super(effect); + private static final SubTypeAssignment subTypeAssigner = new SubTypeAssignment( + SubType.ISLAND, + SubType.SWAMP, + SubType.MOUNTAIN + ); + + GemOfBecomingTarget() { + super(0, 3, filter); + } + + private GemOfBecomingTarget(final GemOfBecomingTarget target) { + super(target); } @Override - public GemOfBecomingEffect copy() { - return new GemOfBecomingEffect(this); + public GemOfBecomingTarget copy() { + return new GemOfBecomingTarget(this); } @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { return false; } - - Cards cards = new CardsImpl(); - - searchLand(player, source, game, cards, "Island"); - searchLand(player, source, game, cards, "Swamp"); - searchLand(player, source, game, cards, "Mountain"); - - player.revealCards("Gem of Becoming", cards, game); - player.shuffleLibrary(source, game); - - return false; - } - - private void searchLand(Player player, Ability source, Game game, Cards cards, String subtype) { - FilterLandCard filter = new FilterLandCard(subtype); - filter.add(SubType.byDescription(subtype).getPredicate()); - TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, source, game)) { - Card card = player.getLibrary().remove(target.getFirstTarget(), game); - if (card != null) { - card.moveToZone(Zone.HAND, source.getSourceId(), game, false); - cards.add(card); - } + Card card = game.getCard(id); + if (card == null) { + return false; } + if (this.getTargets().isEmpty()) { + return true; + } + Cards cards = new CardsImpl(this.getTargets()); + cards.add(card); + return subTypeAssigner.getRoleCount(cards, game) >= cards.size(); } } diff --git a/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java b/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java index 2667bc647d7..e795c20827a 100644 --- a/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java +++ b/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java @@ -2,17 +2,24 @@ package mage.cards.j; import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.*; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SuperType; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardInYourGraveyard; import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -24,7 +31,7 @@ public final class JourneyForTheElixir extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); // Search your library and graveyard for a basic land card and a card named Jiang Yanggu, reveal them, put them into your hand, then shuffle your library. - this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new JourneyForTheElixirTarget())); + this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new JourneyForTheElixirLibraryTarget())); } public JourneyForTheElixir(final JourneyForTheElixir card) { @@ -37,7 +44,43 @@ public final class JourneyForTheElixir extends CardImpl { } } -class JourneyForTheElixirTarget extends TargetCardInLibrary { +class JourneyForTheElixirEffect extends OneShotEffect { + + JourneyForTheElixirEffect() { + super(Outcome.Benefit); + staticText = "Search your library and graveyard for a basic land card and a card named Jiang Yanggu, " + + "reveal them, put them into your hand, then shuffle your library."; + } + + private JourneyForTheElixirEffect(final JourneyForTheElixirEffect effect) { + super(effect); + } + + @Override + public JourneyForTheElixirEffect copy() { + return new JourneyForTheElixirEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetCardInLibrary targetCardInLibrary = new JourneyForTheElixirLibraryTarget(); + player.searchLibrary(targetCardInLibrary, source, game); + Cards cards = new CardsImpl(targetCardInLibrary.getTargets()); + TargetCard target = new JourneyForTheElixirGraveyardTarget(cards); + player.choose(outcome, target, source.getSourceId(), game); + cards.addAll(target.getTargets()); + player.revealCards(source, cards, game); + player.moveCards(cards, Zone.HAND, source, game); + player.shuffleLibrary(source, game); + return true; + } +} + +class JourneyForTheElixirLibraryTarget extends TargetCardInLibrary { private static final String name = "Jiang Yanggu"; private static final FilterCard filter @@ -53,17 +96,17 @@ class JourneyForTheElixirTarget extends TargetCardInLibrary { )); } - JourneyForTheElixirTarget() { + JourneyForTheElixirLibraryTarget() { super(0, 2, filter); } - private JourneyForTheElixirTarget(final JourneyForTheElixirTarget target) { + private JourneyForTheElixirLibraryTarget(final JourneyForTheElixirLibraryTarget target) { super(target); } @Override - public JourneyForTheElixirTarget copy() { - return new JourneyForTheElixirTarget(this); + public JourneyForTheElixirLibraryTarget copy() { + return new JourneyForTheElixirLibraryTarget(this); } @Override @@ -100,3 +143,70 @@ class JourneyForTheElixirTarget extends TargetCardInLibrary { return true; } } + +class JourneyForTheElixirGraveyardTarget extends TargetCardInYourGraveyard { + + private static final String name = "Jiang Yanggu"; + private static final FilterCard filter + = new FilterCard("a basic land card and a card named Jiang Yanggu"); + + static { + filter.add(Predicates.or( + Predicates.and( + SuperType.BASIC.getPredicate(), + CardType.LAND.getPredicate() + ), + new NamePredicate(name) + )); + } + + private final Cards cards = new CardsImpl(); + + JourneyForTheElixirGraveyardTarget(Cards cards) { + super(0, Integer.MAX_VALUE, filter, true); + this.cards.addAll(cards); + } + + private JourneyForTheElixirGraveyardTarget(final JourneyForTheElixirGraveyardTarget target) { + super(target); + this.cards.addAll(cards); + } + + @Override + public JourneyForTheElixirGraveyardTarget copy() { + return new JourneyForTheElixirGraveyardTarget(this); + } + + @Override + public Set possibleTargets(UUID sourceId, UUID playerId, Game game) { + Set possibleTargets = super.possibleTargets(sourceId, playerId, game); + Cards alreadyTargeted = new CardsImpl(this.getTargets()); + alreadyTargeted.addAll(cards); + boolean hasBasic = alreadyTargeted + .getCards(game) + .stream() + .filter(Objects::nonNull) + .filter(MageObject::isLand) + .anyMatch(MageObject::isBasic); + possibleTargets.removeIf(uuid -> { + Card card = game.getCard(uuid); + return card != null + && hasBasic + && card.isLand() + && card.isBasic(); + }); + boolean hasYanggu = alreadyTargeted + .getCards(game) + .stream() + .filter(Objects::nonNull) + .map(MageObject::getName) + .anyMatch(name::equals); + possibleTargets.removeIf(uuid -> { + Card card = game.getCard(uuid); + return card != null + && hasYanggu + && name.equals(card.getName()); + }); + return possibleTargets; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KrosanVerge.java b/Mage.Sets/src/mage/cards/k/KrosanVerge.java index 860c646ef14..b96e4ee3f84 100644 --- a/Mage.Sets/src/mage/cards/k/KrosanVerge.java +++ b/Mage.Sets/src/mage/cards/k/KrosanVerge.java @@ -1,57 +1,46 @@ - package mage.cards.k; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; +import mage.abilities.dynamicvalue.common.SubTypeAssignment; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.mana.ColorlessManaAbility; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.game.Game; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KrosanVerge extends CardImpl { - private static final FilterCard filterForest = new FilterCard("a Forest"); - private static final FilterCard filterPlains = new FilterCard("a Plains"); - - static { - filterForest.add(SubType.FOREST.getPredicate()); - filterPlains.add(SubType.PLAINS.getPredicate()); - } - public KrosanVerge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // Krosan Verge enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); + // {tap}: Add {C}. this.addAbility(new ColorlessManaAbility()); + // {2}, {T}, Sacrifice Krosan Verge: Search your library for a Forest card and a Plains card and put them onto the battlefield tapped. Then shuffle your library. - Effect effect = new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filterForest), true, Outcome.PutLandInPlay); - effect.setText("Search your library for a Forest card and a Plains card and put them onto the battlefield tapped. Then shuffle your library"); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(2)); - effect = new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filterPlains), true, Outcome.PutLandInPlay); - effect.setText(null); - ability.addEffect(effect); + Ability ability = new SimpleActivatedAbility(new SearchLibraryPutInPlayEffect( + new KrosanVergeTarget(), true, Outcome.PutLandInPlay + ), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); - } public KrosanVerge(final KrosanVerge card) { @@ -63,3 +52,49 @@ public final class KrosanVerge extends CardImpl { return new KrosanVerge(this); } } + +class KrosanVergeTarget extends TargetCardInLibrary { + + private static final FilterCard filter + = new FilterCard("a Forest card and a Plains card"); + + static { + filter.add(Predicates.or( + SubType.FOREST.getPredicate(), + SubType.PLAINS.getPredicate() + )); + } + + private static final SubTypeAssignment subTypeAssigner + = new SubTypeAssignment(SubType.FOREST, SubType.PLAINS); + + KrosanVergeTarget() { + super(0, 2, filter); + } + + private KrosanVergeTarget(final KrosanVergeTarget target) { + super(target); + } + + @Override + public KrosanVergeTarget copy() { + return new KrosanVergeTarget(this); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { + return false; + } + Card card = game.getCard(id); + if (card == null) { + return false; + } + if (this.getTargets().isEmpty()) { + return true; + } + Cards cards = new CardsImpl(this.getTargets()); + cards.add(card); + return subTypeAssigner.getRoleCount(cards, game) >= cards.size(); + } +} diff --git a/Mage.Sets/src/mage/cards/p/ProteanHulk.java b/Mage.Sets/src/mage/cards/p/ProteanHulk.java index 30a2df42057..f192d34e864 100644 --- a/Mage.Sets/src/mage/cards/p/ProteanHulk.java +++ b/Mage.Sets/src/mage/cards/p/ProteanHulk.java @@ -1,40 +1,35 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.cards.*; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.ComparisonType; -import mage.constants.Outcome; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.Objects; +import java.util.UUID; + /** - * * @author emerald000 */ public final class ProteanHulk extends CardImpl { public ProteanHulk(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}"); this.subtype.add(SubType.BEAST); this.power = new MageInt(6); this.toughness = new MageInt(6); // When Protean Hulk dies, search your library for any number of creature cards with total converted mana cost 6 or less and put them onto the battlefield. Then shuffle your library. - this.addAbility(new DiesSourceTriggeredAbility(new ProteanHulkEffect())); + this.addAbility(new DiesSourceTriggeredAbility(new SearchLibraryPutInPlayEffect(new ProteanHulkTarget()))); } public ProteanHulk(final ProteanHulk card) { @@ -47,70 +42,35 @@ public final class ProteanHulk extends CardImpl { } } -class ProteanHulkEffect extends OneShotEffect { +class ProteanHulkTarget extends TargetCardInLibrary { - ProteanHulkEffect() { - super(Outcome.PutCreatureInPlay); - this.staticText = "search your library for any number of creature cards with total converted mana cost 6 or less and put them onto the battlefield. Then shuffle your library"; + private static final FilterCard filter + = new FilterCreatureCard("any number of creature cards with total converted mana cost 6 or less"); + + ProteanHulkTarget() { + super(0, Integer.MAX_VALUE, filter); } - ProteanHulkEffect(final ProteanHulkEffect effect) { - super(effect); + private ProteanHulkTarget(final ProteanHulkTarget target) { + super(target); } @Override - public ProteanHulkEffect copy() { - return new ProteanHulkEffect(this); + public ProteanHulkTarget copy() { + return new ProteanHulkTarget(this); } @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Cards cardsPicked = this.ProteanHulkSearch(game, source); - controller.moveCards(cardsPicked.getCards(game), Zone.BATTLEFIELD, source, game); - controller.shuffleLibrary(source, game); - return true; + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { + return false; } - return false; - } - - Cards ProteanHulkSearch(Game game, Ability source) { - Cards cardsPicked = new CardsImpl(); - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - GameEvent event = GameEvent.getEvent(GameEvent.EventType.SEARCH_LIBRARY, source.getControllerId(), source.getControllerId(), source.getControllerId(), Integer.MAX_VALUE); - if (!game.replaceEvent(event)) { - int manaCostLeftToFetch = 6; - int librarySearchLimit = event.getAmount(); - - FilterCard filter = new FilterCreatureCard("number of creature cards with total converted mana cost 6 or less (6 CMC left)"); - filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, manaCostLeftToFetch + 1)); - TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); - target.setCardLimit(librarySearchLimit); - - while (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - target.choose(Outcome.PutCreatureInPlay, source.getControllerId(), source.getControllerId(), game); - Card card = player.getLibrary().remove(target.getFirstTarget(), game); - if (card == null) { - break; - } - cardsPicked.add(card); - game.getState().getLookedAt(source.getControllerId()).add("Protean Hulk", cardsPicked); - - librarySearchLimit--; - if (librarySearchLimit == 0) { - break; - } - manaCostLeftToFetch -= card.getConvertedManaCost(); - filter = new FilterCreatureCard("number of creature cards with total converted mana cost 6 or less (" + manaCostLeftToFetch + " CMC left)"); - filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, manaCostLeftToFetch + 1)); - target = new TargetCardInLibrary(0, 1, filter); - target.setCardLimit(librarySearchLimit); - } - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LIBRARY_SEARCHED, source.getControllerId(), source.getControllerId())); - } + Card card = game.getCard(id); + if (card == null) { + return false; } - return cardsPicked; + Cards cards = new CardsImpl(this.getTargets()); + cards.add(id); + return cards.getCards(game).stream().filter(Objects::nonNull).mapToInt(MageObject::getConvertedManaCost).sum() <= 6; } } diff --git a/Mage.Sets/src/mage/cards/s/ShardConvergence.java b/Mage.Sets/src/mage/cards/s/ShardConvergence.java index 5d447429c5e..b9dd12a44bd 100644 --- a/Mage.Sets/src/mage/cards/s/ShardConvergence.java +++ b/Mage.Sets/src/mage/cards/s/ShardConvergence.java @@ -1,35 +1,31 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.abilities.dynamicvalue.common.SubTypeAssignment; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.*; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.common.FilterLandCard; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author Loki */ public final class ShardConvergence extends CardImpl { public ShardConvergence(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); // Search your library for a Plains card, an Island card, a Swamp card, and a Mountain card. Reveal those cards and put them into your hand. Then shuffle your library. - this.getSpellAbility().addEffect(new ShardConvergenceEffect()); + this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect( + new ShardConvergenceTarget(), true + )); } public ShardConvergence(final ShardConvergence card) { @@ -42,51 +38,54 @@ public final class ShardConvergence extends CardImpl { } } -class ShardConvergenceEffect extends OneShotEffect { - ShardConvergenceEffect() { - super(Outcome.DrawCard); - staticText = "Search your library for a Plains card, an Island card, a Swamp card, and a Mountain card. Reveal those cards and put them into your hand. Then shuffle your library"; +class ShardConvergenceTarget extends TargetCardInLibrary { + + private static final FilterCard filter + = new FilterCard("a Plains card, an Island card, a Swamp card, and a Mountain card"); + + static { + filter.add(Predicates.or( + SubType.PLAINS.getPredicate(), + SubType.ISLAND.getPredicate(), + SubType.SWAMP.getPredicate(), + SubType.MOUNTAIN.getPredicate() + )); } - ShardConvergenceEffect(final ShardConvergenceEffect effect) { - super(effect); + private static final SubTypeAssignment subTypeAssigner = new SubTypeAssignment( + SubType.PLAINS, + SubType.ISLAND, + SubType.SWAMP, + SubType.MOUNTAIN + ); + + ShardConvergenceTarget() { + super(0, 4, filter); + } + + private ShardConvergenceTarget(final ShardConvergenceTarget target) { + super(target); } @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { + public ShardConvergenceTarget copy() { + return new ShardConvergenceTarget(this); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { return false; } - - Cards cards = new CardsImpl(); - - searchLand(player, source, game, cards, "Plains"); - searchLand(player, source, game, cards, "Island"); - searchLand(player, source, game, cards, "Swamp"); - searchLand(player, source, game, cards, "Mountain"); - - player.revealCards("Shard Convergence", cards, game); - player.shuffleLibrary(source, game); - - return true; - } - - private void searchLand(Player player, Ability source, Game game, Cards cards, String subtype) { - FilterLandCard filter = new FilterLandCard(subtype); - filter.add(SubType.byDescription(subtype).getPredicate()); - TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, source, game)) { - Card card = player.getLibrary().remove(target.getFirstTarget(), game); - if (card != null) { - card.moveToZone(Zone.HAND, source.getSourceId(), game, false); - cards.add(card); - } + Card card = game.getCard(id); + if (card == null) { + return false; } + if (this.getTargets().isEmpty()) { + return true; + } + Cards cards = new CardsImpl(this.getTargets()); + cards.add(card); + return subTypeAssigner.getRoleCount(cards, game) >= cards.size(); } - - @Override - public ShardConvergenceEffect copy() { - return new ShardConvergenceEffect(this); - } -} \ No newline at end of file +}