forked from External/mage
fix "any number of targets with total value X or less" (#12808)
* improve UX for Call of the Death-Dweller * add new utility methods for targets of total value limit * fix affected cards to use new standard methods * adjust message * remove incorrect check * requested adjustments
This commit is contained in:
parent
b10c79d737
commit
2f9ba6dba9
17 changed files with 530 additions and 337 deletions
|
|
@ -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<UUID> 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 + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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 + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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 + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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 + ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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 + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||
Set<UUID> 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<UUID> 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
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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) {
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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 + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||
Set<UUID> 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 + ")";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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 + ")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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 + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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 + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<UUID> 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 + ")";
|
||||
}
|
||||
}
|
||||
|
|
@ -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<UUID> 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 + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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 + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<UUID> 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 + ")";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<UUID> selectedTargets, UUID checkTargetId,
|
||||
ToIntFunction<MageObject> 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<UUID> checkPossibleTargetsTotalValueLimit(Collection<UUID> selectedTargets, Set<UUID> possibleTargets,
|
||||
ToIntFunction<MageObject> valueMapper, int maxValue, Game game) {
|
||||
int selectedValue = selectedTargets.stream()
|
||||
.map(game::getObject)
|
||||
.filter(Objects::nonNull)
|
||||
.mapToInt(valueMapper)
|
||||
.sum();
|
||||
int remainingValue = maxValue - selectedValue;
|
||||
Set<UUID> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue