diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 9a746d7009b..5a194a2bbe9 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -28,7 +28,10 @@ import mage.choices.Choice; import mage.constants.CardType; import mage.constants.Rarity; import mage.constants.SubType; +import mage.constants.TargetController; import mage.filter.Filter; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; import mage.game.command.Dungeon; import mage.game.command.Plane; import mage.game.draft.DraftCube; @@ -2064,6 +2067,25 @@ public class VerifyCardDataTest { } } + // special check: equip abilities must have controlled predicate due rules + List equipAbilities = card.getAbilities() + .stream() + .filter(a -> a instanceof EquipAbility) + .map(a -> (EquipAbility) a) + .collect(Collectors.toList()); + equipAbilities.forEach(a -> { + List allPredicates = new ArrayList<>(); + a.getTargets().forEach(t -> Predicates.collectAllComponents(t.getFilter().getPredicates(), t.getFilter().getExtraPredicates(), allPredicates)); + boolean hasControlledFilter = allPredicates + .stream() + .filter(p -> p instanceof TargetController.ControllerPredicate) + .map(p -> ((TargetController.ControllerPredicate) p).getController()) + .anyMatch(tc -> tc.equals(TargetController.YOU)); + if (!hasControlledFilter) { + fail(card, "abilities", "card has equip ability, but it doesn't use controllered filter - " + a.getRule()); + } + }); + // spells have only 1 ability if (card.isInstantOrSorcery()) { return; diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java index e6851731190..015028a6ac2 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java @@ -452,7 +452,7 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu // wait dependency // extraPredicates from some filters is player related, you don't need it here List list = new ArrayList<>(); - Predicates.collectAllComponents(filter.getPredicates(), list); + Predicates.collectAllComponents(filter.getPredicates(), filter.getExtraPredicates(), list); if (list.stream().anyMatch(SubType.SubTypePredicate.class::isInstance)) { this.addDependedToType(DependencyType.AddingCreatureType); } diff --git a/Mage/src/main/java/mage/constants/TargetController.java b/Mage/src/main/java/mage/constants/TargetController.java index bfd0e04255b..ffd672f28f8 100644 --- a/Mage/src/main/java/mage/constants/TargetController.java +++ b/Mage/src/main/java/mage/constants/TargetController.java @@ -182,7 +182,14 @@ public enum TargetController { @Override public String toString() { - return "TargetController(" + controller.toString() + ')'; + return "TargetController (" + controller.toString() + ')'; + } + + /** + * For tests + */ + public TargetController getController() { + return this.controller; } } } diff --git a/Mage/src/main/java/mage/filter/Filter.java b/Mage/src/main/java/mage/filter/Filter.java index 8ed5e6dd831..90486321ab9 100644 --- a/Mage/src/main/java/mage/filter/Filter.java +++ b/Mage/src/main/java/mage/filter/Filter.java @@ -5,6 +5,7 @@ import mage.game.Game; import mage.util.Copyable; import java.io.Serializable; +import java.util.ArrayList; import java.util.List; /** @@ -35,4 +36,8 @@ public interface Filter extends Serializable, Copyable> { public void setLockedFilter(boolean lockedFilter); List> getPredicates(); + + default List getExtraPredicates() { + return new ArrayList<>(); + } } diff --git a/Mage/src/main/java/mage/filter/FilterCard.java b/Mage/src/main/java/mage/filter/FilterCard.java index d9b2f18d142..c4d2f98183c 100644 --- a/Mage/src/main/java/mage/filter/FilterCard.java +++ b/Mage/src/main/java/mage/filter/FilterCard.java @@ -91,12 +91,17 @@ public class FilterCard extends FilterObject { return new FilterCard(this); } + @Override + public List getExtraPredicates() { + return new ArrayList<>(extraPredicates); + } + public static void checkPredicateIsSuitableForCardFilter(Predicate predicate) { // card filter can't contain controller predicate (only permanents on battlefield have controller) List list = new ArrayList<>(); Predicates.collectAllComponents(predicate, list); if (list.stream().anyMatch(TargetController.ControllerPredicate.class::isInstance)) { - throw new IllegalArgumentException("Card filter doesn't support controller predicate"); + throw new IllegalArgumentException("Wrong code usage: card filter doesn't support controller predicate"); } } diff --git a/Mage/src/main/java/mage/filter/FilterPermanent.java b/Mage/src/main/java/mage/filter/FilterPermanent.java index 03307604b51..0177accc9f8 100644 --- a/Mage/src/main/java/mage/filter/FilterPermanent.java +++ b/Mage/src/main/java/mage/filter/FilterPermanent.java @@ -4,6 +4,7 @@ import mage.abilities.Ability; import mage.constants.SubType; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.permanent.Permanent; @@ -11,6 +12,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author North @@ -69,4 +71,9 @@ public class FilterPermanent extends FilterObject implements FilterIn public FilterPermanent copy() { return new FilterPermanent(this); } + + @Override + public List getExtraPredicates() { + return new ArrayList<>(extraPredicates); + } } diff --git a/Mage/src/main/java/mage/filter/FilterPlayer.java b/Mage/src/main/java/mage/filter/FilterPlayer.java index 4fbb9063d5f..0fa56b3a2a7 100644 --- a/Mage/src/main/java/mage/filter/FilterPlayer.java +++ b/Mage/src/main/java/mage/filter/FilterPlayer.java @@ -3,6 +3,7 @@ package mage.filter; import mage.abilities.Ability; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.Predicate; import mage.game.Game; import mage.players.Player; @@ -56,4 +57,9 @@ public class FilterPlayer extends FilterImpl { public FilterPlayer copy() { return new FilterPlayer(this); } + + @Override + public List getExtraPredicates() { + return new ArrayList<>(extraPredicates); + } } diff --git a/Mage/src/main/java/mage/filter/FilterStackObject.java b/Mage/src/main/java/mage/filter/FilterStackObject.java index 6035fbe7b33..bfdd56d54fd 100644 --- a/Mage/src/main/java/mage/filter/FilterStackObject.java +++ b/Mage/src/main/java/mage/filter/FilterStackObject.java @@ -3,6 +3,7 @@ package mage.filter; import mage.abilities.Ability; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.stack.StackObject; @@ -49,4 +50,9 @@ public class FilterStackObject extends FilterObject { public FilterStackObject copy() { return new FilterStackObject(this); } + + @Override + public List getExtraPredicates() { + return new ArrayList<>(extraPredicates); + } } diff --git a/Mage/src/main/java/mage/filter/predicate/Predicates.java b/Mage/src/main/java/mage/filter/predicate/Predicates.java index 859e46cd683..0f2a0c9cbbd 100644 --- a/Mage/src/main/java/mage/filter/predicate/Predicates.java +++ b/Mage/src/main/java/mage/filter/predicate/Predicates.java @@ -232,17 +232,18 @@ public final class Predicates { if (predicate instanceof NotPredicate) { collectAllComponents(((NotPredicate) predicate).predicate, res); } else if (predicate instanceof AndPredicate) { - collectAllComponents(((AndPredicate) predicate).components, res); + collectAllComponents(((AndPredicate) predicate).components, null, res); } else if (predicate instanceof OrPredicate) { - collectAllComponents(((OrPredicate) predicate).components, res); + collectAllComponents(((OrPredicate) predicate).components, null, res); } else { res.add(predicate); } } - public static void collectAllComponents(List predicates, List res) { - predicates.forEach(p -> { - collectAllComponents(p, res); - }); + public static void collectAllComponents(List predicates, List extraPredicates, List res) { + predicates.forEach(p -> collectAllComponents(p, res)); + if (extraPredicates != null) { + extraPredicates.forEach(p -> collectAllComponents(p, res)); + } } }