diff --git a/Mage.Sets/src/mage/cards/b/BrutalExpulsion.java b/Mage.Sets/src/mage/cards/b/BrutalExpulsion.java index 8eec6a17a4a..64066e1d184 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalExpulsion.java +++ b/Mage.Sets/src/mage/cards/b/BrutalExpulsion.java @@ -10,7 +10,6 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterSpellOrPermanent; import mage.target.common.TargetCreatureOrPlaneswalker; import mage.target.common.TargetSpellOrPermanent; @@ -26,7 +25,7 @@ public final class BrutalExpulsion extends CardImpl { private static final FilterSpellOrPermanent filter = new FilterSpellOrPermanent("spell or creature"); static { - filter.setPermanentFilter(new FilterCreaturePermanent()); + filter.getPermanentFilter().add(CardType.CREATURE.getPredicate()); } public BrutalExpulsion(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CommitMemory.java b/Mage.Sets/src/mage/cards/c/CommitMemory.java index 0c5f6b523ca..49e3cdc7e8a 100644 --- a/Mage.Sets/src/mage/cards/c/CommitMemory.java +++ b/Mage.Sets/src/mage/cards/c/CommitMemory.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -13,16 +12,17 @@ import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SpellAbilityType; -import mage.filter.common.FilterNonlandPermanent; import mage.filter.common.FilterSpellOrPermanent; +import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetSpellOrPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class CommitMemory extends SplitCard { @@ -30,7 +30,7 @@ public final class CommitMemory extends SplitCard { private static final FilterSpellOrPermanent filter = new FilterSpellOrPermanent("spell or nonland permanent"); static { - filter.setPermanentFilter(new FilterNonlandPermanent()); + filter.getPermanentFilter().add(Predicates.not(CardType.LAND.getPredicate())); } public CommitMemory(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/u/Unsubstantiate.java b/Mage.Sets/src/mage/cards/u/Unsubstantiate.java index 764262a00e6..0e3fd807e54 100644 --- a/Mage.Sets/src/mage/cards/u/Unsubstantiate.java +++ b/Mage.Sets/src/mage/cards/u/Unsubstantiate.java @@ -1,17 +1,16 @@ package mage.cards.u; -import java.util.UUID; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterSpellOrPermanent; import mage.target.common.TargetSpellOrPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Unsubstantiate extends CardImpl { @@ -19,11 +18,11 @@ public final class Unsubstantiate extends CardImpl { private static final FilterSpellOrPermanent filter = new FilterSpellOrPermanent("spell or creature"); static { - filter.setPermanentFilter(new FilterCreaturePermanent()); + filter.getPermanentFilter().add(CardType.CREATURE.getPredicate()); } public Unsubstantiate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Return target spell or creature to its owner's hand. this.getSpellAbility().addTarget(new TargetSpellOrPermanent(1, 1, filter, false)); diff --git a/Mage/src/main/java/mage/filter/Filter.java b/Mage/src/main/java/mage/filter/Filter.java index 0eea30f5a35..44b47979b3b 100644 --- a/Mage/src/main/java/mage/filter/Filter.java +++ b/Mage/src/main/java/mage/filter/Filter.java @@ -28,6 +28,20 @@ public interface Filter extends Serializable, Copyable> { Filter add(Predicate predicate); + /** + * Make sure on setting a new Filter that you overwrite this method + * and call Predicates.makeSurePredicateCompatibleWithFilter + * to check that the filter is able to process objects + * of the right kind. Helps with checks the Compiler can't do + * due to ObjectSourcePlayer casting in the this.match(4 arguments). + *

+ * (method should then call this.addExtra(predicate) after verify checks) + */ + void add(ObjectSourcePlayerPredicate predicate); + + // TODO: if someone can find a way to not have to add this (overload of add made it necessary to introduce) + void addExtra(ObjectSourcePlayerPredicate predicate); + boolean checkObjectClass(Object object); String getMessage(); @@ -36,9 +50,9 @@ public interface Filter extends Serializable, Copyable> { Filter copy(); - public boolean isLockedFilter(); + boolean isLockedFilter(); - public void setLockedFilter(boolean lockedFilter); + void setLockedFilter(boolean lockedFilter); List> getPredicates(); diff --git a/Mage/src/main/java/mage/filter/FilterAbility.java b/Mage/src/main/java/mage/filter/FilterAbility.java index 887d3b3eb65..66fc6bf1fed 100644 --- a/Mage/src/main/java/mage/filter/FilterAbility.java +++ b/Mage/src/main/java/mage/filter/FilterAbility.java @@ -4,11 +4,13 @@ package mage.filter; import mage.abilities.Ability; import mage.constants.AbilityType; import mage.constants.Zone; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; import mage.game.Game; +import mage.game.stack.StackObject; /** - * * @author North */ public class FilterAbility extends FilterImpl { @@ -38,6 +40,18 @@ public class FilterAbility extends FilterImpl { return new AbilityTypePredicate(type); } + @Override + public Filter add(Predicate predicate) { + return super.add(predicate); + } + + @Override + public void add(ObjectSourcePlayerPredicate predicate) { + // Verify Checks + Predicates.makeSurePredicateCompatibleWithFilter(predicate, Ability.class, StackObject.class); + this.addExtra(predicate); + } + @Override public boolean checkObjectClass(Object object) { return object instanceof Ability; diff --git a/Mage/src/main/java/mage/filter/FilterImpl.java b/Mage/src/main/java/mage/filter/FilterImpl.java index 8575e0b7063..bca981cedd0 100644 --- a/Mage/src/main/java/mage/filter/FilterImpl.java +++ b/Mage/src/main/java/mage/filter/FilterImpl.java @@ -63,18 +63,8 @@ public abstract class FilterImpl implements Filter { return this; } - /** - * Make sure on setting a new Filter that you overwrite this method - * and call Predicates.makeSurePredicateCompatibleWithFilter - * to check that the filter is able to process objects - * of the right kind. Helps with checks the Compiler can't do - * due to ObjectSourcePlayer casting in the this.match(4 arguments). - */ - public void add(ObjectSourcePlayerPredicate predicate) { - addExtra(predicate); - } - - public void addExtra(ObjectSourcePlayerPredicate predicate) { + @Override + public final void addExtra(ObjectSourcePlayerPredicate predicate) { if (isLockedFilter()) { throw new UnsupportedOperationException("You may not modify a locked filter"); } diff --git a/Mage/src/main/java/mage/filter/FilterSpell.java b/Mage/src/main/java/mage/filter/FilterSpell.java index a2a56ff759a..1abaabdb0d1 100644 --- a/Mage/src/main/java/mage/filter/FilterSpell.java +++ b/Mage/src/main/java/mage/filter/FilterSpell.java @@ -1,6 +1,7 @@ package mage.filter; +import mage.cards.Card; import mage.game.stack.Spell; /** @@ -22,7 +23,8 @@ public class FilterSpell extends FilterStackObject { @Override public boolean checkObjectClass(Object object) { - return object instanceof Spell; + return object instanceof Spell + || object instanceof Card; // TODO: investigate. Is sometimes used for checking a spell's characteristic before cast } @Override diff --git a/Mage/src/main/java/mage/filter/FilterStackObject.java b/Mage/src/main/java/mage/filter/FilterStackObject.java index 53f59d7c131..0ba2ebe4d42 100644 --- a/Mage/src/main/java/mage/filter/FilterStackObject.java +++ b/Mage/src/main/java/mage/filter/FilterStackObject.java @@ -38,6 +38,7 @@ public class FilterStackObject extends FilterObject { @Override public boolean checkObjectClass(Object object) { - return object instanceof StackObject; + return object instanceof StackObject + || object instanceof Card; // TODO: investigate. Is sometimes used for checking a spell's characteristic before cast } } diff --git a/Mage/src/main/java/mage/filter/MultiFilterImpl.java b/Mage/src/main/java/mage/filter/MultiFilterImpl.java new file mode 100644 index 00000000000..dbbfc862100 --- /dev/null +++ b/Mage/src/main/java/mage/filter/MultiFilterImpl.java @@ -0,0 +1,122 @@ +package mage.filter; + +import mage.abilities.Ability; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.Predicate; +import mage.game.Game; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * Make a Filter out of multiple inner filters. + * + * @author Susucr + */ +public abstract class MultiFilterImpl implements Filter { + + protected List> innerFilters = new ArrayList<>(); + private String message; + + @Override + public abstract MultiFilterImpl copy(); + + protected MultiFilterImpl(String name, Filter... filters) { + this.message = name; + this.innerFilters.addAll(Arrays.stream(filters).collect(Collectors.toList())); + } + + protected MultiFilterImpl(final MultiFilterImpl filter) { + this.message = filter.message; + for (Filter innerFilter : filter.innerFilters) { + this.innerFilters.add(innerFilter.copy()); + } + } + + @Override + public boolean match(E object, Game game) { + return innerFilters + .stream() + .anyMatch((Filter filter) -> filter.match(object, game)); + } + + public boolean match(E object, UUID sourceControllerId, Ability source, Game game) { + return innerFilters + .stream() + .anyMatch((Filter filter) -> filter.match(object, sourceControllerId, source, game)); + } + + @Override + public Filter add(Predicate predicate) { + innerFilters.forEach((Filter filter) -> filter.add(predicate)); + return this; + } + + @Override + public void add(ObjectSourcePlayerPredicate predicate) { + innerFilters.forEach((Filter filter) -> filter.add(predicate)); + } + + @Override + public void addExtra(ObjectSourcePlayerPredicate predicate) { + innerFilters.forEach((Filter filter) -> filter.addExtra(predicate)); + } + + @Override + public boolean checkObjectClass(Object object) { + return innerFilters + .stream() + .anyMatch((Filter filter) -> filter.checkObjectClass(object)); + } + + @Override + public String getMessage() { + return message; + } + + @Override + public final void setMessage(String message) { + if (isLockedFilter()) { + throw new UnsupportedOperationException("You may not modify a locked filter"); + } + this.message = message; + } + + @Override + public String toString() { + return message; + } + + @Override + public boolean isLockedFilter() { + return innerFilters.stream().anyMatch((Filter filter) -> filter.isLockedFilter()); + } + + @Override + public void setLockedFilter(boolean lockedFilter) { + innerFilters.forEach((Filter filter) -> filter.setLockedFilter(lockedFilter)); + } + + public List> getPredicates() { + List> predicates = new ArrayList<>(); + for (Filter filter : innerFilters) { + for (Predicate predicate : filter.getPredicates()) { + predicates.add(predicate); + } + } + return predicates; + } + + public List> getExtraPredicates() { + List> predicates = new ArrayList<>(); + for (Filter filter : innerFilters) { + for (ObjectSourcePlayerPredicate predicate : filter.getExtraPredicates()) { + predicates.add(predicate); + } + } + return predicates; + } +} diff --git a/Mage/src/main/java/mage/filter/common/FilterAnyTarget.java b/Mage/src/main/java/mage/filter/common/FilterAnyTarget.java index 0958607c370..ad4bf776e2b 100644 --- a/Mage/src/main/java/mage/filter/common/FilterAnyTarget.java +++ b/Mage/src/main/java/mage/filter/common/FilterAnyTarget.java @@ -14,7 +14,7 @@ public class FilterAnyTarget extends FilterPermanentOrPlayer { public FilterAnyTarget(String name) { super(name); - this.permanentFilter.add(Predicates.or( + this.getPermanentFilter().add(Predicates.or( CardType.CREATURE.getPredicate(), CardType.PLANESWALKER.getPredicate(), CardType.BATTLE.getPredicate() diff --git a/Mage/src/main/java/mage/filter/common/FilterCreaturePlayerOrPlaneswalker.java b/Mage/src/main/java/mage/filter/common/FilterCreaturePlayerOrPlaneswalker.java index 996205563c6..ee8afd2a19a 100644 --- a/Mage/src/main/java/mage/filter/common/FilterCreaturePlayerOrPlaneswalker.java +++ b/Mage/src/main/java/mage/filter/common/FilterCreaturePlayerOrPlaneswalker.java @@ -16,7 +16,7 @@ public class FilterCreaturePlayerOrPlaneswalker extends FilterPermanentOrPlayer public FilterCreaturePlayerOrPlaneswalker(String name) { super(name); - this.permanentFilter.add(Predicates.or( + this.getPermanentFilter().add(Predicates.or( CardType.CREATURE.getPredicate(), CardType.PLANESWALKER.getPredicate() )); diff --git a/Mage/src/main/java/mage/filter/common/FilterDefender.java b/Mage/src/main/java/mage/filter/common/FilterDefender.java index 61b335dd0a1..5920d9b5a10 100644 --- a/Mage/src/main/java/mage/filter/common/FilterDefender.java +++ b/Mage/src/main/java/mage/filter/common/FilterDefender.java @@ -3,7 +3,6 @@ package mage.filter.common; import mage.constants.CardType; import mage.filter.predicate.Predicates; import mage.filter.predicate.other.PlayerIdPredicate; -import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.filter.predicate.permanent.PermanentIdPredicate; import java.util.Set; @@ -17,17 +16,17 @@ public class FilterDefender extends FilterPermanentOrPlayer { public FilterDefender(Set defenders) { super("player, planeswalker, or battle to attack"); - this.permanentFilter.add(Predicates.or( + this.getPermanentFilter().add(Predicates.or( CardType.PLANESWALKER.getPredicate(), CardType.BATTLE.getPredicate() )); - this.permanentFilter.add(Predicates.or( + this.getPermanentFilter().add(Predicates.or( defenders .stream() .map(PermanentIdPredicate::new) .collect(Collectors.toList()) )); - this.playerFilter.add(Predicates.or( + this.getPlayerFilter().add(Predicates.or( defenders .stream() .map(PlayerIdPredicate::new) diff --git a/Mage/src/main/java/mage/filter/common/FilterPermanentOrPlayer.java b/Mage/src/main/java/mage/filter/common/FilterPermanentOrPlayer.java index ac18369a15b..136477a1c03 100644 --- a/Mage/src/main/java/mage/filter/common/FilterPermanentOrPlayer.java +++ b/Mage/src/main/java/mage/filter/common/FilterPermanentOrPlayer.java @@ -1,23 +1,14 @@ package mage.filter.common; import mage.MageItem; -import mage.abilities.Ability; -import mage.filter.FilterImpl; import mage.filter.FilterPermanent; import mage.filter.FilterPlayer; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; - -import java.util.UUID; +import mage.filter.MultiFilterImpl; /** * @author nantuko */ -public class FilterPermanentOrPlayer extends FilterImpl { - - protected final FilterPermanent permanentFilter; - protected final FilterPlayer playerFilter; +public class FilterPermanentOrPlayer extends MultiFilterImpl { public FilterPermanentOrPlayer() { this("player or permanent"); @@ -28,52 +19,11 @@ public class FilterPermanentOrPlayer extends FilterImpl { } public FilterPermanentOrPlayer(String name, FilterPermanent permanentFilter, FilterPlayer playerFilter) { - super(name); - this.permanentFilter = permanentFilter; - this.playerFilter = playerFilter; + super(name, permanentFilter, playerFilter); } protected FilterPermanentOrPlayer(final FilterPermanentOrPlayer filter) { super(filter); - this.permanentFilter = filter.permanentFilter.copy(); - this.playerFilter = filter.playerFilter.copy(); - } - - @Override - public boolean checkObjectClass(Object object) { - return true; - } - - @Override - public boolean match(MageItem o, Game game) { - if (super.match(o, game)) { - if (o instanceof Player) { - return playerFilter.match((Player) o, game); - } else if (o instanceof Permanent) { - return permanentFilter.match((Permanent) o, game); - } - } - return false; - } - - @Override - public boolean match(MageItem o, UUID playerId, Ability source, Game game) { - if (super.match(o, game)) { // process predicates - if (o instanceof Player) { - return playerFilter.match((Player) o, playerId, source, game); - } else if (o instanceof Permanent) { - return permanentFilter.match((Permanent) o, playerId, source, game); - } - } - return false; - } - - public FilterPermanent getPermanentFilter() { - return this.permanentFilter; - } - - public FilterPlayer getPlayerFilter() { - return this.playerFilter; } @Override @@ -81,4 +31,12 @@ public class FilterPermanentOrPlayer extends FilterImpl { return new FilterPermanentOrPlayer(this); } + public FilterPermanent getPermanentFilter() { + return (FilterPermanent) this.innerFilters.get(0); + } + + public FilterPlayer getPlayerFilter() { + return (FilterPlayer) this.innerFilters.get(1); + } + } diff --git a/Mage/src/main/java/mage/filter/common/FilterPermanentOrSuspendedCard.java b/Mage/src/main/java/mage/filter/common/FilterPermanentOrSuspendedCard.java index 7bde90a10ff..082d8626f33 100644 --- a/Mage/src/main/java/mage/filter/common/FilterPermanentOrSuspendedCard.java +++ b/Mage/src/main/java/mage/filter/common/FilterPermanentOrSuspendedCard.java @@ -1,88 +1,42 @@ package mage.filter.common; import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.keyword.SuspendAbility; -import mage.cards.Card; import mage.counters.CounterType; import mage.filter.FilterCard; -import mage.filter.FilterImpl; import mage.filter.FilterPermanent; +import mage.filter.MultiFilterImpl; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; - -import java.util.UUID; /** * @author emerald000 */ -public class FilterPermanentOrSuspendedCard extends FilterImpl { - - protected FilterCard cardFilter; - protected FilterPermanent permanentFilter; +public class FilterPermanentOrSuspendedCard extends MultiFilterImpl { public FilterPermanentOrSuspendedCard() { this("permanent or suspended card"); } public FilterPermanentOrSuspendedCard(String name) { - super(name); - permanentFilter = new FilterPermanent(); - cardFilter = new FilterCard(); - cardFilter.add(new AbilityPredicate(SuspendAbility.class)); - cardFilter.add(CounterType.TIME.getPredicate()); + super(name, new FilterPermanent(), new FilterCard()); + this.getCardFilter().add(new AbilityPredicate(SuspendAbility.class)); + this.getCardFilter().add(CounterType.TIME.getPredicate()); } protected FilterPermanentOrSuspendedCard(final FilterPermanentOrSuspendedCard filter) { super(filter); - this.permanentFilter = filter.permanentFilter.copy(); - this.cardFilter = filter.cardFilter.copy(); - } - - @Override - public boolean checkObjectClass(Object object) { - return object instanceof MageObject; - } - - @Override - public boolean match(MageObject o, Game game) { - if (o instanceof Permanent) { - return permanentFilter.match((Permanent) o, game); - } else if (o instanceof Card) { - return cardFilter.match((Card) o, game); - } - return false; - } - - @Override - public boolean match(MageObject o, UUID playerId, Ability source, Game game) { - if (o instanceof Permanent) { - return permanentFilter.match((Permanent) o, playerId, source, game); - } else if (o instanceof Card) { - return cardFilter.match((Card) o, playerId, source, game); - } - return false; - } - - public FilterPermanent getPermanentFilter() { - return this.permanentFilter; - } - - public FilterCard getCardFilter() { - return this.cardFilter; - } - - public void setPermanentFilter(FilterPermanent permanentFilter) { - this.permanentFilter = permanentFilter; - } - - public void setCardFilter(FilterCard cardFilter) { - this.cardFilter = cardFilter; } @Override public FilterPermanentOrSuspendedCard copy() { return new FilterPermanentOrSuspendedCard(this); } + + public FilterPermanent getPermanentFilter() { + return (FilterPermanent) this.innerFilters.get(0); + } + + public FilterCard getCardFilter() { + return (FilterCard) this.innerFilters.get(1); + } } diff --git a/Mage/src/main/java/mage/filter/common/FilterSpellOrPermanent.java b/Mage/src/main/java/mage/filter/common/FilterSpellOrPermanent.java index 8757abc3d60..37cde8d496b 100644 --- a/Mage/src/main/java/mage/filter/common/FilterSpellOrPermanent.java +++ b/Mage/src/main/java/mage/filter/common/FilterSpellOrPermanent.java @@ -1,86 +1,25 @@ package mage.filter.common; import mage.MageObject; -import mage.abilities.Ability; -import mage.filter.FilterImpl; import mage.filter.FilterPermanent; import mage.filter.FilterSpell; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.stack.Spell; - -import java.util.UUID; +import mage.filter.MultiFilterImpl; /** * @author LevelX */ -public class FilterSpellOrPermanent extends FilterImpl { - - protected FilterPermanent permanentFilter; - protected FilterSpell spellFilter; +public class FilterSpellOrPermanent extends MultiFilterImpl { public FilterSpellOrPermanent() { this("spell or permanent"); } public FilterSpellOrPermanent(String name) { - super(name); - permanentFilter = new FilterPermanent(); - spellFilter = new FilterSpell(); + super(name, new FilterPermanent(), new FilterSpell()); } protected FilterSpellOrPermanent(final FilterSpellOrPermanent filter) { super(filter); - this.permanentFilter = filter.permanentFilter.copy(); - this.spellFilter = filter.spellFilter.copy(); - } - - @Override - public boolean checkObjectClass(Object object) { - return object instanceof MageObject; - } - - @Override - public boolean match(MageObject o, Game game) { - if (o instanceof Spell) { - return spellFilter.match((Spell) o, game); - } else if (o instanceof Permanent) { - return permanentFilter.match((Permanent) o, game); - } - return false; - } - - @Override - public boolean match(MageObject o, UUID playerId, Ability source, Game game) { - if (o instanceof Spell) { - return spellFilter.match((Spell) o, playerId, source, game); - } else if (o instanceof Permanent) { - return permanentFilter.match((Permanent) o, playerId, source, game); - } - return false; - } - - @Override - public void setLockedFilter(boolean lockedFilter) { - super.setLockedFilter(lockedFilter); - spellFilter.setLockedFilter(lockedFilter); - permanentFilter.setLockedFilter(lockedFilter); - } - - public FilterPermanent getPermanentFilter() { - return this.permanentFilter; - } - - public FilterSpell getSpellFilter() { - return this.spellFilter; - } - - public void setPermanentFilter(FilterPermanent permanentFilter) { - this.permanentFilter = permanentFilter; - } - - public void setSpellFilter(FilterSpell spellFilter) { - this.spellFilter = spellFilter; } @Override @@ -88,4 +27,11 @@ public class FilterSpellOrPermanent extends FilterImpl { return new FilterSpellOrPermanent(this); } + public FilterPermanent getPermanentFilter() { + return (FilterPermanent) this.innerFilters.get(0); + } + + public FilterSpell getSpellFilter() { + return (FilterSpell) this.innerFilters.get(1); + } }