refactor methods to find cards in exile (#13967)

* refactor exile method names, add comments

* fix card effects checking exile with filter to process ObjectSourcePlayerPredicates

* fix card effects checking exile to respect range of influence
This commit is contained in:
xenohedron 2025-09-12 17:06:53 -04:00 committed by GitHub
parent 32af4a0671
commit 34c26f09c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
60 changed files with 183 additions and 195 deletions

View file

@ -117,7 +117,7 @@ class AltairIbnLaAhadTokenEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Set<Card> cards = game Set<Card> cards = game
.getExile() .getExile()
.getAllCards(game, source.getControllerId()) .getCardsOwned(game, source.getControllerId())
.stream() .stream()
.filter(card -> card.getCounters(game).containsKey(CounterType.MEMORY)) .filter(card -> card.getCounters(game).containsKey(CounterType.MEMORY))
.filter(card -> card.isCreature(game)) .filter(card -> card.isCreature(game))

View file

@ -11,6 +11,7 @@ import mage.constants.*;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.card.FaceDownPredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.token.AshiokNightmareMuseToken; import mage.game.permanent.token.AshiokNightmareMuseToken;
@ -20,8 +21,6 @@ import mage.target.common.TargetNonlandPermanent;
import mage.util.CardUtil; import mage.util.CardUtil;
import java.util.UUID; import java.util.UUID;
import mage.filter.predicate.card.FaceDownPredicate;
import mage.filter.predicate.card.OwnerIdPredicate;
/** /**
* @author TheElk801 * @author TheElk801
@ -96,6 +95,10 @@ class AshiokNightmareMuseBounceEffect extends OneShotEffect {
class AshiokNightmareMuseCastEffect extends OneShotEffect { class AshiokNightmareMuseCastEffect extends OneShotEffect {
private static final FilterCard filter = new FilterCard("face-up cards your opponents own from exile"); private static final FilterCard filter = new FilterCard("face-up cards your opponents own from exile");
static {
filter.add(TargetController.OPPONENT.getOwnerPredicate());
filter.add(Predicates.not(FaceDownPredicate.instance));
}
AshiokNightmareMuseCastEffect() { AshiokNightmareMuseCastEffect() {
super(Outcome.Benefit); super(Outcome.Benefit);
@ -117,11 +120,10 @@ class AshiokNightmareMuseCastEffect extends OneShotEffect {
if (controller == null) { if (controller == null) {
return false; return false;
} }
// card is owned by an opponent and is face up
filter.add(Predicates.not(new OwnerIdPredicate(controller.getId())));
filter.add(Predicates.not(FaceDownPredicate.instance));
CardUtil.castMultipleWithAttributeForFree( CardUtil.castMultipleWithAttributeForFree(
controller, source, game, new CardsImpl(game.getExile().getCards(filter, game)), controller, source, game, new CardsImpl(
game.getExile().getCardsInRange(filter, controller.getId(), source, game)
),
StaticFilters.FILTER_CARD, 3 StaticFilters.FILTER_CARD, 3
); );
return true; return true;

View file

@ -88,7 +88,7 @@ class BiotransferenceEffect extends ContinuousEffectImpl {
} }
} }
// in Exile // in Exile
for (Card card : game.getState().getExile().getAllCards(game, source.getControllerId())) { for (Card card : game.getState().getExile().getCardsOwned(game, source.getControllerId())) {
if (card.isCreature(game) && !card.isArtifact(game)) { if (card.isCreature(game) && !card.isArtifact(game)) {
card.addCardType(game, CardType.ARTIFACT); card.addCardType(game, CardType.ARTIFACT);
} }

View file

@ -65,7 +65,7 @@ enum CandlekeepInspirationValue implements DynamicValue {
.getCards(game) .getCards(game)
.stream(), .stream(),
game.getExile() game.getExile()
.getAllCards(game, sourceAbility.getControllerId()) .getCardsOwned(game, sourceAbility.getControllerId())
.stream() .stream()
) )
.filter(Objects::nonNull) .filter(Objects::nonNull)

View file

@ -128,7 +128,7 @@ class CelestialDawnToWhiteEffect extends ContinuousEffectImpl {
} }
} }
// Exile // Exile
for (Card card : game.getExile().getAllCardsByRange(game, controller.getId())) { for (Card card : game.getExile().getCardsInRange(game, controller.getId())) {
if (card.isOwnedBy(controller.getId())) { if (card.isOwnedBy(controller.getId())) {
setColor(card.getColor(game), game); setColor(card.getColor(game), game);
} }

View file

@ -164,7 +164,7 @@ class ChissGoriaForgeTyrantAffinityEffect extends ContinuousEffectImpl {
return false; return false;
} }
for (Card card : game.getExile().getAllCardsByRange(game, source.getControllerId())) { for (Card card : game.getExile().getCardsInRange(game, source.getControllerId())) {
if (morSet.contains(new MageObjectReference(card, game)) && card.isArtifact(game)) { if (morSet.contains(new MageObjectReference(card, game)) && card.isArtifact(game)) {
game.getState().addOtherAbility(card, new AffinityForArtifactsAbility()); game.getState().addOtherAbility(card, new AffinityForArtifactsAbility());
} }

View file

@ -92,14 +92,14 @@ public final class Conspiracy extends CardImpl {
} }
} }
// in Exile // in Exile
for (Card card : game.getState().getExile().getAllCards(game)) { for (Card card : game.getState().getExile().getCardsOwned(game, controller.getId())) {
if (card.isOwnedBy(controller.getId()) && card.isCreature(game)) { if (card.isCreature(game)) {
setCreatureSubtype(card, subType, game); setCreatureSubtype(card, subType, game);
} }
} }
// in Library (e.g. for Mystical Teachings) // in Library (e.g. for Mystical Teachings)
for (Card card : controller.getLibrary().getCards(game)) { for (Card card : controller.getLibrary().getCards(game)) {
if (card.isOwnedBy(controller.getId()) && card.isCreature(game)) { if (card.isCreature(game)) {
setCreatureSubtype(card, subType, game); setCreatureSubtype(card, subType, game);
} }
} }

View file

@ -56,7 +56,7 @@ enum CosmogoyfValue implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
return game.getState().getExile().getAllCards(game, sourceAbility.getControllerId()).size(); return game.getState().getExile().getCardsOwned(game, sourceAbility.getControllerId()).size();
} }
@Override @Override

View file

@ -161,7 +161,7 @@ class TargetControlledSource extends TargetSource {
possibleTargets.add(card.getId()); possibleTargets.add(card.getId());
} }
// 108.4a If anything asks for the controller of a card that doesn't have one (because it's not a permanent or spell), use its owner instead. // 108.4a If anything asks for the controller of a card that doesn't have one (because it's not a permanent or spell), use its owner instead.
for (Card card : game.getExile().getAllCards(game)) { for (Card card : game.getExile().getCardsInRange(game, sourceControllerId)) {
if (Objects.equals(card.getOwnerId(), sourceControllerId)) { if (Objects.equals(card.getOwnerId(), sourceControllerId)) {
possibleTargets.add(card.getId()); possibleTargets.add(card.getId());
} }

View file

@ -79,7 +79,7 @@ class DragonKamisEggEffect extends OneShotEffect {
} }
Cards cards = new CardsImpl(); Cards cards = new CardsImpl();
game.getExile() game.getExile()
.getAllCards(game, player.getId()) .getCardsOwned(game, player.getId())
.stream() .stream()
.filter(Objects::nonNull) .filter(Objects::nonNull)
.filter(card -> card.getCounters(game).containsKey(CounterType.HATCHLING)) .filter(card -> card.getCounters(game).containsKey(CounterType.HATCHLING))

View file

@ -115,7 +115,7 @@ class DuneChanterContinuousEffect extends ContinuousEffectImpl {
} }
} }
// in exile // in exile
for (Card card : game.getState().getExile().getAllCards(game, controllerId)) { for (Card card : game.getState().getExile().getCardsOwned(game, controllerId)) {
if (filterCard.match(card, controllerId, source, game) && !card.hasSubtype(subType, game)) { if (filterCard.match(card, controllerId, source, game) && !card.hasSubtype(subType, game)) {
game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType);
} }
@ -174,5 +174,3 @@ class DuneChanterEffect extends OneShotEffect {
return true; return true;
} }
} }

View file

@ -83,7 +83,7 @@ class DustOfMomentsEffect extends OneShotEffect {
permanent.addCounters(CounterType.TIME.createInstance(2), source, game); permanent.addCounters(CounterType.TIME.createInstance(2), source, game);
} }
} }
for (Card card : game.getExile().getCards(filter.getCardFilter(), game)) { for (Card card : game.getExile().getCardsInRange(filter.getCardFilter(), source.getControllerId(), source, game)) {
if (remove) { if (remove) {
card.removeCounters(CounterType.TIME.createInstance(2), source, game); card.removeCounters(CounterType.TIME.createInstance(2), source, game);
} else { } else {

View file

@ -80,7 +80,7 @@ class EncroachingMycosynthEffect extends ContinuousEffectImpl {
} }
} }
// in Exile // in Exile
for (Card card : game.getState().getExile().getAllCards(game, source.getControllerId())) { for (Card card : game.getState().getExile().getCardsOwned(game, source.getControllerId())) {
if (card.isPermanent(game) && !card.isLand(game) && !card.isArtifact(game)) { if (card.isPermanent(game) && !card.isLand(game) && !card.isArtifact(game)) {
card.addCardType(game, CardType.ARTIFACT); card.addCardType(game, CardType.ARTIFACT);
} }

View file

@ -96,8 +96,8 @@ class EtrataTheSilencerEffect extends OneShotEffect {
if (card != null) { if (card != null) {
card.addCounters(CounterType.HIT.createInstance(), source.getControllerId(), source, game); card.addCounters(CounterType.HIT.createInstance(), source.getControllerId(), source, game);
} }
int cardsFound = game.getExile().getAllCards(game).stream() int cardsFound = game.getExile().getCardsOwned(game, player.getId())
.filter(c -> c.getOwnerId().equals(player.getId())) .stream()
.filter(c -> c.getCounters(game).getCount(CounterType.HIT) > 0) .filter(c -> c.getCounters(game).getCount(CounterType.HIT) > 0)
.mapToInt(x -> 1) .mapToInt(x -> 1)
.sum(); .sum();

View file

@ -85,30 +85,26 @@ class FalkenrathGorgerEffect extends ContinuousEffectImpl {
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller == null) {
Map<UUID, MadnessAbility> usedMadnessAbilities = new HashMap<>(); return false;
// hand
for (Card card : controller.getHand().getCards(filter, game)) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
// graveyard
for (Card card : controller.getGraveyard().getCards(filter, game)) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
// Exile
for (Card card : game.getExile().getAllCards(game)) {
if (filter.match(card, controller.getId(), source, game)) {
if (card.isOwnedBy(controller.getId())) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
}
}
madnessAbilities.clear();
madnessAbilities.putAll(usedMadnessAbilities);
return true;
} }
Map<UUID, MadnessAbility> usedMadnessAbilities = new HashMap<>();
// hand
for (Card card : controller.getHand().getCards(filter, game)) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
// graveyard
for (Card card : controller.getGraveyard().getCards(filter, game)) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
// Exile
for (Card card : game.getExile().getCardsOwned(filter, controller.getId(), source, game)) {
addMadnessToCard(game, card, usedMadnessAbilities);
}
madnessAbilities.clear();
madnessAbilities.putAll(usedMadnessAbilities);
return true;
return false;
} }
private void addMadnessToCard(Game game, Card card, Map<UUID, MadnessAbility> usedMadnessAbilities) { private void addMadnessToCard(Game game, Card card, Map<UUID, MadnessAbility> usedMadnessAbilities) {

View file

@ -97,7 +97,7 @@ class FlamewarBrashVeteranEffect extends OneShotEffect {
} }
Set<Card> cards = game Set<Card> cards = game
.getExile() .getExile()
.getAllCards(game, source.getControllerId()) .getCardsOwned(game, source.getControllerId())
.stream() .stream()
.filter(card -> card.getCounters(game).containsKey(CounterType.INTEL)) .filter(card -> card.getCounters(game).containsKey(CounterType.INTEL))
.collect(Collectors.toSet()); .collect(Collectors.toSet());

View file

@ -2,12 +2,12 @@ package mage.cards.h;
import mage.MageObject; import mage.MageObject;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.keyword.ScryEffect; import mage.abilities.effects.keyword.ScryEffect;
import mage.abilities.keyword.HexproofAbility; import mage.abilities.keyword.HexproofAbility;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.Cards; import mage.cards.Cards;
@ -15,7 +15,6 @@ import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.mageobject.NamePredicate;
@ -93,9 +92,7 @@ class HedronAlignmentEffect extends OneShotEffect {
if (controller.getGraveyard().getCards(filterCard, controller.getId(), source, game).isEmpty()) { if (controller.getGraveyard().getCards(filterCard, controller.getId(), source, game).isEmpty()) {
return true; return true;
} }
Cards cardsToCheck = new CardsImpl(); if (game.getExile().getCardsOwned(filterCard, controller.getId(), source, game).isEmpty()) {
cardsToCheck.addAllCards(game.getExile().getAllCards(game));
if (cardsToCheck.count(filterCard, controller.getId(), source, game) == 0) {
return true; return true;
} }
controller.won(game); controller.won(game);

View file

@ -87,7 +87,7 @@ class HenzieToolboxTorreGainBlitzEffect extends ContinuousEffectImpl {
controller.getLibrary().getCards(game).stream() controller.getLibrary().getCards(game).stream()
.filter(c -> filter.match(c, game)) .filter(c -> filter.match(c, game))
.forEach(cardsToGainBlitz::add); .forEach(cardsToGainBlitz::add);
game.getExile().getAllCardsByRange(game, controller.getId()).stream() game.getExile().getCardsInRange(game, controller.getId()).stream()
.filter(c -> filter.match(c, game)) .filter(c -> filter.match(c, game))
.forEach(cardsToGainBlitz::add); .forEach(cardsToGainBlitz::add);
game.getCommanderCardsFromCommandZone(controller, CommanderCardType.ANY) game.getCommanderCardsFromCommandZone(controller, CommanderCardType.ANY)

View file

@ -87,7 +87,7 @@ class HerigastEruptingNullkiteEffect extends ContinuousEffectImpl {
controller.getLibrary().getCards(game).stream() controller.getLibrary().getCards(game).stream()
.filter(c -> StaticFilters.FILTER_CARD_CREATURE.match(c, game)) .filter(c -> StaticFilters.FILTER_CARD_CREATURE.match(c, game))
.forEach(cardsToGainEmerge::add); .forEach(cardsToGainEmerge::add);
game.getExile().getAllCardsByRange(game, controller.getId()).stream() game.getExile().getCardsInRange(game, controller.getId()).stream()
.filter(c -> StaticFilters.FILTER_CARD_CREATURE.match(c, game)) .filter(c -> StaticFilters.FILTER_CARD_CREATURE.match(c, game))
.forEach(cardsToGainEmerge::add); .forEach(cardsToGainEmerge::add);
game.getCommanderCardsFromCommandZone(controller, CommanderCardType.ANY) game.getCommanderCardsFromCommandZone(controller, CommanderCardType.ANY)

View file

@ -59,7 +59,7 @@ enum HowlingGalefangCondition implements Condition {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
return game return game
.getExile() .getExile()
.getAllCards(game, source.getControllerId()) .getCardsOwned(game, source.getControllerId())
.stream() .stream()
.anyMatch(AdventureCard.class::isInstance); .anyMatch(AdventureCard.class::isInstance);
} }
@ -67,4 +67,4 @@ enum HowlingGalefangCondition implements Condition {
public static Hint getHint() { public static Hint getHint() {
return hint; return hint;
} }
} }

View file

@ -77,13 +77,8 @@ enum HuskbursterSwarmValue implements DynamicValue {
} }
return game return game
.getExile() .getExile()
.getAllCards(game) .getCardsOwned(StaticFilters.FILTER_CARD_CREATURE, player.getId(), sourceAbility, game)
.stream() .size()
.filter(card -> card.isCreature(game))
.map(Ownerable::getOwnerId)
.filter(sourceAbility::isControlledBy)
.mapToInt(x -> 1)
.sum()
+ player + player
.getGraveyard() .getGraveyard()
.count(StaticFilters.FILTER_CARD_CREATURE, game); .count(StaticFilters.FILTER_CARD_CREATURE, game);

View file

@ -18,10 +18,8 @@ import mage.target.TargetCard;
import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInExile;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
/** /**
* @author spjspj * @author spjspj
@ -150,13 +148,7 @@ class KarnMinus1Effect extends OneShotEffect {
if (controller == null) { if (controller == null) {
return false; return false;
} }
Cards cards = new CardsImpl(game Cards cards = new CardsImpl(game.getExile().getCardsOwned(filter, controller.getId(), source, game));
.getExile()
.getCards(filter, game)
.stream()
.filter(Objects::nonNull)
.filter(card -> card.isOwnedBy(source.getControllerId()))
.collect(Collectors.toList()));
Card card; Card card;
switch (cards.size()) { switch (cards.size()) {
case 0: case 0:
@ -173,6 +165,6 @@ class KarnMinus1Effect extends OneShotEffect {
if (card == null) { if (card == null) {
return false; return false;
} }
return card != null && controller.moveCards(card, Zone.HAND, source, game); return controller.moveCards(card, Zone.HAND, source, game);
} }
} }

View file

@ -131,14 +131,9 @@ class KayaOrzhovUsurperDamageEffect extends OneShotEffect {
if (controller == null || player == null) { if (controller == null || player == null) {
return false; return false;
} }
int count = 0; int count = game.getExile().getCardsOwned(game, player.getId()).size();
for (Card card : game.getExile().getAllCards(game)) {
if (card != null && card.getOwnerId().equals(player.getId())) {
count += 1;
}
}
player.damage(count, source.getSourceId(), source, game); player.damage(count, source.getSourceId(), source, game);
controller.gainLife(count, game, source); controller.gainLife(count, game, source);
return true; return true;
} }
} }

View file

@ -127,10 +127,8 @@ enum KianneDeanOfSubstanceValue implements DynamicValue {
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
return game return game
.getExile() .getExile()
.getAllCards(game) .getCardsOwned(game, sourceAbility.getControllerId())
.stream() .stream()
.filter(Objects::nonNull)
.filter(card -> card.isOwnedBy(sourceAbility.getControllerId()))
.filter(card -> card.getCounters(game).containsKey(CounterType.STUDY)) .filter(card -> card.getCounters(game).containsKey(CounterType.STUDY))
.map(MageObject::getManaValue) .map(MageObject::getManaValue)
.distinct() .distinct()
@ -155,10 +153,8 @@ enum KianneDeanOfSubstanceHint implements Hint {
@Override @Override
public String getText(Game game, Ability ability) { public String getText(Game game, Ability ability) {
List<String> values = game.getExile() List<String> values = game.getExile()
.getAllCards(game) .getCardsOwned(game, ability.getControllerId())
.stream() .stream()
.filter(Objects::nonNull)
.filter(card -> card.isOwnedBy(ability.getControllerId()))
.filter(card -> card.getCounters(game).containsKey(CounterType.STUDY)) .filter(card -> card.getCounters(game).containsKey(CounterType.STUDY))
.mapToInt(MageObject::getManaValue) .mapToInt(MageObject::getManaValue)
.distinct() .distinct()
@ -166,7 +162,7 @@ enum KianneDeanOfSubstanceHint implements Hint {
.mapToObj(String::valueOf) .mapToObj(String::valueOf)
.collect(Collectors.toList()); .collect(Collectors.toList());
return "Mana values of cards exiled with study counters: " + values.size() return "Mana values of cards exiled with study counters: " + values.size()
+ (values.size() > 0 ? " (" + String.join(", ", values) + ')' : ""); + (values.isEmpty() ? "" : " (" + String.join(", ", values) + ')');
} }
@Override @Override

View file

@ -125,7 +125,7 @@ class LivioOathswornSentinelReturnEffect extends OneShotEffect {
} }
Set<Card> cards = game Set<Card> cards = game
.getExile() .getExile()
.getAllCards(game) .getCardsInRange(game, player.getId())
.stream() .stream()
.filter(Objects::nonNull) .filter(Objects::nonNull)
.filter(card -> card.getCounters(game).containsKey(CounterType.AEGIS)) .filter(card -> card.getCounters(game).containsKey(CounterType.AEGIS))

View file

@ -135,14 +135,12 @@ class MairsilThePretenderGainAbilitiesEffect extends ContinuousEffectImpl {
if (perm == null) { if (perm == null) {
return false; return false;
} }
for (Card card : game.getExile().getAllCards(game)) { for (Card card : game.getExile().getCardsOwned(filter, perm.getControllerId(), source, game)) {
if (filter.match(card, game) && Objects.equals(card.getOwnerId(), perm.getControllerId())) { for (Ability ability : card.getAbilities(game)) {
for (Ability ability : card.getAbilities(game)) { if (ability.isActivatedAbility()) {
if (ability.isActivatedAbility()) { ActivatedAbility copyAbility = (ActivatedAbility) ability.copy();
ActivatedAbility copyAbility = (ActivatedAbility) ability.copy(); copyAbility.setMaxActivationsPerTurn(1);
copyAbility.setMaxActivationsPerTurn(1); perm.addAbility(copyAbility, source.getSourceId(), game, true);
perm.addAbility(copyAbility, source.getSourceId(), game, true);
}
} }
} }
} }

View file

@ -96,7 +96,7 @@ class MaskwoodNexusEffect extends ContinuousEffectImpl {
.forEach(affectedCards::add); .forEach(affectedCards::add);
// in Exile // in Exile
game.getState().getExile().getAllCards(game, controller.getId()).stream() game.getState().getExile().getCardsOwned(game, controller.getId()).stream()
.filter(card -> card.isOwnedBy(controller.getId())) .filter(card -> card.isOwnedBy(controller.getId()))
.forEach(affectedCards::add); .forEach(affectedCards::add);

View file

@ -107,7 +107,7 @@ class EverythingIsColorlessEffect extends ContinuousEffectImpl {
} }
// exile // exile
affectedCards.addAll(game.getExile().getAllCardsByRange(game, controller.getId())); affectedCards.addAll(game.getExile().getCardsInRange(game, controller.getId()));
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {

View file

@ -1,7 +1,5 @@
package mage.cards.o; package mage.cards.o;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
@ -12,19 +10,20 @@ import mage.cards.CardSetInfo;
import mage.cards.Cards; import mage.cards.Cards;
import mage.cards.CardsImpl; import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterLandCard; import mage.filter.common.FilterLandCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.filter.predicate.card.FaceDownPredicate; import mage.filter.predicate.card.FaceDownPredicate;
import mage.filter.predicate.card.OwnerIdPredicate;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetCard; import mage.target.TargetCard;
import mage.target.common.TargetOpponent; import mage.target.common.TargetOpponent;
import java.util.UUID;
/** /**
* *
* @author LevelX2 * @author LevelX2
@ -56,6 +55,11 @@ public final class OblivionSower extends CardImpl {
class OblivionSowerEffect extends OneShotEffect { class OblivionSowerEffect extends OneShotEffect {
private static final FilterCard filter = new FilterLandCard();
static {
filter.add(Predicates.not(FaceDownPredicate.instance));
}
OblivionSowerEffect() { OblivionSowerEffect() {
super(Outcome.PutLandInPlay); super(Outcome.PutLandInPlay);
this.staticText = ", then you may put any number of land cards that player owns from exile onto the battlefield under your control"; this.staticText = ", then you may put any number of land cards that player owns from exile onto the battlefield under your control";
@ -78,25 +82,21 @@ class OblivionSowerEffect extends OneShotEffect {
*/ */
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
if (controller != null && targetPlayer != null) { if (controller == null || targetPlayer == null) {
FilterLandCard filter = new FilterLandCard(); return false;
filter.add(new OwnerIdPredicate(targetPlayer.getId()));
filter.add(Predicates.not(FaceDownPredicate.instance));
Cards exiledCards = new CardsImpl();
exiledCards.addAllCards(game.getExile().getAllCards(game));
Cards exiledLands = new CardsImpl();
exiledLands.addAllCards(exiledCards.getCards(filter, controller.getId(), source, game));
if (!exiledLands.isEmpty() && controller.chooseUse(outcome, "Put lands into play?", source, game)) {
FilterCard filterToPlay = new FilterCard("land"
+ (exiledLands.size() > 1 ? "s" : "") + " from exile owned by "
+ targetPlayer.getName() + " to put into play under your control");
TargetCard targetCards = new TargetCard(0, exiledLands.size(), Zone.EXILED, filterToPlay);
if (controller.chooseTarget(outcome, exiledLands, targetCards, source, game)) {
controller.moveCards(new CardsImpl(targetCards.getTargets()), Zone.BATTLEFIELD, source, game);
}
}
return true;
} }
return false; Cards exiledLands = new CardsImpl(game.getExile()
.getCardsOwned(filter, targetPlayer.getId(), source, game)
);
if (!exiledLands.isEmpty() && controller.chooseUse(outcome, "Put lands into play?", source, game)) {
FilterCard filterToPlay = new FilterCard("land"
+ (exiledLands.size() > 1 ? "s" : "") + " from exile owned by "
+ targetPlayer.getName() + " to put into play under your control");
TargetCard targetCards = new TargetCard(0, exiledLands.size(), Zone.EXILED, filterToPlay);
if (controller.chooseTarget(outcome, exiledLands, targetCards, source, game)) {
controller.moveCards(new CardsImpl(targetCards.getTargets()), Zone.BATTLEFIELD, source, game);
}
}
return true;
} }
} }

View file

@ -82,7 +82,7 @@ class PaintersServantEffect extends ContinuousEffectImpl {
} }
// exile // exile
affectedCards.addAll(game.getExile().getAllCardsByRange(game, controller.getId())); affectedCards.addAll(game.getExile().getCardsInRange(game, controller.getId()));
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
Player player = game.getPlayer(playerId); Player player = game.getPlayer(playerId);

View file

@ -106,7 +106,7 @@ class AmazingSpiderManEffect extends ContinuousEffectImpl {
controller.getLibrary().getCards(game).stream() controller.getLibrary().getCards(game).stream()
.filter(c -> filter.match(c, game)) .filter(c -> filter.match(c, game))
.forEach(cardsToGainAbility::add); .forEach(cardsToGainAbility::add);
game.getExile().getAllCardsByRange(game, controller.getId()).stream() game.getExile().getCardsInRange(game, controller.getId()).stream()
.filter(c -> filter.match(c, game)) .filter(c -> filter.match(c, game))
.forEach(cardsToGainAbility::add); .forEach(cardsToGainAbility::add);
game.getCommanderCardsFromCommandZone(controller, CommanderCardType.ANY).stream() game.getCommanderCardsFromCommandZone(controller, CommanderCardType.ANY).stream()
@ -127,4 +127,4 @@ class AmazingSpiderManEffect extends ContinuousEffectImpl {
} }
return true; return true;
} }
} }

View file

@ -124,7 +124,7 @@ class RavenloftAdventurerLifeEffect extends OneShotEffect {
} }
int count = game int count = game
.getExile() .getExile()
.getAllCards(game, player.getId()) .getCardsOwned(game, player.getId())
.stream() .stream()
.filter(card -> card.getCounters(game).containsKey(CounterType.HIT)) .filter(card -> card.getCounters(game).containsKey(CounterType.HIT))
.mapToInt(x -> 1) .mapToInt(x -> 1)

View file

@ -74,7 +74,7 @@ class RayamiFirstOfTheFallenEffect extends ContinuousEffectImpl {
return false; return false;
} }
game.getExile() game.getExile()
.getAllCards(game) .getCardsInRange(game, sourcePermanent.getControllerId())
.stream() .stream()
.filter(card1 -> card1.isCreature(game)) .filter(card1 -> card1.isCreature(game))
.filter(card -> card.getCounters(game).getCount(CounterType.BLOOD) > 0) .filter(card -> card.getCounters(game).getCount(CounterType.BLOOD) > 0)

View file

@ -104,7 +104,7 @@ class RexCyberhoundContinuousEffect extends ContinuousEffectImpl {
filter.add(CounterType.BRAIN.getPredicate()); filter.add(CounterType.BRAIN.getPredicate());
} }
public RexCyberhoundContinuousEffect() { RexCyberhoundContinuousEffect() {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
staticText = "{this} has all activated abilities of all cards in exile with brain counters on them"; staticText = "{this} has all activated abilities of all cards in exile with brain counters on them";
addDependencyType(DependencyType.AddingAbility); addDependencyType(DependencyType.AddingAbility);
@ -125,7 +125,7 @@ class RexCyberhoundContinuousEffect extends ContinuousEffectImpl {
if (perm == null) { if (perm == null) {
return false; return false;
} }
for (Card card : game.getExile().getCards(filter, game)) { for (Card card : game.getExile().getCardsInRange(filter, source.getControllerId(), source, game)) {
for (Ability ability : card.getAbilities(game)) { for (Ability ability : card.getAbilities(game)) {
if (ability.isActivatedAbility()) { if (ability.isActivatedAbility()) {
ActivatedAbility copyAbility = (ActivatedAbility) ability.copy(); ActivatedAbility copyAbility = (ActivatedAbility) ability.copy();

View file

@ -85,7 +85,7 @@ enum RoseTylerValue implements DynamicValue {
.count(filter.getPermanentFilter(), sourceAbility.getControllerId(), sourceAbility, game) .count(filter.getPermanentFilter(), sourceAbility.getControllerId(), sourceAbility, game)
+ game + game
.getExile() .getExile()
.getAllCards(game, sourceAbility.getControllerId()) .getCardsOwned(game, sourceAbility.getControllerId())
.stream() .stream()
.filter(card -> card.isOwnedBy(sourceAbility.getControllerId())) .filter(card -> card.isOwnedBy(sourceAbility.getControllerId()))
.mapToInt(card -> filter.getCardFilter().match(card, game) ? 1 : 0) .mapToInt(card -> filter.getCardFilter().match(card, game) ? 1 : 0)

View file

@ -23,7 +23,6 @@ import mage.filter.predicate.Predicates;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import java.util.Optional;
import java.util.UUID; import java.util.UUID;
/** /**
@ -69,7 +68,6 @@ enum SailorsBaneValue implements DynamicValue {
private static final FilterCard filter = new FilterCard(); private static final FilterCard filter = new FilterCard();
static { static {
filter.add(TargetController.YOU.getOwnerPredicate());
filter.add(Predicates.or( filter.add(Predicates.or(
CardType.INSTANT.getPredicate(), CardType.INSTANT.getPredicate(),
CardType.SORCERY.getPredicate(), CardType.SORCERY.getPredicate(),
@ -79,15 +77,12 @@ enum SailorsBaneValue implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
return Optional Player player = game.getPlayer(sourceAbility.getControllerId());
.ofNullable(game.getPlayer(sourceAbility.getControllerId())) if (player == null) {
.map(Player::getGraveyard) return 0;
.map(graveyard -> graveyard.count(filter, game)) }
.orElse(0) return game.getExile().getCardsOwned(filter, player.getId(), sourceAbility, game).size()
+ game + player.getGraveyard().count(filter, player.getId(), sourceAbility, game);
.getExile()
.getCards(filter, game)
.size();
} }
@Override @Override
@ -100,7 +95,7 @@ enum SailorsBaneValue implements DynamicValue {
return ""; return "";
} }
private static final boolean checkAdventure(Card input, Game game) { private static boolean checkAdventure(Card input, Game game) {
return input instanceof AdventureCard; return input instanceof AdventureCard;
} }
} }

View file

@ -62,7 +62,7 @@ enum SeizeTheStormValue implements DynamicValue {
return player.getGraveyard().count( return player.getGraveyard().count(
StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game
) + game.getExile() ) + game.getExile()
.getAllCards(game, sourceAbility.getControllerId()) .getCardsOwned(game, sourceAbility.getControllerId())
.stream() .stream()
.filter(card -> card.getAbilities(game).containsClass(FlashbackAbility.class)) .filter(card -> card.getAbilities(game).containsClass(FlashbackAbility.class))
.mapToInt(x -> 1).sum(); .mapToInt(x -> 1).sum();

View file

@ -87,7 +87,7 @@ class SlimeAgainstHumanityEffect extends OneShotEffect {
int exileCount = game int exileCount = game
.getState() .getState()
.getExile() .getExile()
.getAllCards(game, source.getControllerId()) .getCardsOwned(game, source.getControllerId())
.stream() .stream()
.filter(card -> filter.match(card, game)) .filter(card -> filter.match(card, game))
.mapToInt(x -> 1) .mapToInt(x -> 1)

View file

@ -132,7 +132,7 @@ class TashaTheWitchQueenCastEffect extends OneShotEffect {
if (player == null) { if (player == null) {
return false; return false;
} }
Cards cards = new CardsImpl(game.getExile().getCards(filter, game)); Cards cards = new CardsImpl(game.getExile().getCardsInRange(filter, source.getControllerId(), source, game));
return !cards.isEmpty() && CardUtil.castSpellWithAttributesForFree(player, source, game, cards, StaticFilters.FILTER_CARD); return !cards.isEmpty() && CardUtil.castSpellWithAttributesForFree(player, source, game, cards, StaticFilters.FILTER_CARD);
} }
} }

View file

@ -87,14 +87,14 @@ class TeferiMageOfZhalfirAddFlashEffect extends ContinuousEffectImpl {
} }
} }
// in Exile // in Exile
for (Card card : game.getState().getExile().getAllCards(game)) { for (Card card : game.getState().getExile().getCardsOwned(game, controller.getId())) {
if (card.isOwnedBy(controller.getId()) && card.isCreature(game)) { if (card.isCreature(game)) {
game.getState().addOtherAbility(card, FlashAbility.getInstance()); game.getState().addOtherAbility(card, FlashAbility.getInstance());
} }
} }
// in Library (e.g. for Mystical Teachings) // in Library (e.g. for Mystical Teachings)
for (Card card : controller.getLibrary().getCards(game)) { for (Card card : controller.getLibrary().getCards(game)) {
if (card.isOwnedBy(controller.getId()) && card.isCreature(game)) { if (card.isCreature(game)) {
game.getState().addOtherAbility(card, FlashAbility.getInstance()); game.getState().addOtherAbility(card, FlashAbility.getInstance());
} }
} }

View file

@ -116,7 +116,7 @@ enum UlamogTheDefilerValue implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
return game.getExile() return game.getExile()
.getAllCardsByRange(game, sourceAbility.getControllerId()) .getCardsInRange(game, sourceAbility.getControllerId())
.stream() .stream()
.mapToInt(Card::getManaValue) .mapToInt(Card::getManaValue)
.max() .max()

View file

@ -1,7 +1,5 @@
package mage.cards.w; package mage.cards.w;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
@ -13,12 +11,13 @@ import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Zone; import mage.constants.SubType;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import java.util.UUID;
/** /**
* *
* @author LevelX2 * @author LevelX2
@ -26,7 +25,7 @@ import mage.players.Player;
public final class WardenOfTheBeyond extends CardImpl { public final class WardenOfTheBeyond extends CardImpl {
public WardenOfTheBeyond(UUID ownerId, CardSetInfo setInfo) { public WardenOfTheBeyond(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.WIZARD); this.subtype.add(SubType.WIZARD);
@ -35,9 +34,10 @@ public final class WardenOfTheBeyond extends CardImpl {
// Vigilance // Vigilance
this.addAbility(VigilanceAbility.getInstance()); this.addAbility(VigilanceAbility.getInstance());
// Warden of the Beyond gets +2/+2 as long as an opponent owns a card in exile. // Warden of the Beyond gets +2/+2 as long as an opponent owns a card in exile.
this.addAbility(new SimpleStaticAbility( this.addAbility(new SimpleStaticAbility(
new ConditionalContinuousEffect(new BoostSourceEffect(2,2,Duration.WhileOnBattlefield), OpponentOwnsCardInExileCondition.instance, new ConditionalContinuousEffect(new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), WardenOfTheBeyondCondition.instance,
"{this} gets +2/+2 as long as an opponent owns a card in exile"))); "{this} gets +2/+2 as long as an opponent owns a card in exile")));
} }
@ -51,15 +51,15 @@ public final class WardenOfTheBeyond extends CardImpl {
} }
} }
enum OpponentOwnsCardInExileCondition implements Condition { enum WardenOfTheBeyondCondition implements Condition {
instance; instance;
@Override @Override
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
if (controller != null) { if (controller != null) {
for (Card card :game.getExile().getAllCards(game)) { for (Card card : game.getExile().getCardsInRange(game, controller.getId())) {
if (controller.hasOpponent(card.getOwnerId(), game)) { if (controller.hasOpponent(card.getOwnerId(), game)) {
return true; return true;
} }

View file

@ -115,7 +115,7 @@ class ZethiArcaneBlademasterCastEffect extends OneShotEffect {
if (controller == null) { if (controller == null) {
return false; return false;
} }
Cards cards = new CardsImpl(game.getExile().getAllCards(game, source.getControllerId())); Cards cards = new CardsImpl(game.getExile().getCardsOwned(game, source.getControllerId()));
cards.removeIf(uuid -> !game.getCard(uuid).getCounters(game).containsKey(CounterType.KICK)); cards.removeIf(uuid -> !game.getCard(uuid).getCounters(game).containsKey(CounterType.KICK));
if (cards.isEmpty()) { if (cards.isEmpty()) {
return false; return false;

View file

@ -147,7 +147,7 @@ public class ManifestTest extends CardTestPlayerBase {
runCode("after blink", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { runCode("after blink", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
if (cardAfterBlink == null) { if (cardAfterBlink == null) {
Assert.assertEquals("after blink card must keep in exile", Assert.assertEquals("after blink card must keep in exile",
1, currentGame.getExile().getAllCardsByRange(currentGame, playerA.getId()).size()); 1, currentGame.getExile().getCardsInRange(currentGame, playerA.getId()).size());
} else { } else {
String realPermanentName = currentGame.getBattlefield().getAllPermanents() String realPermanentName = currentGame.getBattlefield().getAllPermanents()
.stream() .stream()

View file

@ -66,7 +66,7 @@ public class DuneChanterTest extends CardTestPlayerBase {
private static void checkExile(String info, Player player, Game game, int count) { private static void checkExile(String info, Player player, Game game, int count) {
int amount = game int amount = game
.getExile() .getExile()
.getAllCards(game, player.getId()) .getCardsOwned(game, player.getId())
.stream() .stream()
.filter(c -> c.getSubtype(game).contains(SubType.DESERT)) .filter(c -> c.getSubtype(game).contains(SubType.DESERT))
.mapToInt(k -> 1) .mapToInt(k -> 1)

View file

@ -888,7 +888,7 @@ public class TokenImagesTest extends CardTestPlayerBase {
// check face down card in exile // check face down card in exile
runCode("on face down", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { runCode("on face down", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
Card card = currentGame.getExile().getAllCards(currentGame, playerA.getId()).get(0); Card card = currentGame.getExile().getCardsOwned(currentGame, playerA.getId()).get(0);
GameView gameView = getGameView(playerA); GameView gameView = getGameView(playerA);
CardView controllerCardView = gameView.getExile() CardView controllerCardView = gameView.getExile()
.stream() .stream()
@ -941,7 +941,7 @@ public class TokenImagesTest extends CardTestPlayerBase {
// check face down card // check face down card
runCode("on face down", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { runCode("on face down", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
Card card = currentGame.getExile().getAllCards(currentGame, playerA.getId()).get(0); Card card = currentGame.getExile().getCardsOwned(currentGame, playerA.getId()).get(0);
GameView gameView = getGameView(playerA); GameView gameView = getGameView(playerA);
CardView controllerCardView = gameView.getExile() CardView controllerCardView = gameView.getExile()
.stream() .stream()

View file

@ -74,8 +74,8 @@ public enum CardsInExileCount implements DynamicValue {
return playerIds.stream() return playerIds.stream()
.map(game::getPlayer) .map(game::getPlayer)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.map(player -> game.getExile().getAllCards(game, player.getId())) .map(player -> game.getExile().getCardsOwned(game, player.getId()))
.flatMap(Collection::stream) .flatMap(Collection::stream)
.filter(Objects::nonNull); .filter(Objects::nonNull);
} }
} }

View file

@ -3,7 +3,6 @@ package mage.abilities.dynamicvalue.common;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.cards.Card;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
@ -17,18 +16,11 @@ public enum InstantSorceryExileGraveyardCount implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
Player player = game.getPlayer(sourceAbility.getControllerId()); Player player = game.getPlayer(sourceAbility.getControllerId());
if (player != null) { if (player == null) {
int exileCount = 0; return 0;
for (Card exiledCard : game.getExile().getAllCards(game)) {
if (exiledCard.getOwnerId().equals(player.getId()) && exiledCard.isInstantOrSorcery(game)) {
exileCount++;
}
}
return player.getGraveyard().count(
StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, game
) + exileCount;
} }
return 0; return game.getExile().getCardsOwned(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, player.getId(), sourceAbility, game).size()
+ player.getGraveyard().count(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, player.getId(), sourceAbility, game);
} }
@Override @Override

View file

@ -26,7 +26,7 @@ public enum TotalCardsExiledOwnedManaValue implements DynamicValue {
@Override @Override
public int calculate(Game game, Ability sourceAbility, Effect effect) { public int calculate(Game game, Ability sourceAbility, Effect effect) {
int totalCMC = 0; int totalCMC = 0;
List<Card> cards = game.getExile().getAllCards( List<Card> cards = game.getExile().getCardsOwned(
game, game,
sourceAbility.getControllerId() sourceAbility.getControllerId()
); );

View file

@ -99,7 +99,7 @@ public class WishEffect extends OneShotEffect {
return false; return false;
} }
Cards cards = controller.getSideboard(); Cards cards = controller.getSideboard();
List<Card> exile = game.getExile().getAllCards(game); List<Card> exile = game.getExile().getCardsOwned(game, controller.getId());
boolean noTargets = cards.isEmpty() && (!alsoFromExile || exile.isEmpty()); boolean noTargets = cards.isEmpty() && (!alsoFromExile || exile.isEmpty());
if (noTargets) { if (noTargets) {
game.informPlayer(controller, "You have no cards outside the game" + (alsoFromExile ? " or in exile" : "") + '.'); game.informPlayer(controller, "You have no cards outside the game" + (alsoFromExile ? " or in exile" : "") + '.');

View file

@ -98,7 +98,7 @@ public class AddCreatureSubTypeAllMultiZoneEffect extends ContinuousEffectImpl {
} }
} }
// in Exile // in Exile
for (Card card : game.getState().getExile().getAllCards(game, controllerId)) { for (Card card : game.getState().getExile().getCardsOwned(game, controllerId)) {
if (filterCard.match(card, controllerId, source, game) && !card.hasSubtype(subType, game)) { if (filterCard.match(card, controllerId, source, game) && !card.hasSubtype(subType, game)) {
game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType);
} }

View file

@ -44,7 +44,7 @@ public class GainAbilityControlledSpellsEffect extends ContinuousEffectImpl {
return false; return false;
} }
for (Card card : game.getExile().getAllCardsByRange(game, source.getControllerId())) { for (Card card : game.getExile().getCardsInRange(game, source.getControllerId())) {
if (filter.match(card, player.getId(), source, game)) { if (filter.match(card, player.getId(), source, game)) {
game.getState().addOtherAbility(card, ability); game.getState().addOtherAbility(card, ability);
} }

View file

@ -93,7 +93,7 @@ public class NextSpellCastHasAbilityEffect extends ContinuousEffectImpl {
discard(); // only one use discard(); // only one use
return false; return false;
} }
for (Card card : game.getExile().getAllCardsByRange(game, playerId)) { for (Card card : game.getExile().getCardsInRange(game, playerId)) {
if (filter.match(card, playerId, source, game)) { if (filter.match(card, playerId, source, game)) {
game.getState().addOtherAbility(card, ability); game.getState().addOtherAbility(card, ability);
} }

View file

@ -79,7 +79,7 @@ public class ChoiceCreatureType extends ChoiceImpl {
}); });
// exile // exile
game.getExile().getAllCards(game, playerId).forEach(card -> { game.getExile().getCardsOwned(game, playerId).forEach(card -> {
list.addAll(card.getSubtype(game).stream().map(SubType::toString).collect(Collectors.toList())); list.addAll(card.getSubtype(game).stream().map(SubType::toString).collect(Collectors.toList()));
}); });
}); });

View file

@ -1,5 +1,6 @@
package mage.game; package mage.game;
import mage.abilities.Ability;
import mage.cards.Card; import mage.cards.Card;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.util.Copyable; import mage.util.Copyable;
@ -61,24 +62,33 @@ public class Exile implements Serializable, Copyable<Exile> {
return null; return null;
} }
/**
* Returns all cards in exile matching the filter. Use only for test framework.
* For card effects, instead use a method that checks owner or range of influence.
*/
@Deprecated
public List<Card> getCards(FilterCard filter, Game game) { public List<Card> getCards(FilterCard filter, Game game) {
List<Card> allCards = getAllCards(game); List<Card> allCards = getAllCards(game);
return allCards.stream().filter(card -> filter.match(card, game)).collect(Collectors.toList()); return allCards.stream().filter(card -> filter.match(card, game)).collect(Collectors.toList());
} }
@Deprecated // TODO: must use related request due game range like getAllCardsByRange /**
* Returns all cards in exile. Use only for test framework.
* For card effects, instead use a method that checks owner or range of influence.
*/
@Deprecated
public List<Card> getAllCards(Game game) { public List<Card> getAllCards(Game game) {
return getAllCards(game, null); return getCardsOwned(game, null);
} }
/** /**
* Return exiled cards owned by a specific player. Use it in effects to find all cards in range. * Returns all cards in exile owned by the specified player
*/ */
public List<Card> getAllCards(Game game, UUID fromPlayerId) { public List<Card> getCardsOwned(Game game, UUID ownerId) {
List<Card> res = new ArrayList<>(); List<Card> res = new ArrayList<>();
for (ExileZone exile : exileZones.values()) { for (ExileZone exile : exileZones.values()) {
for (Card card : exile.getCards(game)) { for (Card card : exile.getCards(game)) {
if (fromPlayerId == null || card.isOwnedBy(fromPlayerId)) { if (ownerId == null || card.isOwnedBy(ownerId)) {
res.add(card); res.add(card);
} }
} }
@ -86,14 +96,37 @@ public class Exile implements Serializable, Copyable<Exile> {
return res; return res;
} }
public List<Card> getAllCardsByRange(Game game, UUID controllerId) { /**
* Returns all cards in exile matching the filter, owned by the specified player
*/
public Set<Card> getCardsOwned(FilterCard filter, UUID playerId, Ability source, Game game) {
return getCardsOwned(game, playerId)
.stream()
.filter(card -> filter.match(card, playerId, source, game))
.collect(Collectors.toCollection(LinkedHashSet::new));
}
/**
* Returns all cards in exile in range of the specified player
*/
public List<Card> getCardsInRange(Game game, UUID controllerId) {
List<Card> res = new ArrayList<>(); List<Card> res = new ArrayList<>();
for (UUID playerId : game.getState().getPlayersInRange(controllerId, game)) { for (UUID playerId : game.getState().getPlayersInRange(controllerId, game)) {
res.addAll(getAllCards(game, playerId)); res.addAll(getCardsOwned(game, playerId));
} }
return res; return res;
} }
/**
* Returns all cards in exile matching the filter, in range of the specified player
*/
public Set<Card> getCardsInRange(FilterCard filter, UUID playerId, Ability source, Game game) {
return getCardsInRange(game, playerId)
.stream()
.filter(card -> filter.match(card, playerId, source, game))
.collect(Collectors.toCollection(LinkedHashSet::new));
}
public boolean removeCard(Card card) { public boolean removeCard(Card card) {
for (ExileZone exile : exileZones.values()) { for (ExileZone exile : exileZones.values()) {
if (exile.contains(card.getId())) { if (exile.contains(card.getId())) {

View file

@ -48,7 +48,6 @@ public class KayaTheInexorableEmblem extends Emblem {
class KayaTheInexorableEmblemEffect extends OneShotEffect { class KayaTheInexorableEmblemEffect extends OneShotEffect {
private static final FilterCard filter = new FilterOwnedCard();
private static final FilterCard filter2 = new FilterCard(); private static final FilterCard filter2 = new FilterCard();
private static final Set<String> choices = new LinkedHashSet<>(); private static final Set<String> choices = new LinkedHashSet<>();
@ -94,7 +93,7 @@ class KayaTheInexorableEmblemEffect extends OneShotEffect {
cards.addAll(player.getGraveyard()); cards.addAll(player.getGraveyard());
break; break;
case "Exile": case "Exile":
cards.addAllCards(game.getExile().getCards(filter, game)); cards.addAllCards(game.getExile().getCardsOwned(game, player.getId()));
break; break;
} }
return CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter2); return CardUtil.castSpellWithAttributesForFree(player, source, game, cards, filter2);

View file

@ -134,7 +134,7 @@ public class TargetCard extends TargetObject {
protected static Set<UUID> getAllPossibleTargetInExile(Game game, Player player, UUID sourceControllerId, Ability source, FilterCard filter, boolean isNotTarget) { protected static Set<UUID> getAllPossibleTargetInExile(Game game, Player player, UUID sourceControllerId, Ability source, FilterCard filter, boolean isNotTarget) {
Set<UUID> possibleTargets = new HashSet<>(); Set<UUID> possibleTargets = new HashSet<>();
UUID sourceId = source != null ? source.getSourceId() : null; UUID sourceId = source != null ? source.getSourceId() : null;
for (Card card : game.getExile().getAllCardsByRange(game, sourceControllerId)) { for (Card card : game.getExile().getCardsInRange(game, sourceControllerId)) {
if (filter.match(card, sourceControllerId, source, game)) { if (filter.match(card, sourceControllerId, source, game)) {
possibleTargets.add(card.getId()); possibleTargets.add(card.getId());
} }

View file

@ -115,7 +115,7 @@ public class TargetSource extends TargetObject {
} }
} }
} }
for (Card card : game.getExile().getAllCards(game)) { for (Card card : game.getExile().getCardsInRange(game, sourceControllerId)) {
if (filter.match(card, sourceControllerId, source, game)) { if (filter.match(card, sourceControllerId, source, game)) {
possibleTargets.add(card.getId()); possibleTargets.add(card.getId());
} }

View file

@ -52,7 +52,7 @@ public class TargetCardInExile extends TargetCard {
Set<UUID> possibleTargets = new HashSet<>(); Set<UUID> possibleTargets = new HashSet<>();
if (zoneId == null) { // no specific exile zone if (zoneId == null) { // no specific exile zone
for (Card card : game.getExile().getAllCardsByRange(game, sourceControllerId)) { for (Card card : game.getExile().getCardsInRange(game, sourceControllerId)) {
if (filter.match(card, sourceControllerId, source, game)) { if (filter.match(card, sourceControllerId, source, game)) {
possibleTargets.add(card.getId()); possibleTargets.add(card.getId());
} }

View file

@ -66,7 +66,7 @@ public class TargetPermanentOrSuspendedCard extends TargetImpl {
possibleTargets.add(permanent.getId()); possibleTargets.add(permanent.getId());
} }
} }
for (Card card : game.getExile().getAllCards(game)) { for (Card card : game.getExile().getCardsInRange(game, sourceControllerId)) {
if (filter.match(card, sourceControllerId, source, game)) { if (filter.match(card, sourceControllerId, source, game)) {
possibleTargets.add(card.getId()); possibleTargets.add(card.getId());
} }