diff --git a/Mage.Sets/src/mage/cards/g/GaeasBalance.java b/Mage.Sets/src/mage/cards/g/GaeasBalance.java index 58d20cabd32..624f8541c35 100644 --- a/Mage.Sets/src/mage/cards/g/GaeasBalance.java +++ b/Mage.Sets/src/mage/cards/g/GaeasBalance.java @@ -2,25 +2,19 @@ package mage.cards.g; import mage.abilities.Ability; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.OneShotEffect; -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.SearchLibraryPutInPlayEffect; +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.StaticFilters; import mage.filter.common.FilterLandCard; +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.Arrays; -import java.util.List; import java.util.UUID; /** @@ -37,7 +31,7 @@ public final class GaeasBalance extends CardImpl { )); // Search your library for a land card of each basic land type and put them onto the battlefield. Then shuffle your library. - this.getSpellAbility().addEffect(new GaeasBalanceEffect()); + this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect(new GaeasBalanceTarget())); } private GaeasBalance(final GaeasBalance card) { @@ -50,54 +44,55 @@ public final class GaeasBalance extends CardImpl { } } -class GaeasBalanceEffect extends OneShotEffect { +class GaeasBalanceTarget extends TargetCardInLibrary { - private static final FilterCard plainsFilter = new FilterLandCard("a Plains land card"); - private static final FilterCard islandFilter = new FilterLandCard("an Island land card"); - private static final FilterCard swampFilter = new FilterLandCard("a Swamp land card"); - private static final FilterCard mountainFilter = new FilterLandCard("a Mountain land card"); - private static final FilterCard forestFilter = new FilterLandCard("a Forest land card"); + private static final FilterCard filter = new FilterLandCard("a land card of each basic land type"); static { - plainsFilter.add(SubType.PLAINS.getPredicate()); - islandFilter.add(SubType.ISLAND.getPredicate()); - swampFilter.add(SubType.SWAMP.getPredicate()); - mountainFilter.add(SubType.MOUNTAIN.getPredicate()); - forestFilter.add(SubType.FOREST.getPredicate()); + filter.add(Predicates.or( + SubType.PLAINS.getPredicate(), + SubType.ISLAND.getPredicate(), + SubType.SWAMP.getPredicate(), + SubType.MOUNTAIN.getPredicate(), + SubType.FOREST.getPredicate() + )); } - private static final List filterList = Arrays.asList( - plainsFilter, islandFilter, swampFilter, mountainFilter, forestFilter + private static final SubTypeAssignment subTypeAssigner = new SubTypeAssignment( + SubType.PLAINS, + SubType.ISLAND, + SubType.SWAMP, + SubType.MOUNTAIN, + SubType.FOREST ); - GaeasBalanceEffect() { - super(Outcome.Benefit); - staticText = "Search your library for a land card of each basic land type " + - "and put them onto the battlefield. Then shuffle your library."; + GaeasBalanceTarget() { + super(0, 5, filter); } - private GaeasBalanceEffect(final GaeasBalanceEffect effect) { - super(effect); + private GaeasBalanceTarget(final GaeasBalanceTarget target) { + super(target); } @Override - public GaeasBalanceEffect copy() { - return new GaeasBalanceEffect(this); + public GaeasBalanceTarget copy() { + return new GaeasBalanceTarget(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(); - filterList.stream().map(TargetCardInLibrary::new).forEachOrdered(target -> { - player.searchLibrary(target, source, game, target.getFilter().getMessage().contains("Forest")); - cards.add(target.getFirstTarget()); - }); - player.moveCards(cards, Zone.BATTLEFIELD, source, game); - player.shuffleLibrary(source, game); - return true; + 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(); } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/RoleAssignment.java b/Mage/src/main/java/mage/abilities/dynamicvalue/RoleAssignment.java new file mode 100644 index 00000000000..c49ac9d232b --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/RoleAssignment.java @@ -0,0 +1,93 @@ +package mage.abilities.dynamicvalue; + +import mage.cards.Card; +import mage.cards.Cards; +import mage.game.Game; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Used for when you need to know how attributes are assigned among cards, such as for party count + * Can be adapted for various card attributes + * + * @author TheElk801 + */ +public abstract class RoleAssignment { + + protected final List attributes = new ArrayList<>(); + + protected RoleAssignment(T... attributes) { + for (T attribute : attributes) { + this.attributes.add(attribute); + } + } + + protected abstract Set makeSet(Card card, Game game); + + private boolean attemptRearrange(T attribute, UUID uuid, Set attributes, Map attributeUUIDMap, Map> attributeSetMap) { + UUID uuid1 = attributeUUIDMap.get(attribute); + if (uuid1 == null) { + return false; + } + Set attributes1 = attributeSetMap.get(uuid1); + for (T attribute1 : attributes1) { + if (attribute == attribute1) { + continue; + } + if (!attributeUUIDMap.containsKey(attribute1)) { + attributeUUIDMap.put(attribute, uuid); + attributeUUIDMap.put(attribute1, uuid1); + return true; + } + } + for (T attribute1 : attributes1) { + if (attribute == attribute1) { + continue; + } + if (attemptRearrange(attribute1, uuid1, attributes, attributeUUIDMap, attributeSetMap)) { + attributeUUIDMap.put(attribute, uuid); + attributeUUIDMap.put(attribute1, uuid1); + return true; + } + } + return false; + } + + public int getRoleCount(Cards cards, Game game) { + Map> attributeMap = new HashMap<>(); + cards.getCards(game).forEach(card -> attributeMap.put(card.getId(), this.makeSet(card, game))); + if (attributeMap.size() < 2) { + return attributeMap.size(); + } + Set availableTypes = attributeMap + .values() + .stream() + .flatMap(Collection::stream) + .collect(Collectors.toSet()); + if (attributeMap.size() == 2) { + return Math.min(2, availableTypes.size()); + } + Map attributeUUIDMap = new HashMap<>(); + for (Map.Entry> entry : attributeMap.entrySet()) { + for (T attribute : entry.getValue()) { + if (!attributeUUIDMap.containsKey(attribute)) { + attributeUUIDMap.put(attribute, entry.getKey()); + break; + } + } + if (attributeUUIDMap.size() >= availableTypes.size()) { + return attributeUUIDMap.size(); + } else if (attributeUUIDMap.containsValue(entry.getKey())) { + continue; + } else { + for (T attribute : entry.getValue()) { + if (attemptRearrange(attribute, entry.getKey(), entry.getValue(), attributeUUIDMap, attributeMap)) { + break; + } + } + } + } + return attributeUUIDMap.keySet().size(); + } +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PartyCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PartyCount.java index 5c79e4535c3..7c732321273 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PartyCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PartyCount.java @@ -3,14 +3,14 @@ package mage.abilities.dynamicvalue.common; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.game.Game; -import mage.game.permanent.Permanent; -import java.util.*; import java.util.stream.Collectors; /** @@ -29,92 +29,20 @@ public enum PartyCount implements DynamicValue { )); } - private static final List partyTypes = Arrays.asList( + private static final SubTypeAssignment subTypeAssigner = new SubTypeAssignment( SubType.CLERIC, SubType.ROGUE, SubType.WARRIOR, SubType.WIZARD ); - private static Set makeSet(Permanent permanent, Game game) { - Set subTypeSet = new HashSet<>(); - for (SubType subType : partyTypes) { - if (permanent.hasSubtype(subType, game)) { - subTypeSet.add(subType); - } - } - return subTypeSet; - } - - private static boolean attemptRearrange(SubType subType, UUID uuid, Set creatureTypes, Map subTypeUUIDMap, Map> creatureTypesMap) { - UUID uuid1 = subTypeUUIDMap.get(subType); - if (uuid1 == null) { - return false; - } - Set creatureTypes1 = creatureTypesMap.get(uuid1); - for (SubType subType1 : creatureTypes1) { - if (subType == subType1) { - continue; - } - if (!subTypeUUIDMap.containsKey(subType1)) { - subTypeUUIDMap.put(subType, uuid); - subTypeUUIDMap.put(subType1, uuid1); - return true; - } - } - for (SubType subType1 : creatureTypes1) { - if (subType == subType1) { - continue; - } - if (attemptRearrange(subType1, uuid1, creatureTypes, subTypeUUIDMap, creatureTypesMap)) { - subTypeUUIDMap.put(subType, uuid); - subTypeUUIDMap.put(subType1, uuid1); - return true; - } - } - return false; - } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - Map> creatureTypesMap = new HashMap<>(); - game.getBattlefield() - .getActivePermanents( - filter, sourceAbility.getControllerId(), sourceAbility.getSourceId(), game - ).stream() - .forEach(permanent -> creatureTypesMap.put(permanent.getId(), makeSet(permanent, game))); - if (creatureTypesMap.size() < 2) { - return creatureTypesMap.size(); - } - Set availableTypes = creatureTypesMap - .values() - .stream() - .flatMap(Collection::stream) - .collect(Collectors.toSet()); - if (creatureTypesMap.size() == 2) { - return Math.min(2, availableTypes.size()); - } - Map subTypeUUIDMap = new HashMap<>(); - for (Map.Entry> entry : creatureTypesMap.entrySet()) { - for (SubType subType : entry.getValue()) { - if (!subTypeUUIDMap.containsKey(subType)) { - subTypeUUIDMap.put(subType, entry.getKey()); - break; - } - } - if (subTypeUUIDMap.size() >= availableTypes.size()) { - return subTypeUUIDMap.size(); - } else if (subTypeUUIDMap.containsValue(entry.getKey())) { - continue; - } else { - for (SubType subType : entry.getValue()) { - if (attemptRearrange(subType, entry.getKey(), entry.getValue(), subTypeUUIDMap, creatureTypesMap)) { - break; - } - } - } - } - return subTypeUUIDMap.keySet().size(); + Cards cards = new CardsImpl(game.getBattlefield().getActivePermanents( + filter, sourceAbility.getControllerId(), sourceAbility.getSourceId(), game + ).stream().collect(Collectors.toSet())); + return subTypeAssigner.getRoleCount(cards, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SubTypeAssignment.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SubTypeAssignment.java new file mode 100644 index 00000000000..b35177725cc --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SubTypeAssignment.java @@ -0,0 +1,24 @@ +package mage.abilities.dynamicvalue.common; + +import mage.abilities.dynamicvalue.RoleAssignment; +import mage.cards.Card; +import mage.constants.SubType; +import mage.game.Game; + +import java.util.Set; +import java.util.stream.Collectors; + +public class SubTypeAssignment extends RoleAssignment { + + public SubTypeAssignment(SubType... subTypes) { + super(subTypes); + } + + @Override + protected Set makeSet(Card card, Game game) { + return attributes + .stream() + .filter(subType -> card.hasSubtype(subType, game)) + .collect(Collectors.toSet()); + } +}