mirror of
https://github.com/correl/mage.git
synced 2025-01-12 11:08:01 +00:00
reworked Gaea's Balance, broke out main party count algorithm for more general use
This commit is contained in:
parent
e3733dfae7
commit
a6300e30e5
4 changed files with 163 additions and 123 deletions
|
@ -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<FilterCard> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<T> {
|
||||
|
||||
protected final List<T> attributes = new ArrayList<>();
|
||||
|
||||
protected RoleAssignment(T... attributes) {
|
||||
for (T attribute : attributes) {
|
||||
this.attributes.add(attribute);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Set<T> makeSet(Card card, Game game);
|
||||
|
||||
private boolean attemptRearrange(T attribute, UUID uuid, Set<T> attributes, Map<T, UUID> attributeUUIDMap, Map<UUID, Set<T>> attributeSetMap) {
|
||||
UUID uuid1 = attributeUUIDMap.get(attribute);
|
||||
if (uuid1 == null) {
|
||||
return false;
|
||||
}
|
||||
Set<T> 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<UUID, Set<T>> attributeMap = new HashMap<>();
|
||||
cards.getCards(game).forEach(card -> attributeMap.put(card.getId(), this.makeSet(card, game)));
|
||||
if (attributeMap.size() < 2) {
|
||||
return attributeMap.size();
|
||||
}
|
||||
Set<T> availableTypes = attributeMap
|
||||
.values()
|
||||
.stream()
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toSet());
|
||||
if (attributeMap.size() == 2) {
|
||||
return Math.min(2, availableTypes.size());
|
||||
}
|
||||
Map<T, UUID> attributeUUIDMap = new HashMap<>();
|
||||
for (Map.Entry<UUID, Set<T>> 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();
|
||||
}
|
||||
}
|
|
@ -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<SubType> partyTypes = Arrays.asList(
|
||||
private static final SubTypeAssignment subTypeAssigner = new SubTypeAssignment(
|
||||
SubType.CLERIC,
|
||||
SubType.ROGUE,
|
||||
SubType.WARRIOR,
|
||||
SubType.WIZARD
|
||||
);
|
||||
|
||||
private static Set<SubType> makeSet(Permanent permanent, Game game) {
|
||||
Set<SubType> 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<SubType> creatureTypes, Map<SubType, UUID> subTypeUUIDMap, Map<UUID, Set<SubType>> creatureTypesMap) {
|
||||
UUID uuid1 = subTypeUUIDMap.get(subType);
|
||||
if (uuid1 == null) {
|
||||
return false;
|
||||
}
|
||||
Set<SubType> 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<UUID, Set<SubType>> 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<SubType> availableTypes = creatureTypesMap
|
||||
.values()
|
||||
.stream()
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toSet());
|
||||
if (creatureTypesMap.size() == 2) {
|
||||
return Math.min(2, availableTypes.size());
|
||||
}
|
||||
Map<SubType, UUID> subTypeUUIDMap = new HashMap<>();
|
||||
for (Map.Entry<UUID, Set<SubType>> 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
|
||||
|
|
|
@ -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<SubType> {
|
||||
|
||||
public SubTypeAssignment(SubType... subTypes) {
|
||||
super(subTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<SubType> makeSet(Card card, Game game) {
|
||||
return attributes
|
||||
.stream()
|
||||
.filter(subType -> card.hasSubtype(subType, game))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue