diff --git a/Mage.Sets/src/mage/cards/a/AncientBrassDragon.java b/Mage.Sets/src/mage/cards/a/AncientBrassDragon.java index 7db2e72bce2..4e748752c45 100644 --- a/Mage.Sets/src/mage/cards/a/AncientBrassDragon.java +++ b/Mage.Sets/src/mage/cards/a/AncientBrassDragon.java @@ -1,27 +1,27 @@ package mage.cards.a; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.delayed.ReflexiveTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.keyword.FlyingAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.players.Player; - -import java.util.UUID; import mage.target.common.TargetCardInGraveyard; +import mage.util.CardUtil; + +import java.util.Objects; +import java.util.Set; +import java.util.UUID; /** * @author TheElk801 @@ -91,7 +91,9 @@ class AncientBrassDragonTarget extends TargetCardInGraveyard { private final int xValue; AncientBrassDragonTarget(int xValue) { - super(0, Integer.MAX_VALUE, makeFilter(xValue), false); + super(0, Integer.MAX_VALUE, new FilterCreatureCard( + "creature cards with total mana value " + xValue + " or less from graveyards" + ), false); this.xValue = xValue; } @@ -107,24 +109,27 @@ class AncientBrassDragonTarget extends TargetCardInGraveyard { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - return card != null - && this.getTargets() - .stream() - .map(game::getCard) - .mapToInt(Card::getManaValue) - .sum() + card.getManaValue() <= xValue; + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, xValue, game); } - private static final FilterCard makeFilter(int xValue) { - FilterCard filter = new FilterCreatureCard( - "creature cards with total mana value " - + xValue + " or less from graveyards" - ); - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, xValue+1)); - return filter; + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, xValue, game); } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; + } + } diff --git a/Mage.Sets/src/mage/cards/a/AoTheDawnSky.java b/Mage.Sets/src/mage/cards/a/AoTheDawnSky.java index 9e9020cab6b..5813da126bd 100644 --- a/Mage.Sets/src/mage/cards/a/AoTheDawnSky.java +++ b/Mage.Sets/src/mage/cards/a/AoTheDawnSky.java @@ -9,7 +9,10 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.*; import mage.counters.CounterType; import mage.filter.FilterCard; @@ -21,8 +24,10 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -110,14 +115,13 @@ class AoTheDawnSkyEffect extends OneShotEffect { class AoTheDawnSkyTarget extends TargetCardInLibrary { - private static final FilterCard filter = new FilterPermanentCard("nonland permanent card"); - + private static final FilterCard filterStatic = new FilterPermanentCard("nonland permanent cards with total mana value 4 or less from your graveyard"); static { - filter.add(Predicates.not(CardType.LAND.getPredicate())); + filterStatic.add(Predicates.not(CardType.LAND.getPredicate())); } AoTheDawnSkyTarget() { - super(0, Integer.MAX_VALUE, filter); + super(0, Integer.MAX_VALUE, filterStatic); } private AoTheDawnSkyTarget(final AoTheDawnSkyTarget target) { @@ -130,19 +134,27 @@ class AoTheDawnSkyTarget extends TargetCardInLibrary { } @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { - if (!super.canTarget(playerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - return card != null - && card.getManaValue() - + this - .getTargets() - .stream() - .map(game::getCard) + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, 4, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, 4, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) .filter(Objects::nonNull) .mapToInt(MageObject::getManaValue) - .sum() <= 4; + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; } } diff --git a/Mage.Sets/src/mage/cards/c/CallOfTheDeathDweller.java b/Mage.Sets/src/mage/cards/c/CallOfTheDeathDweller.java index 37d72138912..ed40fb64915 100644 --- a/Mage.Sets/src/mage/cards/c/CallOfTheDeathDweller.java +++ b/Mage.Sets/src/mage/cards/c/CallOfTheDeathDweller.java @@ -1,11 +1,14 @@ package mage.cards.c; import mage.MageItem; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.Outcome; import mage.constants.Zone; import mage.counters.CounterType; @@ -13,7 +16,6 @@ import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; @@ -21,11 +23,9 @@ import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.UUID; +import java.util.*; import java.util.stream.Collectors; /** @@ -93,6 +93,14 @@ class CallOfTheDeathDwellerEffect extends OneShotEffect { if (predicates.isEmpty()) { return false; } + if (predicates.size() == 1) { + Permanent permanent = game.getPermanent(cards.stream().findFirst().orElse(null)); + if (permanent != null) { + permanent.addCounters(CounterType.DEATHTOUCH.createInstance(), source.getControllerId(), source, game); + permanent.addCounters(CounterType.MENACE.createInstance(), source.getControllerId(), source, game); + } + return true; + } FilterPermanent filter = new FilterPermanent("creature to put a deathtouch counter on"); filter.add(Predicates.or(predicates)); Target target = new TargetPermanent(0, 1, filter, true); @@ -116,15 +124,11 @@ class CallOfTheDeathDwellerEffect extends OneShotEffect { class CallOfTheDeathDwellerTarget extends TargetCardInYourGraveyard { - private static final FilterCard filter + private static final FilterCard filterStatic = new FilterCreatureCard("creature cards with total mana value 3 or less from your graveyard"); - static { - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); - } - CallOfTheDeathDwellerTarget() { - super(0, 2, filter, false); + super(0, 2, filterStatic, false); } private CallOfTheDeathDwellerTarget(final CallOfTheDeathDwellerTarget target) { @@ -138,15 +142,27 @@ class CallOfTheDeathDwellerTarget extends TargetCardInYourGraveyard { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - return card != null && - this.getTargets() - .stream() - .map(game::getCard) - .mapToInt(Card::getManaValue) - .sum() + card.getManaValue() <= 3; + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, 3, game); } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, 3, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; + } + } diff --git a/Mage.Sets/src/mage/cards/k/KairiTheSwirlingSky.java b/Mage.Sets/src/mage/cards/k/KairiTheSwirlingSky.java index 94dbc702157..37d1f67a3b1 100644 --- a/Mage.Sets/src/mage/cards/k/KairiTheSwirlingSky.java +++ b/Mage.Sets/src/mage/cards/k/KairiTheSwirlingSky.java @@ -18,13 +18,14 @@ import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.filter.common.FilterNonlandPermanent; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; import mage.target.TargetPermanent; import mage.target.common.TargetCardInGraveyard; +import mage.util.CardUtil; import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -70,11 +71,11 @@ public final class KairiTheSwirlingSky extends CardImpl { class KairiTheSwirlingSkyTarget extends TargetPermanent { - private static final FilterPermanent filter + private static final FilterPermanent filterStatic = new FilterNonlandPermanent("nonland permanents with total mana value 6 or less"); KairiTheSwirlingSkyTarget() { - super(0, Integer.MAX_VALUE, filter, false); + super(0, Integer.MAX_VALUE, filterStatic, false); } private KairiTheSwirlingSkyTarget(final KairiTheSwirlingSkyTarget target) { @@ -88,24 +89,27 @@ class KairiTheSwirlingSkyTarget extends TargetPermanent { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Permanent permanent = game.getPermanent(id); - if (permanent == null) { - return false; - } - int added = 0; // We need to prevent the target to be counted twice on revalidation. - if (!this.getTargets().contains(id)) { - added = permanent.getManaValue();// fresh target, adding its MV - } - return added + - this.getTargets() - .stream() - .map(game::getPermanent) - .filter(Objects::nonNull) - .mapToInt(MageObject::getManaValue) - .sum() <= 6; + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, 6, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, 6, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; } } diff --git a/Mage.Sets/src/mage/cards/l/LivelyDirge.java b/Mage.Sets/src/mage/cards/l/LivelyDirge.java index dd73357b2e5..39579ba8ca9 100644 --- a/Mage.Sets/src/mage/cards/l/LivelyDirge.java +++ b/Mage.Sets/src/mage/cards/l/LivelyDirge.java @@ -1,24 +1,29 @@ package mage.cards.l; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInGraveyardEffect; import mage.abilities.keyword.SpreeAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -81,15 +86,11 @@ class LivelyDirgeEffect extends OneShotEffect { class LivelyDirgeTarget extends TargetCardInYourGraveyard { - private static final FilterCard filter + private static final FilterCard filterStatic = new FilterCreatureCard("creature cards with total mana value 4 or less from your graveyard"); - static { - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 5)); - } - LivelyDirgeTarget() { - super(0, 2, filter, true); + super(0, 2, filterStatic, true); } private LivelyDirgeTarget(final LivelyDirgeTarget target) { @@ -103,15 +104,26 @@ class LivelyDirgeTarget extends TargetCardInYourGraveyard { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - return card != null && - this.getTargets() - .stream() - .map(game::getCard) - .mapToInt(Card::getManaValue) - .sum() + card.getManaValue() <= 4; + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, 4, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, 4, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; } } diff --git a/Mage.Sets/src/mage/cards/m/MarchFromTheTomb.java b/Mage.Sets/src/mage/cards/m/MarchFromTheTomb.java index 5fde901f379..47f751c7aae 100644 --- a/Mage.Sets/src/mage/cards/m/MarchFromTheTomb.java +++ b/Mage.Sets/src/mage/cards/m/MarchFromTheTomb.java @@ -1,21 +1,20 @@ - package mage.cards.m; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; +import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; + +import java.util.Objects; +import java.util.Set; +import java.util.UUID; /** * @@ -27,12 +26,8 @@ public final class MarchFromTheTomb extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{W}{B}"); // Return any number of target Ally creature cards with total converted mana cost of 8 or less from your graveyard to the battlefield. - Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); - effect.setText("Return any number of target Ally creature cards with total mana value 8 or less from your graveyard to the battlefield"); - this.getSpellAbility().addEffect(effect); - FilterCard filter = new FilterCreatureCard(); - filter.add(SubType.ALLY.getPredicate()); - this.getSpellAbility().addTarget(new MarchFromTheTombTarget(0, Integer.MAX_VALUE, filter)); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + this.getSpellAbility().addTarget(new MarchFromTheTombTarget()); } private MarchFromTheTomb(final MarchFromTheTomb card) { @@ -47,8 +42,13 @@ public final class MarchFromTheTomb extends CardImpl { class MarchFromTheTombTarget extends TargetCardInYourGraveyard { - public MarchFromTheTombTarget(int minNumTargets, int maxNumTargets, FilterCard filter) { - super(minNumTargets, maxNumTargets, filter); + private static final FilterCreatureCard filterStatic = new FilterCreatureCard("Ally creature cards with total mana value 8 or less from your graveyard"); + static { + filterStatic.add(SubType.ALLY.getPredicate()); + } + + MarchFromTheTombTarget() { + super(0, Integer.MAX_VALUE, filterStatic); } private MarchFromTheTombTarget(final MarchFromTheTombTarget target) { @@ -56,40 +56,28 @@ class MarchFromTheTombTarget extends TargetCardInYourGraveyard { } @Override - public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { - int cmcLeft = 8; - for (UUID targetId : this.getTargets()) { - Card card = game.getCard(targetId); - if (card != null) { - cmcLeft -= card.getManaValue(); - } - } - Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); - Set leftPossibleTargets = new HashSet<>(); - for (UUID targetId : possibleTargets) { - Card card = game.getCard(targetId); - if (card != null && card.getManaValue() <= cmcLeft) { - leftPossibleTargets.add(targetId); - } - } - withTargetName("any number of target Ally creature cards with total mana value of 8 or less (" + cmcLeft + " left) from your graveyard"); - return leftPossibleTargets; + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, 8, game); } @Override - public boolean canTarget(UUID playerId, UUID objectId, Ability source, Game game) { - if (super.canTarget(playerId, objectId, source, game)) { - int cmcLeft = 8; - for (UUID targetId : this.getTargets()) { - Card card = game.getCard(targetId); - if (card != null) { - cmcLeft -= card.getManaValue(); - } - } - Card card = game.getCard(objectId); - return card != null && card.getManaValue() <= cmcLeft; - } - return false; + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, 8, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; } @Override diff --git a/Mage.Sets/src/mage/cards/m/MoorlandRescuer.java b/Mage.Sets/src/mage/cards/m/MoorlandRescuer.java index f3e0710dc81..a619369c7e8 100644 --- a/Mage.Sets/src/mage/cards/m/MoorlandRescuer.java +++ b/Mage.Sets/src/mage/cards/m/MoorlandRescuer.java @@ -1,6 +1,7 @@ package mage.cards.m; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -21,7 +22,10 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -80,6 +84,7 @@ class MoorlandRescuerEffect extends OneShotEffect { player.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); Card sourceCard = source.getSourceCardIfItStillExists(game); if (sourceCard != null) { + game.processAction(); player.moveCards(sourceCard, Zone.EXILED, source, game); } return true; @@ -108,21 +113,28 @@ class MoorlandRescuerTarget extends TargetCardInYourGraveyard { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - if (card == null) { - return false; - } - int powerSum = this - .getTargets() - .stream() - .map(game::getCard) - .map(Card::getPower) + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, m -> m.getPower().getValue(), xValue, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + m -> m.getPower().getValue(), xValue, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .map(MageObject::getPower) .mapToInt(MageInt::getValue) .sum(); - return card.getPower().getValue() + powerSum <= xValue; + return super.getMessage(game) + " (selected total power " + selectedValue + ")"; } private static FilterCard makeFilter(int xValue, Ability source, Game game) { diff --git a/Mage.Sets/src/mage/cards/n/NethroiApexOfDeath.java b/Mage.Sets/src/mage/cards/n/NethroiApexOfDeath.java index 8e635cc601f..0f1746723d8 100644 --- a/Mage.Sets/src/mage/cards/n/NethroiApexOfDeath.java +++ b/Mage.Sets/src/mage/cards/n/NethroiApexOfDeath.java @@ -1,13 +1,13 @@ package mage.cards.n; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.MutatesSourceTriggeredAbility; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.LifelinkAbility; import mage.abilities.keyword.MutateAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -17,7 +17,10 @@ import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -63,11 +66,11 @@ public final class NethroiApexOfDeath extends CardImpl { class NethroiApexOfDeathTarget extends TargetCardInYourGraveyard { - private static final FilterCard filter + private static final FilterCard filterStatic = new FilterCreatureCard("creature cards with total power 10 or less from your graveyard"); NethroiApexOfDeathTarget() { - super(0, Integer.MAX_VALUE, filter); + super(0, Integer.MAX_VALUE, filterStatic); } private NethroiApexOfDeathTarget(final NethroiApexOfDeathTarget target) { @@ -81,20 +84,28 @@ class NethroiApexOfDeathTarget extends TargetCardInYourGraveyard { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - if (card == null) { - return false; - } - int powerSum = this - .getTargets() - .stream() - .map(game::getCard) - .map(Card::getPower) + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, m -> m.getPower().getValue(), 10, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + m -> m.getPower().getValue(), 10, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .map(MageObject::getPower) .mapToInt(MageInt::getValue) .sum(); - return card.getPower().getValue() + powerSum <= 10; + return super.getMessage(game) + " (selected total power " + selectedValue + ")"; } -} \ No newline at end of file + +} diff --git a/Mage.Sets/src/mage/cards/o/OrcusPrinceOfUndeath.java b/Mage.Sets/src/mage/cards/o/OrcusPrinceOfUndeath.java index 06463aad899..9f1c1c8c302 100644 --- a/Mage.Sets/src/mage/cards/o/OrcusPrinceOfUndeath.java +++ b/Mage.Sets/src/mage/cards/o/OrcusPrinceOfUndeath.java @@ -1,9 +1,7 @@ package mage.cards.o; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -13,18 +11,22 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.keyword.HasteAbility; -import mage.cards.Card; -import mage.constants.*; import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; import mage.target.targetadjustment.TargetAdjuster; +import mage.util.CardUtil; + +import java.util.Objects; +import java.util.Set; +import java.util.UUID; /** * @@ -101,7 +103,7 @@ class OrcusPrinceOfUndeathTarget extends TargetCardInYourGraveyard { private final int xValue; - public OrcusPrinceOfUndeathTarget(int xValue, FilterCreatureCard filter) { + OrcusPrinceOfUndeathTarget(int xValue, FilterCreatureCard filter) { super(0, xValue, filter); this.xValue = xValue; } @@ -116,23 +118,29 @@ class OrcusPrinceOfUndeathTarget extends TargetCardInYourGraveyard { return new OrcusPrinceOfUndeathTarget(this); } + @Override + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, xValue, game); + } + @Override public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { - Set possibleTargets = new HashSet<>(); - int maxManaValue = this.xValue; - for (UUID targetId : this.getTargets()) { - Card card = game.getCard(targetId); - if (card != null) { - maxManaValue -= card.getManaValue(); - } - } - for (UUID possibleTargetId : super.possibleTargets(sourceControllerId, source, game)) { - Card card = game.getCard(possibleTargetId); - if (card != null && card.getManaValue() <= maxManaValue) { - possibleTargets.add(possibleTargetId); - } - } - return possibleTargets; + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, xValue, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; } } diff --git a/Mage.Sets/src/mage/cards/p/PairODiceLost.java b/Mage.Sets/src/mage/cards/p/PairODiceLost.java index e50bbb2e556..b6ff94a6107 100644 --- a/Mage.Sets/src/mage/cards/p/PairODiceLost.java +++ b/Mage.Sets/src/mage/cards/p/PairODiceLost.java @@ -1,9 +1,9 @@ package mage.cards.p; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSpellEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; @@ -15,7 +15,10 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -78,19 +81,18 @@ class PairODiceLostEffect extends OneShotEffect { class PairODiceLostTarget extends TargetCardInYourGraveyard { - private static final FilterCard filter = new FilterCard( - "cards with total mana value X or less from your graveyard" - ); - private final int value; + private final int xValue; - PairODiceLostTarget(int value) { - super(0, Integer.MAX_VALUE, filter, true); - this.value = value; + PairODiceLostTarget(int xValue) { + super(0, Integer.MAX_VALUE, new FilterCard( + "cards with total mana value " + xValue + " or less from your graveyard" + ), true); + this.xValue = xValue; } private PairODiceLostTarget(final PairODiceLostTarget target) { super(target); - this.value = target.value; + this.xValue = target.xValue; } @Override @@ -100,15 +102,27 @@ class PairODiceLostTarget extends TargetCardInYourGraveyard { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - return card != null && - this.getTargets() - .stream() - .map(game::getCard) - .mapToInt(Card::getManaValue) - .sum() + card.getManaValue() <= value; + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, xValue, game); } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, xValue, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; + } + } diff --git a/Mage.Sets/src/mage/cards/p/PatchUp.java b/Mage.Sets/src/mage/cards/p/PatchUp.java index 1055cf663d0..16237f5b2e6 100644 --- a/Mage.Sets/src/mage/cards/p/PatchUp.java +++ b/Mage.Sets/src/mage/cards/p/PatchUp.java @@ -1,18 +1,19 @@ package mage.cards.p; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.ComparisonType; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -40,15 +41,11 @@ public final class PatchUp extends CardImpl { class PatchUpTarget extends TargetCardInYourGraveyard { - private static final FilterCard filter + private static final FilterCard filterStatic = new FilterCreatureCard("creature cards with total mana value 3 or less from your graveyard"); - static { - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4)); - } - PatchUpTarget() { - super(0, 3, filter, false); + super(0, 3, filterStatic, false); } private PatchUpTarget(final PatchUpTarget target) { @@ -62,15 +59,26 @@ class PatchUpTarget extends TargetCardInYourGraveyard { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - return card != null && - this.getTargets() - .stream() - .map(game::getCard) - .mapToInt(Card::getManaValue) - .sum() + card.getManaValue() <= 3; + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, 3, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, 3, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; } } diff --git a/Mage.Sets/src/mage/cards/p/ProteanHulk.java b/Mage.Sets/src/mage/cards/p/ProteanHulk.java index 59cf04d5c0a..afde70d42f8 100644 --- a/Mage.Sets/src/mage/cards/p/ProteanHulk.java +++ b/Mage.Sets/src/mage/cards/p/ProteanHulk.java @@ -5,15 +5,18 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -44,11 +47,11 @@ public final class ProteanHulk extends CardImpl { class ProteanHulkTarget extends TargetCardInLibrary { - private static final FilterCard filter + private static final FilterCard filterStatic = new FilterCreatureCard("creature cards with total mana value 6 or less"); ProteanHulkTarget() { - super(0, Integer.MAX_VALUE, filter); + super(0, Integer.MAX_VALUE, filterStatic); } private ProteanHulkTarget(final ProteanHulkTarget target) { @@ -61,16 +64,27 @@ class ProteanHulkTarget extends TargetCardInLibrary { } @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { - if (!super.canTarget(playerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - if (card == null) { - return false; - } - Cards cards = new CardsImpl(this.getTargets()); - cards.add(id); - return cards.getCards(game).stream().filter(Objects::nonNull).mapToInt(MageObject::getManaValue).sum() <= 6; + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, 6, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, 6, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; } } diff --git a/Mage.Sets/src/mage/cards/r/RampagingYaoGuai.java b/Mage.Sets/src/mage/cards/r/RampagingYaoGuai.java index 2386956b8ac..6a1fbc46c72 100644 --- a/Mage.Sets/src/mage/cards/r/RampagingYaoGuai.java +++ b/Mage.Sets/src/mage/cards/r/RampagingYaoGuai.java @@ -18,10 +18,11 @@ import mage.counters.CounterType; import mage.filter.FilterPermanent; import mage.filter.common.FilterArtifactOrEnchantmentPermanent; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.TargetPermanent; +import mage.util.CardUtil; import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -62,14 +63,13 @@ public final class RampagingYaoGuai extends CardImpl { } } -//Based on Kairi, The Swirling Sky class RampagingYaoGuaiTarget extends TargetPermanent { - private static final FilterPermanent filter + private static final FilterPermanent filterStatic = new FilterArtifactOrEnchantmentPermanent("artifacts and/or enchantments with total mana value X or less"); RampagingYaoGuaiTarget() { - super(0, Integer.MAX_VALUE, filter, false); + super(0, Integer.MAX_VALUE, filterStatic, false); } private RampagingYaoGuaiTarget(final RampagingYaoGuaiTarget target) { @@ -83,23 +83,26 @@ class RampagingYaoGuaiTarget extends TargetPermanent { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Permanent permanent = game.getPermanent(id); - if (permanent == null) { - return false; - } - int added = 0; // We need to prevent the target to be counted twice on revalidation. - if (!this.getTargets().contains(id)) { - added = permanent.getManaValue();// fresh target, adding its MV - } - return added + - this.getTargets() - .stream() - .map(game::getPermanent) - .filter(Objects::nonNull) - .mapToInt(MageObject::getManaValue) - .sum() <= GetXValue.instance.calculate(game, source, null); + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, GetXValue.instance.calculate(game, source, null), game); } -} \ No newline at end of file + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, GetXValue.instance.calculate(game, source, null), game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; + } +} diff --git a/Mage.Sets/src/mage/cards/t/Technomancer.java b/Mage.Sets/src/mage/cards/t/Technomancer.java index 125959a8e98..830c673ba3d 100644 --- a/Mage.Sets/src/mage/cards/t/Technomancer.java +++ b/Mage.Sets/src/mage/cards/t/Technomancer.java @@ -1,23 +1,28 @@ package mage.cards.t; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.MillCardsControllerEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -80,17 +85,16 @@ class TechnomancerEffect extends OneShotEffect { class TechnomancerTarget extends TargetCardInYourGraveyard { - private static final FilterCard filter = new FilterCreatureCard( + private static final FilterCard filterStatic = new FilterCreatureCard( "artifact creature cards with total mana value 6 or less from your graveyard" ); static { - filter.add(CardType.ARTIFACT.getPredicate()); - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 7)); + filterStatic.add(CardType.ARTIFACT.getPredicate()); } TechnomancerTarget() { - super(0, Integer.MAX_VALUE, filter, true); + super(0, Integer.MAX_VALUE, filterStatic, true); } private TechnomancerTarget(final TechnomancerTarget target) { @@ -104,15 +108,26 @@ class TechnomancerTarget extends TargetCardInYourGraveyard { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - return card != null && - this.getTargets() - .stream() - .map(game::getCard) - .mapToInt(Card::getManaValue) - .sum() + card.getManaValue() <= 6; + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, 6, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, 6, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; } } diff --git a/Mage.Sets/src/mage/cards/t/TheWarInHeaven.java b/Mage.Sets/src/mage/cards/t/TheWarInHeaven.java index 0ff29ae4efd..43898175052 100644 --- a/Mage.Sets/src/mage/cards/t/TheWarInHeaven.java +++ b/Mage.Sets/src/mage/cards/t/TheWarInHeaven.java @@ -1,5 +1,6 @@ package mage.cards.t; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SagaAbility; import mage.abilities.effects.OneShotEffect; @@ -7,20 +8,23 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; -import mage.cards.*; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.CounterType; -import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.UUID; -import mage.target.targetpointer.FixedTarget; /** * @author TheElk801 @@ -38,8 +42,7 @@ public final class TheWarInHeaven extends CardImpl { // I -- You draw three cards and you lose 3 life. sagaAbility.addChapterEffect( this, SagaChapter.CHAPTER_I, - new DrawCardSourceControllerEffect(3) - .setText("you draw three cards"), + new DrawCardSourceControllerEffect(3, true), new LoseLifeSourceControllerEffect(3) .concatBy("and") ); @@ -71,7 +74,7 @@ class TheWarInHeavenEffect extends OneShotEffect { super(Outcome.Benefit); staticText = "choose up to three target creature cards with total mana value 8 or less in your graveyard. " + "Return each of them to the battlefield with a necrodermis counter on it. " - + "They\'re artifacts in addition to their other types"; + + "They're artifacts in addition to their other types"; } private TheWarInHeavenEffect(final TheWarInHeavenEffect effect) { @@ -108,15 +111,11 @@ class TheWarInHeavenEffect extends OneShotEffect { class TheWarInHeavenTarget extends TargetCardInYourGraveyard { - private static final FilterCard filter + private static final FilterCreatureCard filterStatic = new FilterCreatureCard("creature cards with total mana value 8 or less from your graveyard"); - static { - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 9)); - } - TheWarInHeavenTarget() { - super(0, 3, filter, false); + super(0, 3, filterStatic, false); } private TheWarInHeavenTarget(final TheWarInHeavenTarget target) { @@ -130,15 +129,26 @@ class TheWarInHeavenTarget extends TargetCardInYourGraveyard { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - return card != null - && this.getTargets() - .stream() - .map(game::getCard) - .mapToInt(Card::getManaValue) - .sum() + card.getManaValue() <= 8; + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, 8, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, 8, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; } } diff --git a/Mage.Sets/src/mage/cards/t/TocasiaDigSiteMentor.java b/Mage.Sets/src/mage/cards/t/TocasiaDigSiteMentor.java index 3a3b87cafef..6c2c76bd899 100644 --- a/Mage.Sets/src/mage/cards/t/TocasiaDigSiteMentor.java +++ b/Mage.Sets/src/mage/cards/t/TocasiaDigSiteMentor.java @@ -1,6 +1,7 @@ package mage.cards.t; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -12,17 +13,17 @@ import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffec import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.keyword.SurveilEffect; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.filter.common.FilterArtifactCard; -import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; +import mage.util.CardUtil; +import java.util.Objects; +import java.util.Set; import java.util.UUID; /** @@ -74,16 +75,12 @@ public final class TocasiaDigSiteMentor extends CardImpl { class TocasiaDigSiteMentorTarget extends TargetCardInYourGraveyard { - private static final FilterCard filter = new FilterArtifactCard( + private static final FilterArtifactCard filterStatic = new FilterArtifactCard( "artifact cards with total mana value 10 or less from your graveyard" ); - static { - filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 11)); - } - TocasiaDigSiteMentorTarget() { - super(0, Integer.MAX_VALUE, filter, false); + super(0, Integer.MAX_VALUE, filterStatic, false); } private TocasiaDigSiteMentorTarget(final TocasiaDigSiteMentorTarget target) { @@ -97,15 +94,26 @@ class TocasiaDigSiteMentorTarget extends TargetCardInYourGraveyard { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - if (!super.canTarget(controllerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - return card != null && - this.getTargets() - .stream() - .map(game::getCard) - .mapToInt(Card::getManaValue) - .sum() + card.getManaValue() <= 10; + return super.canTarget(controllerId, id, source, game) + && CardUtil.checkCanTargetTotalValueLimit( + this.getTargets(), id, MageObject::getManaValue, 10, game); + } + + @Override + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + return CardUtil.checkPossibleTargetsTotalValueLimit(this.getTargets(), + super.possibleTargets(sourceControllerId, source, game), + MageObject::getManaValue, 10, game); + } + + @Override + public String getMessage(Game game) { + // shows selected total + int selectedValue = this.getTargets().stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(MageObject::getManaValue) + .sum(); + return super.getMessage(game) + " (selected total mana value " + selectedValue + ")"; } } diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index f5c64098ab1..49742ab086d 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -57,6 +57,7 @@ import java.net.URLDecoder; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.*; +import java.util.function.ToIntFunction; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -1123,6 +1124,58 @@ public final class CardUtil { return false; } + /** + * For overriding `canTarget()` with usages such as "any number of target cards with total mana value X or less". + * Call this after super.canTarget() returns true. + * + * @param selectedTargets this.getTargets() + * @param checkTargetId id from canTarget + * @param valueMapper e.g. MageObject::getManaValue or m -> m.getPower().getValue() + * @param maxValue the maximum total value of the parameter + * @return true if the total value would not be exceeded by the target being checked. + */ + public static boolean checkCanTargetTotalValueLimit(Collection selectedTargets, UUID checkTargetId, + ToIntFunction valueMapper, int maxValue, + Game game) { + MageObject checkTarget = game.getObject(checkTargetId); + if (checkTarget == null) { + return false; + } + return maxValue >= selectedTargets.stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(valueMapper) + .sum() + + (selectedTargets.contains(checkTargetId) ? 0 : valueMapper.applyAsInt(checkTarget)); + } + + /** + * For overriding `possibleTargets()` with usages such as "any number of target cards with total mana value X or less". + * + * @param selectedTargets this.getTargets() + * @param possibleTargets super.possibleTargets() + * @param valueMapper e.g. MageObject::getManaValue or m -> m.getPower().getValue() + * @param maxValue the maximum total value of the parameter + * @return the set of possible targets that don't exceed the maximum total value. + */ + public static Set checkPossibleTargetsTotalValueLimit(Collection selectedTargets, Set possibleTargets, + ToIntFunction valueMapper, int maxValue, Game game) { + int selectedValue = selectedTargets.stream() + .map(game::getObject) + .filter(Objects::nonNull) + .mapToInt(valueMapper) + .sum(); + int remainingValue = maxValue - selectedValue; + Set validTargets = new HashSet<>(); + for (UUID id: possibleTargets) { + MageObject mageObject = game.getObject(id); + if (mageObject != null && valueMapper.applyAsInt(mageObject) <= remainingValue) { + validTargets.add(id); + } + } + return validTargets; + } + /** * Put card to battlefield without resolve/ETB (for cheats and tests only) * @@ -2325,6 +2378,6 @@ public final class CardUtil { */ public static boolean isInformationAbility(Ability ability) { return !ability.getEffects().isEmpty() - && ability.getEffects().stream().allMatch(e -> e instanceof InfoEffect); + && ability.getEffects().stream().allMatch(InfoEffect.class::isInstance); } }