mirror of
https://github.com/magefree/mage.git
synced 2026-01-19 01:39:58 -08:00
add some new cardutil stuff
This commit is contained in:
parent
c07b9680bd
commit
b9b69586dc
3 changed files with 111 additions and 129 deletions
|
|
@ -1,7 +1,6 @@
|
|||
package mage.cards.c;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.condition.Condition;
|
||||
|
|
@ -19,9 +18,6 @@ import mage.game.Game;
|
|||
import mage.game.permanent.token.Construct4Token;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
|
|
@ -66,16 +62,11 @@ enum ChromeReplicatorCondition implements Condition {
|
|||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Map<String, Integer> nameMap = new HashMap<>();
|
||||
return game
|
||||
.getBattlefield()
|
||||
.getActivePermanents(
|
||||
filter, source.getControllerId(), source, game
|
||||
).stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(MageObject::getName)
|
||||
.filter(Objects::nonNull)
|
||||
.filter(s -> !s.isEmpty())
|
||||
.anyMatch(s -> nameMap.compute(s, CardUtil::setOrIncrementValue) >= 2);
|
||||
return CardUtil
|
||||
.checkAnyPairs(
|
||||
game.getBattlefield().getActivePermanents(
|
||||
filter, source.getControllerId(), source, game
|
||||
), (p1, p2) -> p1.sharesName(p2, game)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,22 +6,21 @@ import mage.abilities.common.SimpleActivatedAbility;
|
|||
import mage.abilities.costs.common.DiscardTargetCost;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.*;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterNonlandCard;
|
||||
import mage.filter.predicate.mageobject.NamePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInHand;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
|
|
@ -39,9 +38,9 @@ public final class SphinxOfTheChimes extends CardImpl {
|
|||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// Discard two nonland cards with the same name: Draw four cards.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(4), new DiscardTwoNonlandCardsWithTheSameNameCost());
|
||||
this.addAbility(ability);
|
||||
|
||||
this.addAbility(new SimpleActivatedAbility(
|
||||
new DrawCardSourceControllerEffect(4), new DiscardTargetCost(new SphinxOfTheChimesTarget())
|
||||
));
|
||||
}
|
||||
|
||||
private SphinxOfTheChimes(final SphinxOfTheChimes card) {
|
||||
|
|
@ -54,122 +53,54 @@ public final class SphinxOfTheChimes extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class DiscardTwoNonlandCardsWithTheSameNameCost extends DiscardTargetCost {
|
||||
class SphinxOfTheChimesTarget extends TargetCardInHand {
|
||||
|
||||
public DiscardTwoNonlandCardsWithTheSameNameCost() {
|
||||
super(new TargetTwoNonLandCardsWithSameNameInHand());
|
||||
private static final FilterCard filter = new FilterNonlandCard("nonland cards with the same name");
|
||||
|
||||
public SphinxOfTheChimesTarget() {
|
||||
super(2, 2, filter);
|
||||
}
|
||||
|
||||
private DiscardTwoNonlandCardsWithTheSameNameCost(final DiscardTwoNonlandCardsWithTheSameNameCost cost) {
|
||||
super(cost);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscardTwoNonlandCardsWithTheSameNameCost copy() {
|
||||
return new DiscardTwoNonlandCardsWithTheSameNameCost(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand {
|
||||
|
||||
public TargetTwoNonLandCardsWithSameNameInHand() {
|
||||
super(2, 2, new FilterNonlandCard("nonland cards with the same name"));
|
||||
}
|
||||
|
||||
private TargetTwoNonLandCardsWithSameNameInHand(final TargetTwoNonLandCardsWithSameNameInHand target) {
|
||||
private SphinxOfTheChimesTarget(final SphinxOfTheChimesTarget target) {
|
||||
super(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Game game) {
|
||||
Set<UUID> newPossibleTargets = new HashSet<>();
|
||||
Set<UUID> possibleTargets = new HashSet<>();
|
||||
Player player = game.getPlayer(sourceControllerId);
|
||||
if (player == null) {
|
||||
return newPossibleTargets;
|
||||
}
|
||||
for (Card card : player.getHand().getCards(filter, game)) {
|
||||
possibleTargets.add(card.getId());
|
||||
}
|
||||
|
||||
Cards cardsToCheck = new CardsImpl();
|
||||
cardsToCheck.addAll(possibleTargets);
|
||||
if (targets.size() == 1) {
|
||||
// first target is laready chosen, now only targets with the same name are selectable
|
||||
for (Map.Entry<UUID, Integer> entry : targets.entrySet()) {
|
||||
Card chosenCard = cardsToCheck.get(entry.getKey(), game);
|
||||
if (chosenCard != null) {
|
||||
for (UUID cardToCheck : cardsToCheck) {
|
||||
if (!cardToCheck.equals(chosenCard.getId()) && chosenCard.getName().equals(game.getCard(cardToCheck).getName())) {
|
||||
newPossibleTargets.add(cardToCheck);
|
||||
}
|
||||
}
|
||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
switch (this.getTargets().size()) {
|
||||
case 0:
|
||||
if (possibleTargets.size() < 2) {
|
||||
possibleTargets.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (UUID cardToCheck : cardsToCheck) {
|
||||
Card card = game.getCard(cardToCheck);
|
||||
if (card != null) {
|
||||
String nameToSearch = CardUtil.getCardNameForSameNameSearch(card);
|
||||
FilterCard nameFilter = new FilterCard();
|
||||
nameFilter.add(new NamePredicate(nameToSearch));
|
||||
|
||||
if (cardsToCheck.count(nameFilter, game) > 1) {
|
||||
newPossibleTargets.add(cardToCheck);
|
||||
}
|
||||
}
|
||||
}
|
||||
Set<UUID> set = CardUtil
|
||||
.streamPairsWithMap(
|
||||
possibleTargets,
|
||||
(u1, u2) -> game.getCard(u1).sharesName(game.getCard(u2), game)
|
||||
? Stream.of(u1, u2)
|
||||
: Stream.<UUID>empty()
|
||||
)
|
||||
.flatMap(Function.identity())
|
||||
.collect(Collectors.toSet());
|
||||
possibleTargets.clear();
|
||||
possibleTargets.addAll(set);
|
||||
break;
|
||||
case 1:
|
||||
possibleTargets.removeIf(
|
||||
uuid -> !game
|
||||
.getCard(uuid)
|
||||
.sharesName(game.getCard(this.getTargets().get(0)), game)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
possibleTargets.clear();
|
||||
}
|
||||
return newPossibleTargets;
|
||||
return possibleTargets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canChoose(UUID sourceControllerId, Game game) {
|
||||
Cards cardsToCheck = new CardsImpl();
|
||||
Player player = game.getPlayer(sourceControllerId);
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
for (Card card : player.getHand().getCards(filter, game)) {
|
||||
cardsToCheck.add(card.getId());
|
||||
}
|
||||
int possibleCards = 0;
|
||||
for (Card card : cardsToCheck.getCards(game)) {
|
||||
String nameToSearch = CardUtil.getCardNameForSameNameSearch(card);
|
||||
FilterCard nameFilter = new FilterCard();
|
||||
nameFilter.add(new NamePredicate(nameToSearch));
|
||||
|
||||
if (cardsToCheck.count(nameFilter, game) > 1) {
|
||||
++possibleCards;
|
||||
}
|
||||
}
|
||||
return possibleCards > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTarget(UUID id, Game game) {
|
||||
if (super.canTarget(id, game)) {
|
||||
Card card = game.getCard(id);
|
||||
if (card != null) {
|
||||
if (targets.size() == 1) {
|
||||
Card card2 = game.getCard(targets.entrySet().iterator().next().getKey());
|
||||
return CardUtil.haveSameNames(card2, card);
|
||||
} else {
|
||||
String nameToSearch = CardUtil.getCardNameForSameNameSearch(card);
|
||||
FilterCard nameFilter = new FilterCard();
|
||||
nameFilter.add(new NamePredicate(nameToSearch));
|
||||
|
||||
Player player = game.getPlayer(card.getOwnerId());
|
||||
return player != null && player.getHand().getCards(nameFilter, game).size() > 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetTwoNonLandCardsWithSameNameInHand copy() {
|
||||
return new TargetTwoNonLandCardsWithSameNameInHand(this);
|
||||
public SphinxOfTheChimesTarget copy() {
|
||||
return new SphinxOfTheChimesTarget(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ import java.net.URLDecoder;
|
|||
import java.net.URLEncoder;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.*;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.ToIntFunction;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
|
@ -2167,6 +2169,64 @@ public final class CardUtil {
|
|||
return stream.filter(clazz::isInstance).map(clazz::cast).filter(Objects::nonNull);
|
||||
}
|
||||
|
||||
private static class IntPairIterator implements Iterator<AbstractMap.SimpleImmutableEntry<Integer, Integer>> {
|
||||
private final int amount;
|
||||
private int firstCounter = 0;
|
||||
private int secondCounter = 1;
|
||||
|
||||
IntPairIterator(int amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return firstCounter + 1 < amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractMap.SimpleImmutableEntry<Integer, Integer> next() {
|
||||
AbstractMap.SimpleImmutableEntry<Integer, Integer> value
|
||||
= new AbstractMap.SimpleImmutableEntry(firstCounter, secondCounter);
|
||||
secondCounter++;
|
||||
if (secondCounter == amount) {
|
||||
firstCounter++;
|
||||
secondCounter = firstCounter + 1;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public int getMax() {
|
||||
// amount choose 2
|
||||
return (amount * amount - amount) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> boolean checkAnyPairs(Collection<T> collection, BiPredicate<T, T> predicate) {
|
||||
return streamPairsWithMap(collection, (t1, t2) -> predicate.test(t1, t2)).anyMatch(x -> x);
|
||||
}
|
||||
|
||||
public static <T, U> Stream<U> streamPairsWithMap(
|
||||
Collection<T> collection,
|
||||
BiFunction<T, T, U> function) {
|
||||
if (collection.size() < 2) {
|
||||
return Stream.empty();
|
||||
}
|
||||
List<T> list;
|
||||
if (collection instanceof List) {
|
||||
list = (List<T>) collection;
|
||||
} else {
|
||||
list = new ArrayList<>(collection);
|
||||
}
|
||||
IntPairIterator it = new IntPairIterator(list.size());
|
||||
return Stream
|
||||
.generate(it::next)
|
||||
.limit(it.getMax())
|
||||
.map(pair -> function.apply(
|
||||
list.get(pair.getKey()),
|
||||
list.get(pair.getValue())
|
||||
));
|
||||
}
|
||||
|
||||
public static void AssertNoControllerOwnerPredicates(Target target) {
|
||||
List<Predicate> list = new ArrayList<>();
|
||||
Predicates.collectAllComponents(target.getFilter().getPredicates(), target.getFilter().getExtraPredicates(), list);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue