more refactoring

This commit is contained in:
theelk801 2024-09-28 15:20:07 -04:00
parent 3307eb31a5
commit d69bc200d4
26 changed files with 335 additions and 506 deletions

View file

@ -1,9 +1,6 @@
package mage.cards.d;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.LeavesBattlefieldAllTriggeredAbility;
@ -20,15 +17,18 @@ import mage.constants.SetTargetPointer;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.mageobject.SharesNamePredicate;
import mage.filter.predicate.permanent.TokenPredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.util.CardUtil;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
*
* @author TheElk801
*/
public final class DualNature extends CardImpl {
@ -129,7 +129,7 @@ class DualNatureCreatureLeavesEffect extends OneShotEffect {
if (creature != null) {
FilterPermanent filter = new FilterPermanent();
filter.add(TokenPredicate.TRUE);
filter.add(new NamePredicate(creature.getName()));
filter.add(new SharesNamePredicate(creature));
new ExileAllEffect(filter).apply(game, source);
return true;
}

View file

@ -1,8 +1,5 @@
package mage.cards.e;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.ActivateIfConditionActivatedAbility;
import mage.abilities.condition.Condition;
@ -16,9 +13,11 @@ import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.util.RandomUtil;
import java.util.*;
/**
*
* @author TheElk801
*/
public final class EndlessAtlas extends CardImpl {
@ -31,7 +30,7 @@ public final class EndlessAtlas extends CardImpl {
Zone.BATTLEFIELD,
new DrawCardSourceControllerEffect(1),
new GenericManaCost(2),
new EndlessAtlasCondition()
EndlessAtlasCondition.instance
);
ability.addCost(new TapSourceCost());
this.addAbility(ability);
@ -47,21 +46,27 @@ public final class EndlessAtlas extends CardImpl {
}
}
class EndlessAtlasCondition implements Condition {
enum EndlessAtlasCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
Map<String, Integer> landMap = new HashMap<>();
for (Permanent land : game.getBattlefield().getActivePermanents(
Set<Permanent> lands = new HashSet<>(game.getBattlefield().getActivePermanents(
StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND,
source.getControllerId(), game
)) {
if (land != null) {
int landCount = landMap.getOrDefault(land.getName(), 0);
if (landCount > 1) {
source.getControllerId(), source, game
));
while (lands.size() >= 3) {
Permanent land = RandomUtil.randomFromCollection(lands);
lands.remove(land);
int amount = 0;
for (Permanent permanent : lands) {
if (!permanent.sharesName(land, game)) {
continue;
}
amount++;
if (amount >= 3) {
return true;
}
landMap.put(land.getName(), landCount + 1);
}
}
return false;

View file

@ -65,16 +65,16 @@ class EscapedShapeshifterEffect extends ContinuousEffectImpl {
if (sourcePermanent == null) {
return false;
}
game.getBattlefield()
.getActivePermanents(
StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE,
source.getControllerId(), source, game
).stream()
.filter(Objects::nonNull)
.filter(permanent -> !permanent.getName().equals("Escaped Shapeshifter"))
.filter(permanent -> !permanent.hasName("Escaped Shapeshifter", game))
.map(Permanent::getAbilities)
.flatMap(Collection::stream).filter(EscapedShapeshifterEffect::checkAbility)
.flatMap(Collection::stream)
.filter(EscapedShapeshifterEffect::checkAbility)
.forEach(ability -> sourcePermanent.addAbility(ability, source.getSourceId(), game));
return true;
}
@ -97,4 +97,4 @@ class EscapedShapeshifterEffect extends ContinuousEffectImpl {
public EscapedShapeshifterEffect copy() {
return new EscapedShapeshifterEffect(this);
}
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.e;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.Effect;
@ -11,11 +9,7 @@ import mage.abilities.mana.TriggeredManaAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.AbilityWord;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.constants.*;
import mage.filter.common.FilterLandPermanent;
import mage.game.Game;
import mage.game.events.GameEvent;
@ -27,8 +21,9 @@ import mage.target.common.TargetLandPermanent;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class ExtraplanarLens extends CardImpl {
@ -123,8 +118,8 @@ class ExtraplanarLensTriggeredAbility extends TriggeredManaAbility {
Card imprinted = game.getCard(extraplanarLens.getImprinted().get(0));
if (imprinted != null
&& game.getState().getZone(imprinted.getId()) == Zone.EXILED) {
if (landTappedForMana.getName().equals(imprinted.getName())
&& landTappedForMana.isLand(game)) {
if (landTappedForMana.isLand(game)
&& landTappedForMana.sharesName(imprinted, game)) {
ManaEvent mEvent = (ManaEvent) event;
for (Effect effect : getEffects()) {
effect.setValue("mana", mEvent.getMana());

View file

@ -1,8 +1,7 @@
package mage.cards.e;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
@ -10,25 +9,31 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
*
* @author spjspj
*/
public final class EyeOfSingularity extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("a permanent other than a basic land");
static {
filter.add(Predicates.not(Predicates.or(
SuperType.BASIC.getPredicate(),
CardType.LAND.getPredicate()
)));
}
public EyeOfSingularity(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}");
@ -38,7 +43,7 @@ public final class EyeOfSingularity extends CardImpl {
this.addAbility(new EntersBattlefieldTriggeredAbility(new EyeOfSingularityETBEffect()));
// Whenever a permanent other than a basic land enters the battlefield, destroy all other permanents with that name. They can't be regenerated.
this.addAbility(new EyeOfSingularityTriggeredAbility());
this.addAbility(new EntersBattlefieldAllTriggeredAbility(new EyeOfSingularityTriggeredEffect(), filter));
}
private EyeOfSingularity(final EyeOfSingularity card) {
@ -56,12 +61,16 @@ class EyeOfSingularityETBEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterPermanent();
static {
filter.add(Predicates.not(SuperType.BASIC.getPredicate()));
filter.add(Predicates.not(Predicates.or(
SuperType.BASIC.getPredicate(),
CardType.LAND.getPredicate()
)));
}
EyeOfSingularityETBEffect() {
super(Outcome.Benefit);
this.staticText = "destroy each permanent with the same name as another permanent, except for basic lands. They can't be regenerated";
this.staticText = "destroy each permanent with the same name as another permanent, " +
"except for basic lands. They can't be regenerated";
}
private EyeOfSingularityETBEffect(final EyeOfSingularityETBEffect effect) {
@ -75,80 +84,23 @@ class EyeOfSingularityETBEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Map<String, UUID> cardNames = new HashMap<>();
Map<UUID, Integer> toDestroy = new HashMap<>();
Set<Permanent> permanents = CardUtil.streamAllPairwiseMatches(
game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game),
(p1, p2) -> p1.sharesName(p2, game)
).collect(Collectors.toSet());
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) {
String cardName = permanent.getName();
if (cardNames.get(cardName) == null) {
cardNames.put(cardName, permanent.getId());
} else {
toDestroy.put(cardNames.get(cardName), 1);
toDestroy.put(permanent.getId(), 1);
}
}
for (UUID id : toDestroy.keySet()) {
Permanent permanent = game.getPermanent(id);
if (permanent != null) {
permanent.destroy(source, game, false);
}
for (Permanent permanent : permanents) {
permanent.destroy(source, game, true);
}
return true;
}
}
class EyeOfSingularityTriggeredAbility extends TriggeredAbilityImpl {
EyeOfSingularityTriggeredAbility() {
super(Zone.BATTLEFIELD, new EyeOfSingularityTriggeredEffect(), false);
}
private EyeOfSingularityTriggeredAbility(final EyeOfSingularityTriggeredAbility ability) {
super(ability);
}
@Override
public EyeOfSingularityTriggeredAbility copy() {
return new EyeOfSingularityTriggeredAbility(this);
}
@Override
public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD;
}
@Override
public boolean checkTrigger(GameEvent event, Game game) {
UUID targetId = event.getTargetId();
Permanent permanent = game.getPermanent(targetId);
if (event.getTargetId().equals(this.getSourceId())) {
return false;
}
if (permanent != null && !permanent.isBasic(game)) {
getEffects().get(0).setTargetPointer(new FixedTarget(event.getTargetId()));
return true;
}
return false;
}
@Override
public String getRule() {
return "Whenever a permanent other than a basic land enters the battlefield, destroy all other permanents with that name. They can't be regenerated.";
}
}
class EyeOfSingularityTriggeredEffect extends OneShotEffect {
private static final FilterPermanent filter = new FilterPermanent();
static {
filter.add(Predicates.not(SuperType.BASIC.getPredicate()));
}
EyeOfSingularityTriggeredEffect() {
super(Outcome.DestroyPermanent);
staticText = "destroy all other permanents with that name. They cant be regenerated";
}
private EyeOfSingularityTriggeredEffect(final EyeOfSingularityTriggeredEffect effect) {
@ -157,28 +109,20 @@ class EyeOfSingularityTriggeredEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Map<UUID, Integer> toDestroy = new HashMap<>();
Permanent etbPermanent = getTargetPointer().getFirstTargetPermanentOrLKI(game, source);
if (etbPermanent == null) {
Permanent permanent = (Permanent) getValue("permanentEnteringBattlefield");
if (permanent == null) {
return false;
}
String cn = etbPermanent.getName();
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) {
String cardName = permanent.getName();
if (cardName.equals(cn) && !Objects.equals(permanent.getId(), etbPermanent.getId())) {
toDestroy.put(permanent.getId(), 1);
}
Set<Permanent> permanents = game
.getBattlefield()
.getActivePermanents(StaticFilters.FILTER_PERMANENT, source.getControllerId(), source, game)
.stream()
.filter(p -> !p.equals(permanent))
.filter(p -> p.sharesName(permanent, game))
.collect(Collectors.toSet());
for (Permanent p : permanents) {
p.destroy(source, game, true);
}
for (UUID id : toDestroy.keySet()) {
Permanent permanent = game.getPermanent(id);
if (permanent != null) {
permanent.destroy(source, game, false);
}
}
return true;
}

View file

@ -1,7 +1,6 @@
package mage.cards.f;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
@ -92,7 +91,6 @@ enum FrostpyreArcanistPredicate implements ObjectSourcePlayerPredicate<Card> {
.getGraveyard()
.getCards(game)
.stream()
.map(MageObject::getName)
.anyMatch(input.getObject().getName()::equals);
.anyMatch(card -> card.sharesName(input.getObject(), game));
}
}

View file

@ -98,7 +98,7 @@ class GoblinArtisansTarget extends TargetSpell {
if (permanent != null
&& !sourceRef.refersTo(permanent, game)
&& permanent.isCreature(game)
&& "Goblin Artisans".equals(permanent.getName())
&& permanent.hasName("Goblin Artisans", game)
&& stackObject
.getStackAbility()
.getTargets()

View file

@ -1,6 +1,5 @@
package mage.cards.g;
import java.util.*;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.TriggeredAbilityImpl;
@ -28,8 +27,9 @@ import mage.target.targetpointer.FirstTargetPointer;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
import java.util.*;
/**
*
* @author LevelX2
*/
public final class Godsend extends CardImpl {
@ -201,7 +201,7 @@ class GodsendRuleModifyingEffect extends ContinuousRuleModifyingEffectImpl {
ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source));
if ((exileZone != null)) {
for (Card card : exileZone.getCards(game)) {
if ((card.getName().equals(object.getName()))) {
if ((card.sharesName(object, game))) {
return true;
}
}

View file

@ -1,7 +1,6 @@
package mage.cards.g;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility;
import mage.abilities.dynamicvalue.common.ControllerGainedLifeCount;
@ -40,15 +39,11 @@ public final class GollumObsessedStalker extends CardImpl {
this.addAbility(new SkulkAbility());
// At the beginning of your end step, each opponent dealt combat damage this game by a creature named Gollum, Obsessed Stalker loses life equal to the amount of life you gained this turn.
Ability ability = new BeginningOfYourEndStepTriggeredAbility(
new GollumObsessedStalkerEffect(),
false
);
Ability ability = new BeginningOfYourEndStepTriggeredAbility(new GollumObsessedStalkerEffect(), false);
ability.addWatcher(new PlayerGainedLifeWatcher());
ability.addWatcher(new GollumObsessedStalkerWatcher());
ability.addHint(ControllerGainedLifeCount.getHint());
ability.addHint(GollumObsessedStalkerHint.instance);
this.addAbility(ability);
}
@ -64,8 +59,8 @@ public final class GollumObsessedStalker extends CardImpl {
class GollumObsessedStalkerWatcher extends Watcher {
// For each creature name, the players damaged by them during combat.
private final Map<String, Set<UUID>> playersPerName = new HashMap<>();
// Players damaged by creatures named Gollum, Obsessed Stalker during combat.
private final Set<UUID> players = new HashSet<>();
public GollumObsessedStalkerWatcher() {
super(WatcherScope.GAME);
@ -78,22 +73,14 @@ class GollumObsessedStalkerWatcher extends Watcher {
return;
}
Permanent creature = game.getPermanent(event.getSourceId());
if (creature == null) {
return;
if (creature != null && creature.isCreature(game)
&& creature.hasName("Gollum, Obsessed Stalker", game)) {
players.add(event.getPlayerId());
}
String name = creature.getName();
UUID playerId = event.getPlayerId();
if (creature.getName().isEmpty() || playerId == null) {
return;
}
playersPerName.computeIfAbsent(name, k -> new HashSet<>());
playersPerName.get(name).add(playerId);
}
public Set<UUID> getPlayersDamagedByNamed(String name) {
return playersPerName.getOrDefault(name, new HashSet<>());
public Set<UUID> getPlayersDamagedByNamed() {
return players;
}
}
@ -101,8 +88,8 @@ class GollumObsessedStalkerEffect extends OneShotEffect {
GollumObsessedStalkerEffect() {
super(Outcome.LoseLife);
staticText = "each opponent dealt combat damage this game by a creature named "
+ "{this} loses life equal to the amount of life you gained this turn.";
staticText = "each opponent dealt combat damage this game by a creature named " +
"Gollum, Obsessed Stalker loses life equal to the amount of life you gained this turn.";
}
private GollumObsessedStalkerEffect(final GollumObsessedStalkerEffect effect) {
@ -118,14 +105,12 @@ class GollumObsessedStalkerEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
GollumObsessedStalkerWatcher damageWatcher = game.getState().getWatcher(GollumObsessedStalkerWatcher.class);
PlayerGainedLifeWatcher lifeWatcher = game.getState().getWatcher(PlayerGainedLifeWatcher.class);
Permanent gollum = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (damageWatcher == null || lifeWatcher == null || gollum == null) {
if (damageWatcher == null || lifeWatcher == null) {
return false;
}
String name = gollum.getName();
int amount = lifeWatcher.getLifeGained(source.getControllerId());
Set<UUID> playersDamaged = damageWatcher.getPlayersDamagedByNamed(name);
Set<UUID> playersDamaged = damageWatcher.getPlayersDamagedByNamed();
if (amount == 0 || playersDamaged.isEmpty()) {
return true;
@ -135,12 +120,10 @@ class GollumObsessedStalkerEffect extends OneShotEffect {
if (!playersDamaged.contains(playerId)) {
continue;
}
Player player = game.getPlayer(playerId);
if (player == null) {
continue;
}
player.loseLife(amount, game, source, false);
}
@ -153,39 +136,19 @@ enum GollumObsessedStalkerHint implements Hint {
@Override
public String getText(Game game, Ability ability) {
GollumObsessedStalkerWatcher watcher = game.getState().getWatcher(GollumObsessedStalkerWatcher.class);
if (watcher == null) {
return "";
}
String name = null;
Permanent gollum = game.getPermanentOrLKIBattlefield(ability.getSourceId());
if (gollum != null) {
// Gollum is or was in play, its name is using LKI.
name = gollum.getName();
} else {
// if Gollum LKI not in play (like in hand or in command zone),
// find the object.
MageObject gollumObj = game.getObject(ability.getSourceId());
if (gollumObj != null) {
name = gollumObj.getName();
}
}
if (name == null || name.isEmpty()) {
return "";
}
// Not filtering by opponent intentionally, just to provide full info everywhere.
List<String> namesOfPlayersDealtDamage =
watcher.getPlayersDamagedByNamed(name)
.stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.map(Player::getName)
.filter(n -> !n.isEmpty())
.collect(Collectors.toList());
List<String> namesOfPlayersDealtDamage = game
.getState()
.getWatcher(GollumObsessedStalkerWatcher.class)
.getPlayersDamagedByNamed()
.stream()
.map(game::getPlayer)
.filter(Objects::nonNull)
.map(Player::getName)
.filter(n -> !n.isEmpty())
.collect(Collectors.toList());
return "Players dealt combat damage by creatures named " + name + " this game: ["
return "Players dealt combat damage by creatures named Gollum, Obsessed Stalker this game: ["
+ String.join(", ", namesOfPlayersDealtDamage)
+ "]";
}

View file

@ -1,11 +1,10 @@
package mage.cards.h;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
@ -14,9 +13,7 @@ import mage.players.Player;
import mage.target.TargetPlayer;
import mage.util.CardUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
@ -62,26 +59,14 @@ class HintOfInsanityEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getFirstTarget());
Player player = game.getPlayer(getTargetPointer().getFirst(game, source));
if (player == null) {
return false;
}
Map<String, Integer> nameCounts = new HashMap<>();
player.getHand()
.getCards(game)
.stream()
.map(MageObject::getName)
.forEach(s -> nameCounts.compute(s, CardUtil::setOrIncrementValue));
Cards cards = new CardsImpl(
player.getHand()
.getCards(game)
.stream()
.filter(Objects::nonNull)
.filter(card -> !card.isLand(game))
.filter(card -> nameCounts.getOrDefault(card.getName(), 0) > 1)
.collect(Collectors.toSet())
);
player.discard(cards, false, source, game);
return true;
Set<Card> cards = CardUtil.streamAllPairwiseMatches(
player.getHand().getCards(game),
(p1, p2) -> p1.sharesName(p2, game)
).collect(Collectors.toSet());
return !cards.isEmpty() && !player.discard(new CardsImpl(cards), false, source, game).isEmpty();
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.h;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Card;
@ -21,7 +19,6 @@ import java.util.Set;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class HourOfGlory extends CardImpl {
@ -63,28 +60,27 @@ class HourOfGloryEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (controller != null && sourceObject != null) {
Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
if (targetCreature != null) {
controller.moveCards(targetCreature, Zone.EXILED, source, game);
if (targetCreature.hasSubtype(SubType.GOD, game)) {
game.processAction();
Player targetController = game.getPlayer(targetCreature.getControllerId());
if (targetController != null) {
targetController.revealCards(sourceObject.getIdName(), targetController.getHand(), game);
Set<Card> toExile = new HashSet<>();
for (Card card : targetController.getHand().getCards(game)) {
if (card.getName().equals(targetCreature.getName())) {
toExile.add(card);
}
}
targetController.moveCards(toExile, Zone.EXILED, source, game);
}
}
}
Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source));
if (controller == null || targetCreature == null) {
return false;
}
controller.moveCards(targetCreature, Zone.EXILED, source, game);
if (!targetCreature.hasSubtype(SubType.GOD, game)) {
return true;
}
return false;
game.processAction();
Player targetController = game.getPlayer(targetCreature.getControllerId());
if (targetController == null) {
return true;
}
targetController.revealCards(source, targetController.getHand(), game);
Set<Card> toExile = new HashSet<>();
for (Card card : targetController.getHand().getCards(game)) {
if (card.sharesName(targetCreature, game)) {
toExile.add(card);
}
}
targetController.moveCards(toExile, Zone.EXILED, source, game);
return true;
}
}

View file

@ -1,6 +1,5 @@
package mage.cards.j;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.*;
@ -131,12 +130,11 @@ class JourneyForTheElixirLibraryTarget extends TargetCardInLibrary {
.anyMatch(c -> c.isLand(game))) {
return false;
}
if (name.equals(card.getName())
if (card.hasName(name, game)
&& cards
.getCards(game)
.stream()
.map(MageObject::getName)
.anyMatch(name::equals)) {
.anyMatch(c -> c.hasName(name, game))) {
return false;
}
return true;
@ -198,13 +196,12 @@ class JourneyForTheElixirGraveyardTarget extends TargetCardInYourGraveyard {
.getCards(game)
.stream()
.filter(Objects::nonNull)
.map(MageObject::getName)
.anyMatch(name::equals);
.anyMatch(card -> card.hasName(name, game));
possibleTargets.removeIf(uuid -> {
Card card = game.getCard(uuid);
return card != null
&& hasYanggu
&& name.equals(card.getName());
&& card.hasName(name, game);
});
return possibleTargets;
}

View file

@ -10,7 +10,7 @@ import mage.cards.*;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.mageobject.SharesNamePredicate;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
@ -100,7 +100,7 @@ class KotoseTheSilentSpiderEffect extends OneShotEffect {
controller.moveCardsToExile(card, source, game, true, exileId, exileName);
Cards cards = new CardsImpl();
FilterCard filter = new FilterCard("cards named " + card.getName() + " from " + opponent.getName() + "'s graveyard");
filter.add(new NamePredicate(card.getName()));
filter.add(new SharesNamePredicate(card));
TargetCardInGraveyard targetCardInGraveyard = new TargetCardInGraveyard(0, Integer.MAX_VALUE, filter);
controller.choose(outcome, opponent.getGraveyard(), targetCardInGraveyard, source, game);

View file

@ -71,7 +71,7 @@ class LegionsEndEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent == null) {
return false;
}
@ -79,32 +79,28 @@ class LegionsEndEffect extends OneShotEffect {
if (player == null) {
return false;
}
String name = permanent.getName();
if (name == null || name.equals("")) {
player.revealCards(source, player.getHand(), game);
return player.moveCards(permanent, Zone.EXILED, source, game);
}
Cards cards = new CardsImpl();
game.getBattlefield()
.getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, player.getId(), game)
.getActivePermanents(StaticFilters.FILTER_CONTROLLED_CREATURE, player.getId(), source, game)
.stream()
.filter(perm -> name.equals(perm.getName()))
.filter(perm -> perm.sharesName(permanent, game))
.forEach(cards::add);
player.moveCards(cards, Zone.EXILED, source, game);
cards.clear();
player.revealCards(source, player.getHand(), game);
player.getHand()
.getCards(game)
.stream()
.filter(card -> name.equals(card.getName()))
.filter(card -> card.sharesName(permanent, game))
.forEach(cards::add);
player.getGraveyard()
.getCards(game)
.stream()
.filter(card -> name.equals(card.getName()))
.filter(card -> card.sharesName(permanent, game))
.forEach(cards::add);
return player.moveCards(cards, Zone.EXILED, source, game);
}
}
}

View file

@ -1,21 +1,23 @@
package mage.cards.l;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.constants.CardType;
import mage.constants.CostModificationType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class LocketOfYesterdays extends CardImpl {
@ -24,7 +26,7 @@ public final class LocketOfYesterdays extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}");
// Spells you cast cost {1} less to cast for each card with the same name as that spell in your graveyard.
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LocketOfYesterdaysCostReductionEffect()));
this.addAbility(new SimpleStaticAbility(new LocketOfYesterdaysCostReductionEffect()));
}
private LocketOfYesterdays(final LocketOfYesterdays card) {
@ -50,36 +52,32 @@ class LocketOfYesterdaysCostReductionEffect extends CostModificationEffectImpl {
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
Player player = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(abilityToModify.getSourceId());
if (sourceObject != null) {
int amount = 0;
for (UUID cardId : game.getPlayer(source.getControllerId()).getGraveyard()) {
Card card = game.getCard(cardId);
if (card != null && card.getName().equals(sourceObject.getName())) {
amount++;
}
}
if (amount > 0) {
SpellAbility spellAbility = (SpellAbility) abilityToModify;
CardUtil.adjustCost(spellAbility, amount);
}
return true;
if (player == null || sourceObject == null) {
return false;
}
return false;
int amount = player
.getGraveyard()
.getCards(game)
.stream()
.filter(card -> card.sharesName(sourceObject, game))
.mapToInt(x -> 1)
.sum();
if (amount > 0) {
CardUtil.adjustCost((SpellAbility) abilityToModify, amount);
}
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
if (abilityToModify.isControlledBy(source.getControllerId())
&& (abilityToModify instanceof SpellAbility)) {
return true;
}
return false;
return abilityToModify.isControlledBy(source.getControllerId())
&& abilityToModify instanceof SpellAbility;
}
@Override
public LocketOfYesterdaysCostReductionEffect copy() {
return new LocketOfYesterdaysCostReductionEffect(this);
}
}

View file

@ -1,7 +1,6 @@
package mage.cards.l;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.common.CastFromEverywhereSourceCondition;
@ -20,11 +19,11 @@ import mage.constants.TargetController;
import mage.filter.FilterSpell;
import mage.filter.common.FilterInstantOrSorcerySpell;
import mage.target.TargetSpell;
import mage.util.CardUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author TheElk801
@ -84,14 +83,10 @@ enum LutriTheSpellchaserCompanionCondition implements CompanionCondition {
@Override
public boolean isLegal(Set<Card> deck, int minimumDeckSize) {
Map<String, Integer> cardMap = new HashMap<>();
deck.stream()
Set<Card> cards = deck
.stream()
.filter(card -> !card.hasCardTypeForDeckbuilding(CardType.LAND))
.map(MageObject::getName)
.forEach(s -> {
cardMap.putIfAbsent(s, 0);
cardMap.compute(s, (str, i) -> i + 1);
});
return cardMap.values().stream().noneMatch(i -> i > 1);
.collect(Collectors.toSet());
return cards.size() == CardUtil.differentlyNamedAmongCollection(cards, null);
}
}

View file

@ -2,8 +2,12 @@ package mage.cards.m;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.CreateTokenCopyTargetEffect;
import mage.abilities.effects.common.WinGameSourceControllerEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -11,19 +15,16 @@ import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.common.FilterArtifactPermanent;
import mage.filter.common.FilterControlledArtifactPermanent;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.Token;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.target.common.TargetControlledPermanent;
import mage.util.functions.CopyTokenFunction;
import mage.util.RandomUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
/**
@ -37,14 +38,20 @@ public final class MechanizedProduction extends CardImpl {
this.subtype.add(SubType.AURA);
// Enchant artifact you control
TargetPermanent auraTarget = new TargetControlledPermanent(new FilterControlledArtifactPermanent());
TargetPermanent auraTarget = new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT);
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.Copy));
Ability ability = new EnchantAbility(auraTarget);
this.addAbility(ability);
this.addAbility(new EnchantAbility(auraTarget));
// At the beginning of your upkeep, create a token that's a copy of enchanted artifact. Then if you control eight or more artifacts with the same name as one another, you win the game.
this.addAbility(new BeginningOfUpkeepTriggeredAbility(new MechanizedProductionEffect(), TargetController.YOU, false));
Ability ability = new BeginningOfUpkeepTriggeredAbility(
new MechanizedProductionEffect(), TargetController.YOU, false
);
ability.addEffect(new ConditionalOneShotEffect(
new WinGameSourceControllerEffect(), MechanizedProductionCondition.instance,
"Then if you control eight or more artifacts with the same name as one another, you win the game"
));
this.addAbility(ability);
}
private MechanizedProduction(final MechanizedProduction card) {
@ -61,7 +68,7 @@ class MechanizedProductionEffect extends OneShotEffect {
MechanizedProductionEffect() {
super(Outcome.Benefit);
this.staticText = "create a token that's a copy of enchanted artifact. Then if you control eight or more artifacts with the same name as one another, you win the game";
this.staticText = "create a token that's a copy of enchanted artifact";
}
private MechanizedProductionEffect(final MechanizedProductionEffect effect) {
@ -75,30 +82,40 @@ class MechanizedProductionEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId());
if (sourceObject != null && sourceObject.getAttachedTo() != null) {
Permanent enchantedArtifact = game.getPermanentOrLKIBattlefield(sourceObject.getAttachedTo());
if (enchantedArtifact != null) {
Token token = CopyTokenFunction.createTokenCopy(enchantedArtifact, game);
token.putOntoBattlefield(1, game, source, source.getControllerId());
}
Map<String, Integer> countNames = new HashMap<>();
for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), source.getControllerId(), game)) {
int counter = countNames.getOrDefault(permanent.getName(), 0);
countNames.put(permanent.getName(), counter + 1);
}
for (Entry<String, Integer> entry : countNames.entrySet()) {
if (entry.getValue() > 7) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
game.informPlayers(controller.getLogName() + " controls eight or more artifacts with the same name as one another (" + entry.getKey() + ").");
controller.won(game);
return true;
}
Permanent enchantedArtifact = Optional
.ofNullable(source.getSourcePermanentOrLKI(game))
.map(Permanent::getAttachedTo)
.map(game::getPermanentOrLKIBattlefield)
.orElse(null);
return enchantedArtifact != null
&& new CreateTokenCopyTargetEffect()
.setSavedPermanent(enchantedArtifact)
.apply(game, source);
}
}
enum MechanizedProductionCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
Set<Permanent> artifacts = new HashSet<>(game.getBattlefield().getActivePermanents(
StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT,
source.getControllerId(), source, game
));
while (artifacts.size() >= 8) {
Permanent artifact = RandomUtil.randomFromCollection(artifacts);
artifacts.remove(artifact);
int amount = 0;
for (Permanent permanent : artifacts) {
if (!permanent.sharesName(artifact, game)) {
continue;
}
amount++;
if (amount >= 8) {
return true;
}
}
return true;
}
return false;
}

View file

@ -108,7 +108,7 @@ class MedomaisProphecyDelayedTriggeredAbility extends DelayedTriggeredAbility {
return false;
}
Spell spell = game.getStack().getSpell(event.getTargetId());
return spell != null && spellName.equals(spell.getName());
return spell != null && spell.hasName(spellName, game);
}
@Override

View file

@ -1,18 +1,13 @@
package mage.cards.m;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
@ -21,8 +16,9 @@ import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import java.util.UUID;
/**
*
* @author BetaSteward
*/
public final class MirrorMadPhantasm extends CardImpl {
@ -74,7 +70,7 @@ class MirrorMadPhantasmEffect extends OneShotEffect {
Card phantasmCard = null;
for (Card card : owner.getLibrary().getCards(game)) {
cards.add(card);
if (card.getName().equals("Mirror-Mad Phantasm")) {
if (card.hasName("Mirror-Mad Phantasm", game)) {
phantasmCard = card;
break;
}

View file

@ -1,34 +1,34 @@
package mage.cards.p;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.common.FilterCreatureCard;
import mage.filter.predicate.ObjectSourcePlayer;
import mage.filter.predicate.ObjectSourcePlayerPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.common.TargetCardInLibrary;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public final class PatternMatcher extends CardImpl {
private static final FilterCard filter = new FilterCreatureCard("a creature card with the same name as another creature you control");
static {
filter.add(RegularExpression.instance);
}
public PatternMatcher(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}");
@ -37,7 +37,9 @@ public final class PatternMatcher extends CardImpl {
this.toughness = new MageInt(3);
// When Pattern Matcher enters the battlefield, you may search your library for a creature card with the same name as another creature you control, reveal it, put it into your hand, then shuffle your library.
this.addAbility(new EntersBattlefieldTriggeredAbility(new RegularExpression(), true));
this.addAbility(new EntersBattlefieldTriggeredAbility(
new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), true
));
}
private PatternMatcher(final PatternMatcher card) {
@ -50,45 +52,19 @@ public final class PatternMatcher extends CardImpl {
}
}
class RegularExpression extends OneShotEffect {
RegularExpression() {
super(Outcome.Benefit);
staticText = "search your library for a card with the same name as another creature you control, " +
"reveal it, put it into your hand, then shuffle.";
}
private RegularExpression(final RegularExpression effect) {
super(effect);
}
enum RegularExpression implements ObjectSourcePlayerPredicate<Card> {
instance;
@Override
public RegularExpression copy() {
return new RegularExpression(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
List<NamePredicate> predicates = game
public boolean apply(ObjectSourcePlayer<Card> input, Game game) {
return game
.getState()
.getBattlefield()
.getActivePermanents(
StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE,
source.getControllerId(), source, game
).stream()
.map(Permanent::getName)
.filter(Objects::nonNull)
.filter(s -> !s.isEmpty())
.map(NamePredicate::new)
.collect(Collectors.toList());
FilterCard filter
= new FilterCard("a creature card with the same name as another creature you control");
filter.add(Predicates.or(predicates));
return new SearchLibraryPutInHandEffect(
new TargetCardInLibrary(filter), true
).apply(game, source);
StaticFilters.FILTER_OTHER_CONTROLLED_CREATURES,
input.getPlayerId(), input.getSource(), game
)
.stream()
.anyMatch(permanent -> permanent.sharesName(input.getObject(), game));
}
}

View file

@ -1,26 +1,29 @@
package mage.cards.r;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.dynamicvalue.common.GetXValue;
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.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.mageobject.SharesNamePredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInGraveyard;
import mage.target.common.TargetCardInHand;
import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetOpponent;
import mage.util.CardUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author jeffwadsworth
@ -36,7 +39,6 @@ public final class ReapIntellect extends CardImpl {
// same name as that card and exile them. Then that player shuffles their library.
this.getSpellAbility().addEffect(new ReapIntellectEffect());
this.getSpellAbility().addTarget(new TargetOpponent());
}
private ReapIntellect(final ReapIntellect card) {
@ -51,12 +53,6 @@ public final class ReapIntellect extends CardImpl {
class ReapIntellectEffect extends OneShotEffect {
private static final FilterCard filterNonLands = new FilterCard("up to X nonland cards");
static {
filterNonLands.add(Predicates.not(CardType.LAND.getPredicate()));
}
public ReapIntellectEffect() {
super(Outcome.Exile);
staticText = "Target opponent reveals their hand. You choose up to X "
@ -72,82 +68,51 @@ class ReapIntellectEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player targetPlayer = game.getPlayer(source.getFirstTarget());
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = game.getObject(source);
if (targetPlayer != null && sourceObject != null && controller != null) {
// reveal hand of target player
targetPlayer.revealCards(sourceObject.getName(), targetPlayer.getHand(), game);
// Chose cards to exile from hand
Cards exiledCards = new CardsImpl();
int xCost = Math.min(CardUtil.getSourceCostsTag(game, source, "X", 0), targetPlayer.getHand().size());
TargetCard target = new TargetCard(0, xCost, Zone.HAND, filterNonLands);
target.withNotTarget(true);
controller.chooseTarget(Outcome.Benefit, targetPlayer.getHand(), target, source, game);
for (UUID cardId : target.getTargets()) {
Card chosenCard = game.getCard(cardId);
if (chosenCard != null) {
controller.moveCardToExileWithInfo(chosenCard, null, "", source, game, Zone.HAND, true);
exiledCards.add(chosenCard);
}
}
// Exile other cards with the same name
// 4/15/2013 If you don't exile any cards from the player's hand, you don't search that player's library
if (!exiledCards.isEmpty()) {
// Building a card filter with all names
List<NamePredicate> names = new ArrayList<>();
FilterCard filterNamedCards = new FilterCard();
for (Card card : exiledCards.getCards(game)) {
String nameToSearch = CardUtil.getCardNameForSameNameSearch(card);
if (exiledCards.size() == 1) {
filterNamedCards.add(new NamePredicate(nameToSearch));
} else {
names.add(new NamePredicate(nameToSearch));
}
}
if (exiledCards.size() > 1) {
filterNamedCards.add(Predicates.or(names));
}
// search cards in graveyard
TargetCardInGraveyard targetCardsGraveyard = new TargetCardInGraveyard(0, Integer.MAX_VALUE, filterNamedCards);
controller.chooseTarget(outcome, targetPlayer.getGraveyard(), targetCardsGraveyard, source, game);
for (UUID cardId : targetCardsGraveyard.getTargets()) {
Card card = game.getCard(cardId);
if (card != null) {
controller.moveCardToExileWithInfo(card, null, "", source, game, Zone.GRAVEYARD, true);
}
}
// search cards in hand
TargetCard targetCardsHand = new TargetCard(0, Integer.MAX_VALUE, Zone.HAND, filterNamedCards);
controller.chooseTarget(Outcome.Benefit, targetPlayer.getGraveyard(), targetCardsHand, source, game);
for (UUID cardId : targetCardsHand.getTargets()) {
Card card = game.getCard(cardId);
if (card != null) {
controller.moveCardToExileWithInfo(card, null, "", source, game, Zone.HAND, true);
}
}
// search cards in Library
TargetCardInLibrary targetCardsLibrary = new TargetCardInLibrary(0, Integer.MAX_VALUE, filterNamedCards);
controller.searchLibrary(targetCardsLibrary, source, game, targetPlayer.getId());
for (UUID cardId : targetCardsLibrary.getTargets()) {
Card card = game.getCard(cardId);
if (card != null) {
controller.moveCardToExileWithInfo(card, null, "", source, game, Zone.LIBRARY, true);
}
}
}
Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source));
if (controller == null || targetPlayer == null) {
return false;
}
targetPlayer.revealCards(source, targetPlayer.getHand(), game);
TargetCard target = new TargetCardInHand(
0,
GetXValue.instance.calculate(game, source, this),
StaticFilters.FILTER_CARDS_NON_LAND
);
controller.chooseTarget(Outcome.Benefit, targetPlayer.getHand(), target, source, game);
Cards exiledCards = new CardsImpl(target.getTargets());
controller.moveCards(exiledCards, Zone.EXILED, source, game);
exiledCards.retainZone(Zone.EXILED, game);
if (exiledCards.isEmpty()) {
targetPlayer.shuffleLibrary(source, game);
return true;
}
return false;
FilterCard filterCard = new FilterCard("cards with the same name");
filterCard.add(Predicates.or(
exiledCards
.getCards(game)
.stream()
.map(SharesNamePredicate::new)
.collect(Collectors.toSet())
));
exiledCards.clear();
TargetCardInGraveyard targetCardInGraveyard = new TargetCardInGraveyard(0, Integer.MAX_VALUE, filterCard, true);
controller.choose(Outcome.Exile, targetPlayer.getGraveyard(), targetCardInGraveyard, source, game);
exiledCards.addAll(targetCardInGraveyard.getTargets());
TargetCardInHand targetCardInHand = new TargetCardInHand(0, Integer.MAX_VALUE, filterCard);
controller.choose(Outcome.Exile, targetPlayer.getHand(), targetCardInHand, source, game);
exiledCards.addAll(targetCardInHand.getTargets());
TargetCardInLibrary targetCardInLibrary = new TargetCardInLibrary(0, Integer.MAX_VALUE, filterCard);
controller.searchLibrary(targetCardInLibrary, source, game, targetPlayer.getId());
for (UUID cardId : targetCardInLibrary.getTargets()) {
exiledCards.add(targetPlayer.getLibrary().getCard(cardId, game));
}
targetPlayer.shuffleLibrary(source, game);
return true;
}
@Override

View file

@ -1,35 +1,35 @@
package mage.cards.s;
import java.util.ArrayList;
import mage.MageInt;
import mage.Mana;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.TapForManaAllTriggeredManaAbility;
import mage.abilities.costs.common.RevealHandSourceControllerCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.FlipSourceEffect;
import mage.abilities.effects.mana.ManaEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.choices.Choice;
import mage.choices.ChoiceColor;
import mage.constants.*;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledLandPermanent;
import mage.filter.common.FilterLandCard;
import mage.filter.common.FilterLandPermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.mageobject.SharesNamePredicate;
import mage.filter.predicate.permanent.PermanentIdPredicate;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.game.permanent.token.TokenImpl;
import mage.players.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.abilities.effects.Effect;
import mage.choices.Choice;
import mage.choices.ChoiceColor;
/**
* @author LevelX2
@ -143,14 +143,14 @@ class SasayasEssenceManaEffect extends ManaEffect {
if (controller != null && producedMana != null && permanent != null) {
FilterPermanent filter = new FilterLandPermanent();
filter.add(Predicates.not(new PermanentIdPredicate(permanent.getId())));
filter.add(new NamePredicate(permanent.getName()));
filter.add(new SharesNamePredicate(permanent));
int count = game.getBattlefield().countAll(filter, controller.getId(), game);
if (count > 0) {
if (producedMana.getBlack() > 0) {
netMana.add(Mana.BlackMana(count));
if (producedMana.getBlack() > 0) {
netMana.add(Mana.BlackMana(count));
}
if (producedMana.getRed() > 0) {
netMana.add(Mana.RedMana(count));
netMana.add(Mana.RedMana(count));
}
if (producedMana.getBlue() > 0) {
netMana.add(Mana.BlueMana(count));
@ -163,7 +163,7 @@ class SasayasEssenceManaEffect extends ManaEffect {
}
if (producedMana.getColorless() > 0) {
netMana.add(Mana.ColorlessMana(count));
}
}
}
}
return netMana;
@ -174,12 +174,12 @@ class SasayasEssenceManaEffect extends ManaEffect {
* RULINGS 6/1/2005 If Sasayas Essences controller has four Forests and
* taps one of them for Green, the Essence will add GreenGreenGreen to that
* players mana pool for a total of GreenGreenGreenGreen.
*
* <p>
* 6/1/2005 If Sasayas Essences controller has four Mossfire Valley and
* taps one of them for RedGreen, the Essence will add three mana (one for
* each other Mossfire Valley) of any combination of Red and/or Green to
* that players mana pool.
*
* <p>
* 6/1/2005 If Sasayas Essences controller has two Brushlands and taps one
* of them for White, Sasayas Essence adds another White to that players
* mana pool. It wont produce Green or Colorless unless the land was tapped
@ -197,7 +197,7 @@ class SasayasEssenceManaEffect extends ManaEffect {
if (controller != null && mana != null && permanent != null) {
FilterPermanent filter = new FilterLandPermanent();
filter.add(Predicates.not(new PermanentIdPredicate(permanent.getId())));
filter.add(new NamePredicate(permanent.getName()));
filter.add(new SharesNamePredicate(permanent));
int count = game.getBattlefield().countAll(filter, controller.getId(), game);
if (count > 0) {
Choice choice = new ChoiceColor(true);

View file

@ -18,9 +18,7 @@ import mage.util.CardUtil;
import java.util.Set;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author LevelX2
@ -75,13 +73,10 @@ class SphinxOfTheChimesTarget extends TargetCardInHand {
break;
}
Set<UUID> set = CardUtil
.streamPairsWithMap(
.streamAllPairwiseMatches(
possibleTargets,
(u1, u2) -> game.getCard(u1).sharesName(game.getCard(u2), game)
? Stream.of(u1, u2)
: Stream.<UUID>empty()
)
.flatMap(Function.identity())
.collect(Collectors.toSet());
possibleTargets.clear();
possibleTargets.addAll(set);

View file

@ -155,7 +155,7 @@ class YidaroWanderingMonsterWatcher extends Watcher {
return;
}
Card card = game.getCard(object.getSourceId());
if (card != null && "Yidaro, Wandering Monster".equals(card.getName())) {
if (card != null && card.hasName("Yidaro, Wandering Monster", game)) {
countMap.merge(object.getControllerId(), 1, Integer::sum);
}
}

View file

@ -37,7 +37,7 @@ import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.mageobject.NamePredicate;
import mage.filter.predicate.mageobject.SharesNamePredicate;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.filter.predicate.permanent.LegendRuleAppliesPredicate;
import mage.game.combat.Combat;
@ -2869,7 +2869,7 @@ public abstract class GameImpl implements Game {
for (Permanent legend : legendary) {
FilterPermanent filterLegendName = new FilterPermanent();
filterLegendName.add(SuperType.LEGENDARY.getPredicate());
filterLegendName.add(new NamePredicate(legend.getName()));
filterLegendName.add(new SharesNamePredicate(legend));
filterLegendName.add(new ControllerIdPredicate(legend.getControllerId()));
filterLegendName.add(LegendRuleAppliesPredicate.instance);
if (!getBattlefield().contains(filterLegendName, legend.getControllerId(), null, this, 2)) {

View file

@ -58,6 +58,7 @@ import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.ToIntFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@ -2169,6 +2170,19 @@ public final class CardUtil {
return stream.filter(clazz::isInstance).map(clazz::cast).filter(Objects::nonNull);
}
public static <T> boolean checkAnyPairs(Collection<T> collection, BiPredicate<T, T> predicate) {
return streamPairsWithMap(collection, (t1, t2) -> predicate.test(t1, t2)).anyMatch(x -> x);
}
public static <T> Stream<T> streamAllPairwiseMatches(Collection<T> collection, BiPredicate<T, T> predicate) {
return streamPairsWithMap(
collection,
(t1, t2) -> predicate.test(t1, t2)
? Stream.of(t1, t2)
: Stream.<T>empty()
).flatMap(Function.identity()).distinct();
}
private static class IntPairIterator implements Iterator<AbstractMap.SimpleImmutableEntry<Integer, Integer>> {
private final int amount;
private int firstCounter = 0;
@ -2201,13 +2215,7 @@ public final class CardUtil {
}
}
public static <T> boolean checkAnyPairs(Collection<T> collection, BiPredicate<T, T> predicate) {
return streamPairsWithMap(collection, (t1, t2) -> predicate.test(t1, t2)).anyMatch(x -> x);
}
public static <T, U> Stream<U> streamPairsWithMap(
Collection<T> collection,
BiFunction<T, T, U> function) {
public static <T, U> Stream<U> streamPairsWithMap(Collection<T> collection, BiFunction<T, T, U> function) {
if (collection.size() < 2) {
return Stream.empty();
}