From 388fb0b8fdd291120a8d9100ec51863367ac6b8e Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 9 Sep 2024 14:12:35 -0400 Subject: [PATCH 01/16] add hasName method --- Mage/src/main/java/mage/MageObject.java | 6 ++++++ Mage/src/main/java/mage/MageObjectImpl.java | 5 +++++ Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java | 5 +++++ Mage/src/main/java/mage/designations/Designation.java | 5 +++++ Mage/src/main/java/mage/game/command/Commander.java | 5 +++++ Mage/src/main/java/mage/game/command/Dungeon.java | 5 +++++ Mage/src/main/java/mage/game/command/Emblem.java | 6 +++++- Mage/src/main/java/mage/game/command/Plane.java | 6 ++++++ .../main/java/mage/game/command/emblems/TheRingEmblem.java | 5 +++++ Mage/src/main/java/mage/game/stack/Spell.java | 5 +++++ Mage/src/main/java/mage/game/stack/StackAbility.java | 5 +++++ 11 files changed, 57 insertions(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/MageObject.java b/Mage/src/main/java/mage/MageObject.java index 660759e8ab51..6b54aceebdeb 100644 --- a/Mage/src/main/java/mage/MageObject.java +++ b/Mage/src/main/java/mage/MageObject.java @@ -622,5 +622,11 @@ default boolean shareCreatureTypes(Game game, MageObject otherCard) { */ void setIsAllNonbasicLandTypes(Game game, boolean value); + default boolean hasName(String name) { + return hasName(name, null); + } + + boolean hasName(String name, Game game); + void removePTCDA(); } diff --git a/Mage/src/main/java/mage/MageObjectImpl.java b/Mage/src/main/java/mage/MageObjectImpl.java index 51a2dd48d674..4ffe5f13bde8 100644 --- a/Mage/src/main/java/mage/MageObjectImpl.java +++ b/Mage/src/main/java/mage/MageObjectImpl.java @@ -409,4 +409,9 @@ public void removePTCDA() { public String toString() { return getIdName() + " (" + super.getClass().getSuperclass().getSimpleName() + " -> " + this.getClass().getSimpleName() + ")"; } + + @Override + public boolean hasName(String name, Game game) { + return Objects.equals(name, this.name); + } } diff --git a/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java b/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java index eb8f3fcd19f2..52e60b3cb044 100644 --- a/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java +++ b/Mage/src/main/java/mage/cards/ModalDoubleFacedCard.java @@ -432,4 +432,9 @@ public MageInt getPower() { public MageInt getToughness() { return leftHalfCard.getToughness(); } + + @Override + public boolean hasName(String name, Game game) { + return leftHalfCard.hasName(name, game); + } } diff --git a/Mage/src/main/java/mage/designations/Designation.java b/Mage/src/main/java/mage/designations/Designation.java index cb76e274bc05..3be17b33b3f5 100644 --- a/Mage/src/main/java/mage/designations/Designation.java +++ b/Mage/src/main/java/mage/designations/Designation.java @@ -201,4 +201,9 @@ public void setIsAllCreatureTypes(Game game, boolean value) { public boolean isUnique() { return unique; } + + @Override + public boolean hasName(String name, Game game) { + return false; + } } diff --git a/Mage/src/main/java/mage/game/command/Commander.java b/Mage/src/main/java/mage/game/command/Commander.java index 7ff69e6101de..dfdd5c6211ee 100644 --- a/Mage/src/main/java/mage/game/command/Commander.java +++ b/Mage/src/main/java/mage/game/command/Commander.java @@ -331,6 +331,11 @@ public void setIsAllNonbasicLandTypes(Game game, boolean value) { sourceObject.setIsAllNonbasicLandTypes(game, value); } + @Override + public boolean hasName(String name, Game game) { + return sourceObject.hasName(name, game); + } + @Override public void removePTCDA() { } diff --git a/Mage/src/main/java/mage/game/command/Dungeon.java b/Mage/src/main/java/mage/game/command/Dungeon.java index adf15b5b8f4d..a5f28744cfb9 100644 --- a/Mage/src/main/java/mage/game/command/Dungeon.java +++ b/Mage/src/main/java/mage/game/command/Dungeon.java @@ -344,6 +344,11 @@ public void setIsAllNonbasicLandTypes(boolean value) { public void setIsAllNonbasicLandTypes(Game game, boolean value) { } + @Override + public boolean hasName(String name, Game game) { + return Objects.equals(name, getName()); + } + public void discardEffects() { for (Ability ability : abilites) { for (Effect effect : ability.getEffects()) { diff --git a/Mage/src/main/java/mage/game/command/Emblem.java b/Mage/src/main/java/mage/game/command/Emblem.java index 1070de0d4759..d760b30bb006 100644 --- a/Mage/src/main/java/mage/game/command/Emblem.java +++ b/Mage/src/main/java/mage/game/command/Emblem.java @@ -19,7 +19,6 @@ import mage.constants.SuperType; import mage.game.Game; import mage.game.events.ZoneChangeEvent; -import mage.util.CardUtil; import mage.util.SubTypes; import java.util.Collections; @@ -260,6 +259,11 @@ public void setIsAllNonbasicLandTypes(boolean value) { public void setIsAllNonbasicLandTypes(Game game, boolean value) { } + @Override + public boolean hasName(String name, Game game) { + return false; + } + public void discardEffects() { for (Ability ability : abilities) { for (Effect effect : ability.getEffects()) { diff --git a/Mage/src/main/java/mage/game/command/Plane.java b/Mage/src/main/java/mage/game/command/Plane.java index 4e48daaf7cdf..86614955838f 100644 --- a/Mage/src/main/java/mage/game/command/Plane.java +++ b/Mage/src/main/java/mage/game/command/Plane.java @@ -26,6 +26,7 @@ import java.lang.reflect.Constructor; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.UUID; /** @@ -281,6 +282,11 @@ public void setIsAllNonbasicLandTypes(boolean value) { public void setIsAllNonbasicLandTypes(Game game, boolean value) { } + @Override + public boolean hasName(String name, Game game) { + return Objects.equals(name, getName()); + } + public void discardEffects() { for (Ability ability : abilites) { for (Effect effect : ability.getEffects()) { diff --git a/Mage/src/main/java/mage/game/command/emblems/TheRingEmblem.java b/Mage/src/main/java/mage/game/command/emblems/TheRingEmblem.java index e99284e9dd50..1bbc6e5b6b7b 100644 --- a/Mage/src/main/java/mage/game/command/emblems/TheRingEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/TheRingEmblem.java @@ -98,6 +98,11 @@ Zone.COMMAND, new LoseLifeOpponentsEffect(3), filter, false, } game.informPlayers(name + " gains a new Ring ability: \"" + logText + "\""); } + + @Override + public boolean hasName(String name, Game game) { + return "The One Ring".equals(name); + } } enum TheRingEmblemPredicate implements Predicate { diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index c234e901643a..579224ba7109 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -1257,4 +1257,9 @@ public boolean hasCardTypeForDeckbuilding(CardType cardType) { public boolean hasSubTypeForDeckbuilding(SubType subType) { return false; } + + @Override + public boolean hasName(String name, Game game) { + return Objects.equals(name, getName()); + } } diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index d87f9fdf8713..5be8efe63f8a 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -856,4 +856,9 @@ public AbilityImpl setIdentifier(MageIdentifier identifier) { public String toString() { return this.name; } + + @Override + public boolean hasName(String name, Game game) { + return Objects.equals(name, this.name); + } } From 1814467bcda47791483b702797d2a171064243d6 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 11 Sep 2024 16:42:20 -0400 Subject: [PATCH 02/16] some more changes --- .../src/mage/cards/a/AgencyOutfitter.java | 9 +- .../mage/cards/a/AlhammarretHighArbiter.java | 3 +- .../src/mage/cards/a/AnointedPeacekeeper.java | 2 +- Mage.Sets/src/mage/cards/b/BileBlight.java | 4 +- Mage.Sets/src/mage/cards/b/BrainPry.java | 3 +- .../src/mage/cards/c/CabalTherapist.java | 4 +- Mage.Sets/src/mage/cards/c/CabalTherapy.java | 4 +- Mage.Sets/src/mage/cards/c/ConjurersBan.java | 3 +- .../src/mage/cards/c/ConundrumSphinx.java | 3 +- .../src/mage/cards/c/CorneredMarket.java | 50 ++++---- .../src/mage/cards/c/CrownOfEmpires.java | 108 +++++------------ .../src/mage/cards/d/DemonicConsultation.java | 3 +- Mage.Sets/src/mage/cards/e/EchoingReturn.java | 2 +- .../org/mage/test/testapi/AliasesApiTest.java | 114 +++++++++--------- Mage/src/main/java/mage/MageObject.java | 8 +- ...entsCantCastChosenUntilNextTurnEffect.java | 3 +- .../mageobject/ChosenNamePredicate.java | 3 +- .../predicate/mageobject/NamePredicate.java | 45 +++---- .../java/mage/game/GameTinyLeadersImpl.java | 3 +- Mage/src/main/java/mage/util/CardUtil.java | 15 +-- 20 files changed, 156 insertions(+), 233 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/AgencyOutfitter.java b/Mage.Sets/src/mage/cards/a/AgencyOutfitter.java index dfaf1ddcddeb..b096730f723c 100644 --- a/Mage.Sets/src/mage/cards/a/AgencyOutfitter.java +++ b/Mage.Sets/src/mage/cards/a/AgencyOutfitter.java @@ -17,7 +17,6 @@ import mage.target.TargetCard; import mage.target.common.TargetCardAndOrCard; import mage.target.common.TargetCardAndOrCardInLibrary; -import mage.util.CardUtil; import java.util.UUID; @@ -83,9 +82,9 @@ public boolean apply(Game game, Ability source) { for (UUID id : libraryTarget.getTargets()) { Card card = game.getCard(id); if (card != null) { - if (CardUtil.haveSameNames(card, glassName, game)) { + if (card.hasName(glassName, game)) { glassCard = card; - } else if (CardUtil.haveSameNames(card, capName, game)) { + } else if (card.hasName(capName, game)) { capCard = card; } } @@ -115,9 +114,9 @@ public boolean apply(Game game, Ability source) { for (UUID id : target.getTargets()) { Card card = game.getCard(id); if (card != null) { - if (CardUtil.haveSameNames(card, glassName, game)) { + if (card.hasName(glassName, game)) { glassCard = card; - } else if (CardUtil.haveSameNames(card, capName, game)) { + } else if (card.hasName(capName, game)) { capCard = card; } } diff --git a/Mage.Sets/src/mage/cards/a/AlhammarretHighArbiter.java b/Mage.Sets/src/mage/cards/a/AlhammarretHighArbiter.java index 978fef081f4a..34d8873ca03c 100644 --- a/Mage.Sets/src/mage/cards/a/AlhammarretHighArbiter.java +++ b/Mage.Sets/src/mage/cards/a/AlhammarretHighArbiter.java @@ -24,7 +24,6 @@ import java.util.UUID; /** - * * @author LevelX2 */ public final class AlhammarretHighArbiter extends CardImpl { @@ -162,7 +161,7 @@ public boolean applies(GameEvent event, Ability source, Game game) { if (card == null) { return false; } - return CardUtil.haveSameNames(card, cardName, game); + return card.hasName(cardName, game); } return false; } diff --git a/Mage.Sets/src/mage/cards/a/AnointedPeacekeeper.java b/Mage.Sets/src/mage/cards/a/AnointedPeacekeeper.java index ce530b963742..dbbb8d799552 100644 --- a/Mage.Sets/src/mage/cards/a/AnointedPeacekeeper.java +++ b/Mage.Sets/src/mage/cards/a/AnointedPeacekeeper.java @@ -98,6 +98,6 @@ public boolean applies(Ability abilityToModify, Ability source, Game game) { String chosenName = (String) game.getState().getValue( source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY ); - return CardUtil.haveSameNames(activatedSource, chosenName, game); + return activatedSource.hasName(chosenName, game); } } diff --git a/Mage.Sets/src/mage/cards/b/BileBlight.java b/Mage.Sets/src/mage/cards/b/BileBlight.java index caa3e4dbf1bb..abcf5dc5df38 100644 --- a/Mage.Sets/src/mage/cards/b/BileBlight.java +++ b/Mage.Sets/src/mage/cards/b/BileBlight.java @@ -22,7 +22,6 @@ public final class BileBlight extends CardImpl { public BileBlight(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}{B}"); - // Target creature and all creatures with the same name as that creature get -3/-3 until end of turn. this.getSpellAbility().addEffect(new BileBlightEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); @@ -64,9 +63,8 @@ public void init(Ability source, Game game) { affectedObjectList.add(new MageObjectReference(target, game)); return; } - String name = target.getName(); for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (CardUtil.haveSameNames(perm, name, game)) { + if (CardUtil.haveSameNames(perm, target)) { affectedObjectList.add(new MageObjectReference(perm, game)); } } diff --git a/Mage.Sets/src/mage/cards/b/BrainPry.java b/Mage.Sets/src/mage/cards/b/BrainPry.java index 430185d877a4..a6eef4588c83 100644 --- a/Mage.Sets/src/mage/cards/b/BrainPry.java +++ b/Mage.Sets/src/mage/cards/b/BrainPry.java @@ -12,7 +12,6 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; -import mage.util.CardUtil; import java.util.UUID; @@ -60,7 +59,7 @@ public boolean apply(Game game, Ability source) { if (targetPlayer != null && controller != null && sourceObject != null && cardName != null) { boolean hasDiscarded = false; for (Card card : targetPlayer.getHand().getCards(game)) { - if (CardUtil.haveSameNames(card, cardName, game)) { + if (card.hasName(cardName, game)) { targetPlayer.discard(card, false, source, game); hasDiscarded = true; break; diff --git a/Mage.Sets/src/mage/cards/c/CabalTherapist.java b/Mage.Sets/src/mage/cards/c/CabalTherapist.java index c0d567885ecf..e44887b4dc0a 100644 --- a/Mage.Sets/src/mage/cards/c/CabalTherapist.java +++ b/Mage.Sets/src/mage/cards/c/CabalTherapist.java @@ -22,8 +22,6 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; -import mage.target.common.TargetControlledPermanent; -import mage.util.CardUtil; import java.util.UUID; @@ -92,7 +90,7 @@ public boolean apply(Game game, Ability source) { if (card == null) { return true; } - return !CardUtil.haveSameNames(card, cardName, game); + return !card.hasName(cardName, game); }); targetPlayer.discard(hand, false, source, game); return true; diff --git a/Mage.Sets/src/mage/cards/c/CabalTherapy.java b/Mage.Sets/src/mage/cards/c/CabalTherapy.java index 8a2703242947..3ed180c43d75 100644 --- a/Mage.Sets/src/mage/cards/c/CabalTherapy.java +++ b/Mage.Sets/src/mage/cards/c/CabalTherapy.java @@ -16,8 +16,6 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; -import mage.target.common.TargetControlledCreaturePermanent; -import mage.util.CardUtil; import java.util.UUID; @@ -75,7 +73,7 @@ public boolean apply(Game game, Ability source) { if (card == null) { return true; } - return !CardUtil.haveSameNames(card, cardName, game); + return !card.hasName(cardName, game); }); targetPlayer.discard(hand, false, source, game); return true; diff --git a/Mage.Sets/src/mage/cards/c/ConjurersBan.java b/Mage.Sets/src/mage/cards/c/ConjurersBan.java index 6e09f3809663..8d1e4c96561d 100644 --- a/Mage.Sets/src/mage/cards/c/ConjurersBan.java +++ b/Mage.Sets/src/mage/cards/c/ConjurersBan.java @@ -12,7 +12,6 @@ import mage.constants.Outcome; import mage.game.Game; import mage.game.events.GameEvent; -import mage.util.CardUtil; import java.util.UUID; @@ -68,7 +67,7 @@ public boolean checksEventType(GameEvent event, Game game) { public boolean applies(GameEvent event, Ability source, Game game) { MageObject object = game.getObject(event.getSourceId()); String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); - return CardUtil.haveSameNames(object, cardName, game); + return object.hasName(cardName, game); } @Override diff --git a/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java b/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java index 7a5fcd6a3413..0e4533c25ff0 100644 --- a/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java +++ b/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java @@ -14,7 +14,6 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; -import mage.util.CardUtil; import java.util.UUID; @@ -81,7 +80,7 @@ public boolean apply(Game game, Ability source) { } Cards cards = new CardsImpl(card); player.revealCards(source, cards, game); - if (CardUtil.haveSameNames(card, cardName, game)) { + if (card.hasName(cardName, game)) { player.moveCards(cards, Zone.HAND, source, game); } else { player.putCardsOnBottomOfLibrary(cards, game, source, false); diff --git a/Mage.Sets/src/mage/cards/c/CorneredMarket.java b/Mage.Sets/src/mage/cards/c/CorneredMarket.java index 5f1f66791fc5..5f046136f24f 100644 --- a/Mage.Sets/src/mage/cards/c/CorneredMarket.java +++ b/Mage.Sets/src/mage/cards/c/CorneredMarket.java @@ -17,12 +17,10 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import mage.util.CardUtil; import java.util.UUID; /** - * * @author jeffwadsworth */ public final class CorneredMarket extends CardImpl { @@ -77,34 +75,30 @@ public boolean applies(GameEvent event, Ability source, Game game) { return false; } Card card = spellAbility.getCharacteristics(game); - if (card != null) { - Spell spell = game.getState().getStack().getSpell(event.getSourceId()); - // Face Down cast spell (Morph creature) has no name - if (spell != null - && spell.isFaceDown(game)) { - return false; - } - // play land check - if (card.isLand(game) - && !card.isBasic(game)) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { - if (permanent != null) { - if (CardUtil.haveSameNames(card, permanent.getName(), game)) { - return true; - } - } + if (card == null) { + return false; + } + Spell spell = game.getState().getStack().getSpell(event.getSourceId()); + // Face Down cast spell (Morph creature) has no name + if (spell != null && spell.isFaceDown(game)) { + return false; + } + // play land check + if (card.isLand(game) && !card.isBasic(game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { + if (card.sharesName(permanent, game)) { + return true; } - return false; } - // cast spell check - if (spell != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { - if (permanent != null) { - if (CardUtil.haveSameNames(card, permanent.getName(), game)) { - return true; - } - } - } + return false; + } + // cast spell check + if (spell == null) { + return false; + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { + if (card.sharesName(permanent, game)) { + return true; } } return false; diff --git a/Mage.Sets/src/mage/cards/c/CrownOfEmpires.java b/Mage.Sets/src/mage/cards/c/CrownOfEmpires.java index 08e928f2c3a1..714bc6b66aea 100644 --- a/Mage.Sets/src/mage/cards/c/CrownOfEmpires.java +++ b/Mage.Sets/src/mage/cards/c/CrownOfEmpires.java @@ -1,21 +1,24 @@ package mage.cards.c; import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.AddContinuousEffectToGame; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.predicate.mageobject.NamePredicate; import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTarget; -import mage.util.CardUtil; import java.util.UUID; @@ -24,11 +27,28 @@ */ public final class CrownOfEmpires extends CardImpl { + private static final FilterPermanent filter = new FilterControlledArtifactPermanent(); + private static final FilterPermanent filter2 = new FilterControlledArtifactPermanent(); + + static { + filter.add(new NamePredicate("Scepter of Empires")); + filter2.add(new NamePredicate("Throne of Empires")); + } + + private static final Condition condition = new CompoundCondition( + new PermanentsOnTheBattlefieldCondition(filter), + new PermanentsOnTheBattlefieldCondition(filter2) + ); + public CrownOfEmpires(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // {3}, {tap}: Tap target creature. Gain control of that creature instead if you control artifacts named Scepter of Empires and Throne of Empires. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CrownOfEmpiresEffect(), new GenericManaCost(3)); + Ability ability = new SimpleActivatedAbility(new ConditionalOneShotEffect( + new AddContinuousEffectToGame(new GainControlTargetEffect(Duration.Custom)), + new TapTargetEffect(), condition, "tap target creature. Gain control of that creature " + + "instead if you control artifacts named Scepter of Empires and Throne of Empires" + ), new GenericManaCost(3)); ability.addTarget(new TargetCreaturePermanent()); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -43,71 +63,3 @@ public CrownOfEmpires copy() { return new CrownOfEmpires(this); } } - -class CrownOfEmpiresEffect extends OneShotEffect { - - CrownOfEmpiresEffect() { - super(Outcome.Tap); - staticText = "Tap target creature. Gain control of that creature instead if you control artifacts named Scepter of Empires and Throne of Empires"; - } - - private CrownOfEmpiresEffect(final CrownOfEmpiresEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); - boolean scepter = false; - boolean throne = false; - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { - if (CardUtil.haveSameNames(permanent, "Scepter of Empires", game)) { - scepter = true; - } else if (CardUtil.haveSameNames(permanent, "Throne of Empires", game)) { - throne = true; - } - if (scepter && throne) break; - } - if (scepter && throne) { - ContinuousEffect effect = new CrownOfEmpiresControlEffect(); - effect.setTargetPointer(new FixedTarget(target.getId(), game)); - game.getState().setValue(source.getSourceId().toString(), source.getControllerId()); - game.addEffect(effect, source); - } else { - target.tap(source, game); - } - return false; - } - - @Override - public CrownOfEmpiresEffect copy() { - return new CrownOfEmpiresEffect(this); - } -} - -class CrownOfEmpiresControlEffect extends ContinuousEffectImpl { - - CrownOfEmpiresControlEffect() { - super(Duration.EndOfGame, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); - this.staticText = "Gain control of {this}"; - } - - private CrownOfEmpiresControlEffect(final CrownOfEmpiresControlEffect effect) { - super(effect); - } - - @Override - public CrownOfEmpiresControlEffect copy() { - return new CrownOfEmpiresControlEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - UUID controllerId = (UUID) game.getState().getValue(source.getSourceId().toString()); - if (permanent != null && controllerId != null) { - return permanent.changeControllerId(controllerId, game, source); - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DemonicConsultation.java b/Mage.Sets/src/mage/cards/d/DemonicConsultation.java index 92d6fca243b6..4527c2e93cb7 100644 --- a/Mage.Sets/src/mage/cards/d/DemonicConsultation.java +++ b/Mage.Sets/src/mage/cards/d/DemonicConsultation.java @@ -10,7 +10,6 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; -import mage.util.CardUtil; import java.util.UUID; @@ -73,7 +72,7 @@ public boolean apply(Game game, Ability source) { for (Card card : controller.getLibrary().getCards(game)) { cardsToReveal.add(card); // Put that card into your hand - if (CardUtil.haveSameNames(card.getName(), cardName)) { + if (card.hasName(cardName, game)) { cardToHand = card; break; } diff --git a/Mage.Sets/src/mage/cards/e/EchoingReturn.java b/Mage.Sets/src/mage/cards/e/EchoingReturn.java index 3b70cf1ae350..a4171e5c074b 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingReturn.java +++ b/Mage.Sets/src/mage/cards/e/EchoingReturn.java @@ -65,7 +65,7 @@ public boolean apply(Game game, Ability source) { player.getGraveyard() .getCards(game) .stream() - .filter(c -> CardUtil.haveSameNames(c.getName(), card.getName())) + .filter(c -> CardUtil.haveSameNames(c, card)) .forEach(cards::add); return player.moveCards(cards, Zone.HAND, source, game); } diff --git a/Mage.Tests/src/test/java/org/mage/test/testapi/AliasesApiTest.java b/Mage.Tests/src/test/java/org/mage/test/testapi/AliasesApiTest.java index 4de1ffeba247..bd4f1c06f196 100644 --- a/Mage.Tests/src/test/java/org/mage/test/testapi/AliasesApiTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/testapi/AliasesApiTest.java @@ -18,63 +18,63 @@ public class AliasesApiTest extends CardTestPlayerBase { @Test public void test_NamesEquals() { - // empty names for face down cards - Assert.assertTrue(CardUtil.haveEmptyName("")); - Assert.assertTrue(CardUtil.haveEmptyName(EmptyNames.FACE_DOWN_CREATURE.toString())); - Assert.assertFalse(CardUtil.haveEmptyName(" ")); - Assert.assertFalse(CardUtil.haveEmptyName("123")); - Assert.assertFalse(CardUtil.haveEmptyName("Sample Name")); - - // same names (empty names can't be same) - Assert.assertFalse(CardUtil.haveSameNames("", "")); - Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_CREATURE.toString(), "")); - Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_CREATURE.toString(), EmptyNames.FACE_DOWN_CREATURE.toString())); - Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_TOKEN.toString(), "")); - Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_TOKEN.toString(), EmptyNames.FACE_DOWN_CREATURE.toString())); - Assert.assertTrue(CardUtil.haveSameNames("Name", "Name")); - Assert.assertFalse(CardUtil.haveSameNames("Name", "")); - Assert.assertFalse(CardUtil.haveSameNames("Name", " ")); - Assert.assertFalse(CardUtil.haveSameNames("Name", "123")); - Assert.assertFalse(CardUtil.haveSameNames("Name", EmptyNames.FACE_DOWN_CREATURE.toString())); - Assert.assertFalse(CardUtil.haveSameNames("Name1", "Name2")); - - // ignore mtg rules (empty names must be same) - Assert.assertTrue(CardUtil.haveSameNames("", "", true)); - Assert.assertTrue(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_CREATURE.toString(), EmptyNames.FACE_DOWN_CREATURE.toString(), true)); - Assert.assertTrue(CardUtil.haveSameNames("Name", "Name", true)); - Assert.assertFalse(CardUtil.haveSameNames("Name", "", true)); - Assert.assertFalse(CardUtil.haveSameNames("Name", " ", true)); - Assert.assertFalse(CardUtil.haveSameNames("Name", "123", true)); - Assert.assertFalse(CardUtil.haveSameNames("Name", EmptyNames.FACE_DOWN_CREATURE.toString(), true)); - Assert.assertFalse(CardUtil.haveSameNames("Name1", "Name2", true)); - - // name with split card - Card splitCard1 = CardRepository.instance.findCard("Armed // Dangerous").createCard(); - Card splitCard2 = CardRepository.instance.findCard("Alive // Well").createCard(); - Assert.assertTrue(CardUtil.haveSameNames(splitCard1, "Armed", currentGame)); - Assert.assertTrue(CardUtil.haveSameNames(splitCard1, "Dangerous", currentGame)); - Assert.assertTrue(CardUtil.haveSameNames(splitCard1, "Armed // Dangerous", currentGame)); - Assert.assertTrue(CardUtil.haveSameNames(splitCard1, splitCard1)); - Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Other", currentGame)); - Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Other // Dangerous", currentGame)); - Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Armed // Other", currentGame)); - Assert.assertFalse(CardUtil.haveSameNames(splitCard1, splitCard2)); - - // name with face down spells: face down spells don't have names, see https://github.com/magefree/mage/issues/6569 - Card bearCard = CardRepository.instance.findCard("Balduvian Bears").createCard(); - Spell normalSpell = new Spell(bearCard, bearCard.getSpellAbility(), playerA.getId(), Zone.HAND, currentGame); - Spell faceDownSpell = new Spell(bearCard, bearCard.getSpellAbility(), playerA.getId(), Zone.HAND, currentGame); - faceDownSpell.setFaceDown(true, currentGame); - // normal spell - Assert.assertFalse(CardUtil.haveSameNames(normalSpell, "", currentGame)); - Assert.assertFalse(CardUtil.haveSameNames(normalSpell, "Other", currentGame)); - Assert.assertFalse(CardUtil.haveSameNames(normalSpell, EmptyNames.FACE_DOWN_CREATURE.toString(), currentGame)); - Assert.assertTrue(CardUtil.haveSameNames(normalSpell, "Balduvian Bears", currentGame)); - // face down spell - Assert.assertFalse(CardUtil.haveSameNames(faceDownSpell, "", currentGame)); - Assert.assertFalse(CardUtil.haveSameNames(faceDownSpell, "Other", currentGame)); - Assert.assertFalse(CardUtil.haveSameNames(faceDownSpell, EmptyNames.FACE_DOWN_CREATURE.toString(), currentGame)); - Assert.assertFalse(CardUtil.haveSameNames(faceDownSpell, "Balduvian Bears", currentGame)); +// // empty names for face down cards +// Assert.assertTrue(CardUtil.haveEmptyName("")); +// Assert.assertTrue(CardUtil.haveEmptyName(EmptyNames.FACE_DOWN_CREATURE.toString())); +// Assert.assertFalse(CardUtil.haveEmptyName(" ")); +// Assert.assertFalse(CardUtil.haveEmptyName("123")); +// Assert.assertFalse(CardUtil.haveEmptyName("Sample Name")); +// +// // same names (empty names can't be same) +// Assert.assertFalse(CardUtil.haveSameNames("", "")); +// Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_CREATURE.toString(), "")); +// Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_CREATURE.toString(), EmptyNames.FACE_DOWN_CREATURE.toString())); +// Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_TOKEN.toString(), "")); +// Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_TOKEN.toString(), EmptyNames.FACE_DOWN_CREATURE.toString())); +// Assert.assertTrue(CardUtil.haveSameNames("Name", "Name")); +// Assert.assertFalse(CardUtil.haveSameNames("Name", "")); +// Assert.assertFalse(CardUtil.haveSameNames("Name", " ")); +// Assert.assertFalse(CardUtil.haveSameNames("Name", "123")); +// Assert.assertFalse(CardUtil.haveSameNames("Name", EmptyNames.FACE_DOWN_CREATURE.toString())); +// Assert.assertFalse(CardUtil.haveSameNames("Name1", "Name2")); +// +// // ignore mtg rules (empty names must be same) +// Assert.assertTrue(CardUtil.haveSameNames("", "", true)); +// Assert.assertTrue(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_CREATURE.toString(), EmptyNames.FACE_DOWN_CREATURE.toString(), true)); +// Assert.assertTrue(CardUtil.haveSameNames("Name", "Name", true)); +// Assert.assertFalse(CardUtil.haveSameNames("Name", "", true)); +// Assert.assertFalse(CardUtil.haveSameNames("Name", " ", true)); +// Assert.assertFalse(CardUtil.haveSameNames("Name", "123", true)); +// Assert.assertFalse(CardUtil.haveSameNames("Name", EmptyNames.FACE_DOWN_CREATURE.toString(), true)); +// Assert.assertFalse(CardUtil.haveSameNames("Name1", "Name2", true)); +// +// // name with split card +// Card splitCard1 = CardRepository.instance.findCard("Armed // Dangerous").createCard(); +// Card splitCard2 = CardRepository.instance.findCard("Alive // Well").createCard(); +// Assert.assertTrue(CardUtil.haveSameNames(splitCard1, "Armed", currentGame)); +// Assert.assertTrue(CardUtil.haveSameNames(splitCard1, "Dangerous", currentGame)); +// Assert.assertTrue(CardUtil.haveSameNames(splitCard1, "Armed // Dangerous", currentGame)); +// Assert.assertTrue(CardUtil.haveSameNames(splitCard1, splitCard1)); +// Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Other", currentGame)); +// Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Other // Dangerous", currentGame)); +// Assert.assertFalse(CardUtil.haveSameNames(splitCard1, "Armed // Other", currentGame)); +// Assert.assertFalse(CardUtil.haveSameNames(splitCard1, splitCard2)); +// +// // name with face down spells: face down spells don't have names, see https://github.com/magefree/mage/issues/6569 +// Card bearCard = CardRepository.instance.findCard("Balduvian Bears").createCard(); +// Spell normalSpell = new Spell(bearCard, bearCard.getSpellAbility(), playerA.getId(), Zone.HAND, currentGame); +// Spell faceDownSpell = new Spell(bearCard, bearCard.getSpellAbility(), playerA.getId(), Zone.HAND, currentGame); +// faceDownSpell.setFaceDown(true, currentGame); +// // normal spell +// Assert.assertFalse(CardUtil.haveSameNames(normalSpell, "", currentGame)); +// Assert.assertFalse(CardUtil.haveSameNames(normalSpell, "Other", currentGame)); +// Assert.assertFalse(CardUtil.haveSameNames(normalSpell, EmptyNames.FACE_DOWN_CREATURE.toString(), currentGame)); +// Assert.assertTrue(CardUtil.haveSameNames(normalSpell, "Balduvian Bears", currentGame)); +// // face down spell +// Assert.assertFalse(CardUtil.haveSameNames(faceDownSpell, "", currentGame)); +// Assert.assertFalse(CardUtil.haveSameNames(faceDownSpell, "Other", currentGame)); +// Assert.assertFalse(CardUtil.haveSameNames(faceDownSpell, EmptyNames.FACE_DOWN_CREATURE.toString(), currentGame)); +// Assert.assertFalse(CardUtil.haveSameNames(faceDownSpell, "Balduvian Bears", currentGame)); } @Test diff --git a/Mage/src/main/java/mage/MageObject.java b/Mage/src/main/java/mage/MageObject.java index 6b54aceebdeb..e3d35a3aa8ad 100644 --- a/Mage/src/main/java/mage/MageObject.java +++ b/Mage/src/main/java/mage/MageObject.java @@ -622,11 +622,11 @@ default boolean shareCreatureTypes(Game game, MageObject otherCard) { */ void setIsAllNonbasicLandTypes(Game game, boolean value); - default boolean hasName(String name) { - return hasName(name, null); - } - boolean hasName(String name, Game game); + default boolean sharesName(MageObject mageObject, Game game) { + return !mageObject.getName().isEmpty() && hasName(mageObject.getName(), game); + } + void removePTCDA(); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/OpponentsCantCastChosenUntilNextTurnEffect.java b/Mage/src/main/java/mage/abilities/effects/common/OpponentsCantCastChosenUntilNextTurnEffect.java index bc0d906f5939..ee68c17ffae5 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/OpponentsCantCastChosenUntilNextTurnEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/OpponentsCantCastChosenUntilNextTurnEffect.java @@ -9,7 +9,6 @@ import mage.constants.Outcome; import mage.game.Game; import mage.game.events.GameEvent; -import mage.util.CardUtil; /** * This effect must be used in tandem with ChooseACardNameEffect @@ -59,6 +58,6 @@ public boolean applies(GameEvent event, Ability source, Game game) { return false; } String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); - return CardUtil.haveSameNames(card, cardName, game); + return card.hasName(cardName, game); } } diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/ChosenNamePredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/ChosenNamePredicate.java index 7d56a6e86f57..dc10b98b2a33 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/ChosenNamePredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/ChosenNamePredicate.java @@ -5,7 +5,6 @@ import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; -import mage.util.CardUtil; /** * To be used with ChooseACardNameEffect @@ -20,7 +19,7 @@ public boolean apply(ObjectSourcePlayer input, Game game) { String cardName = (String) game.getState().getValue( input.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY ); - return CardUtil.haveSameNames(input.getObject().getName(), cardName); + return input.getObject().hasName(cardName, game); } @Override diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java index 4160a68397c4..1630a7d6b802 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java @@ -42,6 +42,7 @@ public boolean apply(MageObject input, Game game) { if (name == null) { return false; } + return input.hasName(name, game); // If a player names a card, the player may name either half of a split card, but not both. // A split card has the chosen name if one of its two names matches the chosen name. // This is NOT the same for double faced cards, where only the front side matches @@ -51,28 +52,28 @@ public boolean apply(MageObject input, Game game) { // including the one that you countered, because those cards have only their front-face characteristics // (including name) in the graveyard, hand, and library. (2021-04-16) - if (input instanceof SplitCard) { - return CardUtil.haveSameNames(name, ((CardWithHalves) input).getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || - CardUtil.haveSameNames(name, ((CardWithHalves) input).getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || - CardUtil.haveSameNames(name, input.getName(), this.ignoreMtgRuleForEmptyNames); - } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) { - SplitCard card = (SplitCard) ((Spell) input).getCard(); - return CardUtil.haveSameNames(name, card.getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || - CardUtil.haveSameNames(name, card.getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || - CardUtil.haveSameNames(name, card.getName(), this.ignoreMtgRuleForEmptyNames); - } else if (input instanceof Spell && ((Spell) input).isFaceDown(game)) { - // face down spells don't have names, so it's not equal, see https://github.com/magefree/mage/issues/6569 - return false; - } else { - if (name.contains(" // ")) { - String leftName = name.substring(0, name.indexOf(" // ")); - String rightName = name.substring(name.indexOf(" // ") + 4); - return CardUtil.haveSameNames(leftName, input.getName(), this.ignoreMtgRuleForEmptyNames) || - CardUtil.haveSameNames(rightName, input.getName(), this.ignoreMtgRuleForEmptyNames); - } else { - return CardUtil.haveSameNames(name, input.getName(), this.ignoreMtgRuleForEmptyNames); - } - } +// if (input instanceof SplitCard) { +// return CardUtil.haveSameNames(name, ((CardWithHalves) input).getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || +// CardUtil.haveSameNames(name, ((CardWithHalves) input).getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || +// CardUtil.haveSameNames(name, input.getName(), this.ignoreMtgRuleForEmptyNames); +// } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) { +// SplitCard card = (SplitCard) ((Spell) input).getCard(); +// return CardUtil.haveSameNames(name, card.getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || +// CardUtil.haveSameNames(name, card.getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || +// CardUtil.haveSameNames(name, card.getName(), this.ignoreMtgRuleForEmptyNames); +// } else if (input instanceof Spell && ((Spell) input).isFaceDown(game)) { +// // face down spells don't have names, so it's not equal, see https://github.com/magefree/mage/issues/6569 +// return false; +// } else { +// if (name.contains(" // ")) { +// String leftName = name.substring(0, name.indexOf(" // ")); +// String rightName = name.substring(name.indexOf(" // ") + 4); +// return CardUtil.haveSameNames(leftName, input.getName(), this.ignoreMtgRuleForEmptyNames) || +// CardUtil.haveSameNames(rightName, input.getName(), this.ignoreMtgRuleForEmptyNames); +// } else { +// return CardUtil.haveSameNames(name, input.getName(), this.ignoreMtgRuleForEmptyNames); +// } +// } } @Override diff --git a/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java b/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java index 1e76c1986d68..7ecb7ff3f76c 100644 --- a/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java +++ b/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java @@ -15,7 +15,6 @@ import mage.game.mulligan.Mulligan; import mage.game.turn.TurnMod; import mage.players.Player; -import mage.util.CardUtil; import mage.watchers.common.CommanderInfoWatcher; import java.util.HashSet; @@ -92,7 +91,7 @@ protected void init(UUID choosingPlayerId) { private Card findCommander(Game game, Player player, String commanderName) { return game.getCommanderCardsFromAnyZones(player, CommanderCardType.ANY, Zone.ALL) .stream() - .filter(c -> CardUtil.haveSameNames(c, commanderName, game)) + .filter(c -> c.hasName(commanderName, game)) .findFirst() .orElse(null); } diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 49742ab086d8..1bb403132251 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -29,7 +29,6 @@ import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; import mage.filter.predicate.card.OwnerIdPredicate; -import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.CardState; import mage.game.Game; @@ -773,20 +772,12 @@ public static boolean haveSameNames(String name1, String name2, Boolean ignoreMt } } - public static boolean haveSameNames(String name1, String name2) { - return haveSameNames(name1, name2, false); - } - public static boolean haveSameNames(MageObject object1, MageObject object2) { - return object1 != null && object2 != null && haveSameNames(object1.getName(), object2.getName()); + return object1 != null && object2 != null && haveSameNames(object1.getName(), object2.getName(), false); } public static boolean haveSameNames(MageObject object, String needName, Game game) { - return containsName(object, needName, game); - } - - public static boolean containsName(MageObject object, String name, Game game) { - return new NamePredicate(name).apply(object, game); + return object.hasName(needName, game); } public static boolean haveEmptyName(String name) { @@ -1167,7 +1158,7 @@ public static Set checkPossibleTargetsTotalValueLimit(Collection sel .sum(); int remainingValue = maxValue - selectedValue; Set validTargets = new HashSet<>(); - for (UUID id: possibleTargets) { + for (UUID id : possibleTargets) { MageObject mageObject = game.getObject(id); if (mageObject != null && valueMapper.applyAsInt(mageObject) <= remainingValue) { validTargets.add(id); From 7c0d7105eea1ede12fa9387dfca6f0e7e17e9e00 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 13 Sep 2024 17:15:56 -0400 Subject: [PATCH 03/16] a few card rewrites --- .../src/mage/cards/d/DetentionSphere.java | 84 ++++--------- Mage.Sets/src/mage/cards/g/GrimoireThief.java | 13 +- Mage.Sets/src/mage/cards/r/ReflectorMage.java | 45 +++---- Mage.Sets/src/mage/cards/s/SearchTheCity.java | 114 ++++++++---------- Mage/src/main/java/mage/util/CardUtil.java | 4 + 5 files changed, 99 insertions(+), 161 deletions(-) diff --git a/Mage.Sets/src/mage/cards/d/DetentionSphere.java b/Mage.Sets/src/mage/cards/d/DetentionSphere.java index c16dc102058e..185e67bfffe8 100644 --- a/Mage.Sets/src/mage/cards/d/DetentionSphere.java +++ b/Mage.Sets/src/mage/cards/d/DetentionSphere.java @@ -1,36 +1,37 @@ package mage.cards.d; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnFromExileForSourceEffect; +import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.NamePredicate; -import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; import mage.util.CardUtil; -import org.apache.log4j.Logger; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author LevelX2 */ public final class DetentionSphere extends CardImpl { - static final protected FilterPermanent filter = new FilterNonlandPermanent("nonland permanent not named Detention Sphere"); + private static final FilterPermanent filter = new FilterNonlandPermanent("nonland permanent not named Detention Sphere"); static { filter.add(Predicates.not(new NamePredicate("Detention Sphere"))); @@ -48,7 +49,7 @@ public DetentionSphere(UUID ownerId, CardSetInfo setInfo) { // When Detention Sphere leaves the battlefield, return the exiled // cards to the battlefield under their owner's control. - this.addAbility(new LeavesBattlefieldTriggeredAbility(new DetentionSphereLeavesEffect(), false)); + this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false)); } private DetentionSphere(final DetentionSphere card) { @@ -65,7 +66,8 @@ class DetentionSphereEntersEffect extends OneShotEffect { DetentionSphereEntersEffect() { super(Outcome.Exile); - staticText = "you may exile target nonland permanent not named Detention Sphere and all other permanents with the same name as that permanent"; + staticText = "exile target nonland permanent not named Detention Sphere " + + "and all other permanents with the same name as that permanent"; } private DetentionSphereEntersEffect(final DetentionSphereEntersEffect effect) { @@ -74,25 +76,23 @@ private DetentionSphereEntersEffect(final DetentionSphereEntersEffect effect) { @Override public boolean apply(Game game, Ability source) { - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); - Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source); - if (sourceObject != null && exileId != null && targetPermanent != null && controller != null) { - - if (CardUtil.haveEmptyName(targetPermanent)) { // face down creature - controller.moveCardToExileWithInfo(targetPermanent, exileId, sourceObject.getIdName(), source, game, Zone.BATTLEFIELD, true); - } else { - String name = targetPermanent.getName(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (permanent != null && CardUtil.haveSameNames(permanent, name, game)) { - controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName(), source, game, Zone.BATTLEFIELD, true); - } - } - } - return true; + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (player == null || permanent == null) { + return false; } - return false; + Set permanents = game + .getBattlefield() + .getActivePermanents(StaticFilters.FILTER_PERMANENT, source.getControllerId(), source, game) + .stream() + .filter(p -> p.sharesName(permanent, game)) + .collect(Collectors.toSet()); + permanents.add(permanent); + return player.moveCardsToExile( + permanents, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); } @Override @@ -100,39 +100,3 @@ public DetentionSphereEntersEffect copy() { return new DetentionSphereEntersEffect(this); } } - -class DetentionSphereLeavesEffect extends OneShotEffect { - - DetentionSphereLeavesEffect() { - super(Outcome.Neutral); - staticText = "return the exiled cards to the battlefield under their owner's control"; - } - - private DetentionSphereLeavesEffect(final DetentionSphereLeavesEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null && controller != null) { - Permanent permanentLeftBattlefield = (Permanent) getValue("permanentLeftBattlefield"); - if (permanentLeftBattlefield == null) { - Logger.getLogger(ReturnFromExileForSourceEffect.class).error("Permanent not found: " + sourceObject.getName()); - return false; - } - ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), permanentLeftBattlefield.getZoneChangeCounter(game))); - if (exile != null) { - controller.moveCards(exile.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); - } - return true; - } - return false; - } - - @Override - public DetentionSphereLeavesEffect copy() { - return new DetentionSphereLeavesEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/g/GrimoireThief.java b/Mage.Sets/src/mage/cards/g/GrimoireThief.java index 8f9da4e6f2a3..8ccdb8868a9f 100644 --- a/Mage.Sets/src/mage/cards/g/GrimoireThief.java +++ b/Mage.Sets/src/mage/cards/g/GrimoireThief.java @@ -200,18 +200,7 @@ public boolean apply(Game game, Ability source) { for (Iterator iterator = game.getStack().iterator(); iterator.hasNext(); ) { StackObject stackObject = iterator.next(); MageObject mageObject = game.getObject(card.getId()); - String name1; - String name2; - if (mageObject instanceof SplitCard) { - name1 = ((SplitCard) mageObject).getLeftHalfCard().getName(); - name2 = ((SplitCard) mageObject).getRightHalfCard().getName(); - } else { - // modal double faces cards, adventure cards -- all have one name in non stack/battlefield zone - name1 = mageObject.getName(); - name2 = name1; - } - - if (CardUtil.haveSameNames(stackObject, name1, game) || CardUtil.haveSameNames(stackObject, name2, game)) { + if (stackObject.sharesName(mageObject, game)) { Spell spell = (Spell) stackObject; game.getStack().counter(stackObject.getId(), source, game); game.informPlayers(sourceObject.getLogName() + ": spell " + spell.getIdName() + " was countered."); diff --git a/Mage.Sets/src/mage/cards/r/ReflectorMage.java b/Mage.Sets/src/mage/cards/r/ReflectorMage.java index df5dc5d9021e..0469f428b445 100644 --- a/Mage.Sets/src/mage/cards/r/ReflectorMage.java +++ b/Mage.Sets/src/mage/cards/r/ReflectorMage.java @@ -16,9 +16,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; -import mage.util.CardUtil; -import java.util.Objects; import java.util.UUID; /** @@ -59,7 +57,8 @@ class ReflectorMageEffect extends OneShotEffect { ReflectorMageEffect() { super(Outcome.Benefit); - this.staticText = "return target creature an opponent controls to its owner's hand. That creature's owner can't cast spells with the same name as that creature until your next turn"; + this.staticText = "return target creature an opponent controls to its owner's hand. " + + "That creature's owner can't cast spells with the same name as that creature until your next turn"; } private ReflectorMageEffect(final ReflectorMageEffect effect) { @@ -74,35 +73,31 @@ public ReflectorMageEffect copy() { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (targetCreature != null) { - controller.moveCards(targetCreature, Zone.HAND, source, game); - if (!CardUtil.haveEmptyName(targetCreature)) { // if the creature had no name, no restrict effect will be created - game.addEffect(new ExclusionRitualReplacementEffect(targetCreature.getName(), targetCreature.getOwnerId()), source); - } - } - return true; + Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (controller == null || targetCreature == null) { + return false; } - return false; + controller.moveCards(targetCreature, Zone.HAND, source, game); + game.addEffect(new ReflectorMageReplacementEffect(targetCreature, targetCreature.getOwnerId()), source); + return true; } } -class ExclusionRitualReplacementEffect extends ContinuousRuleModifyingEffectImpl { +class ReflectorMageReplacementEffect extends ContinuousRuleModifyingEffectImpl { - private final String creatureName; + private final Permanent creature; private final UUID ownerId; - ExclusionRitualReplacementEffect(String creatureName, UUID ownerId) { + ReflectorMageReplacementEffect(Permanent creature, UUID ownerId) { super(Duration.UntilYourNextTurn, Outcome.Detriment); staticText = "That creature's owner can't cast spells with the same name as that creature until your next turn"; - this.creatureName = creatureName; + this.creature = creature.copy(); this.ownerId = ownerId; } - private ExclusionRitualReplacementEffect(final ExclusionRitualReplacementEffect effect) { + private ReflectorMageReplacementEffect(final ReflectorMageReplacementEffect effect) { super(effect); - this.creatureName = effect.creatureName; + this.creature = effect.creature.copy(); this.ownerId = effect.ownerId; } @@ -114,18 +109,12 @@ public boolean checksEventType(GameEvent event, Game game) { @Override public boolean applies(GameEvent event, Ability source, Game game) { SpellAbility spellAbility = SpellAbility.getSpellAbilityFromEvent(event, game); - if (spellAbility == null) { - return false; - } Card card = spellAbility.getCharacteristics(game); - if (card == null) { - return false; - } - return CardUtil.haveSameNames(card, creatureName, game) && Objects.equals(ownerId, card.getOwnerId()); + return spellAbility != null && card != null && card.isOwnedBy(ownerId) && card.sharesName(creature, game); } @Override - public ExclusionRitualReplacementEffect copy() { - return new ExclusionRitualReplacementEffect(this); + public ReflectorMageReplacementEffect copy() { + return new ReflectorMageReplacementEffect(this); } } diff --git a/Mage.Sets/src/mage/cards/s/SearchTheCity.java b/Mage.Sets/src/mage/cards/s/SearchTheCity.java index a0206a95a4c1..9b1c5e03af30 100644 --- a/Mage.Sets/src/mage/cards/s/SearchTheCity.java +++ b/Mage.Sets/src/mage/cards/s/SearchTheCity.java @@ -1,28 +1,30 @@ package mage.cards.s; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.PlayCardTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.TargetController; import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.StaticFilters; import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.game.stack.Spell; import mage.game.turn.TurnMod; import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInExile; +import mage.target.targetpointer.FixedTargets; import mage.util.CardUtil; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author LevelX2 @@ -37,7 +39,6 @@ public SearchTheCity(UUID ownerId, CardSetInfo setInfo) { // Whenever you play a card with the same name as one of the exiled cards, you may put one of those cards with that name into its owner's hand. Then if there are no cards exiled with Search the City, sacrifice it. If you do, take an extra turn after this one. this.addAbility(new SearchTheCityTriggeredAbility()); - } private SearchTheCity(final SearchTheCity card) { @@ -64,17 +65,10 @@ private SearchTheCityExileEffect(final SearchTheCityExileEffect effect) { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - // move cards from library to exile - for (int i = 0; i < 5; i++) { - if (player.getLibrary().hasCards()) { - Card topCard = player.getLibrary().getFromTop(game); - topCard.moveToExile(source.getSourceId(), "Cards exiled by Search the City", source, game); - } - } - return true; - } - return false; + return player != null && player.moveCardsToExile( + player.getLibrary().getTopCards(game, 5), source, game, true, + CardUtil.getExileZoneId(game, source), CardUtil.getSourceName(game, source) + ); } @Override @@ -86,8 +80,8 @@ public SearchTheCityExileEffect copy() { class SearchTheCityTriggeredAbility extends PlayCardTriggeredAbility { public SearchTheCityTriggeredAbility() { - super(TargetController.YOU, Zone.BATTLEFIELD, new SearchTheCityExiledCardToHandEffect(), true); - setTriggerPhrase("Whenever you play a card with the same name as one of the exiled cards, " ); + super(TargetController.YOU, Zone.BATTLEFIELD, new SearchTheCityExiledCardToHandEffect()); + setTriggerPhrase("Whenever you play a card with the same name as one of the exiled cards, "); } private SearchTheCityTriggeredAbility(final SearchTheCityTriggeredAbility ability) { @@ -99,30 +93,33 @@ public boolean checkTrigger(GameEvent event, Game game) { if (!super.checkTrigger(event, game)) { return false; } - String cardName = ""; - if (event.getType() == GameEvent.EventType.SPELL_CAST) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null) { - cardName = spell.getName(); - } + MageObject object; + switch (event.getType()) { + case SPELL_CAST: + object = game.getStack().getSpell(event.getTargetId()); + break; + case LAND_PLAYED: + object = game.getCard(event.getTargetId()); + break; + default: + object = null; } - if (event.getType() == GameEvent.EventType.LAND_PLAYED) { - Card card = game.getCard(event.getTargetId()); - if (card != null) { - cardName = card.getName(); - } + if (object == null) { + return false; } - if (cardName.isEmpty()) { + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, this)); + if (exileZone == null || exileZone.isEmpty()) { return false; } - ExileZone searchTheCityExileZone = game.getExile().getExileZone(this.getSourceId()); - FilterCard filter = new FilterCard(); - filter.add(new NamePredicate(cardName)); - - if (searchTheCityExileZone.count(filter, game) == 0) { + Set cards = exileZone + .getCards(game) + .stream() + .filter(card -> card.sharesName(object, game)) + .collect(Collectors.toSet()); + if (cards.isEmpty()) { return false; } - this.getEffects().get(0).setValue("cardName", cardName); + this.getEffects().setTargetPointer(new FixedTargets(cards, game)); return true; } @@ -136,7 +133,8 @@ class SearchTheCityExiledCardToHandEffect extends OneShotEffect { SearchTheCityExiledCardToHandEffect() { super(Outcome.DrawCard); - staticText = "you may put one of those cards with that name into its owner's hand. Then if there are no cards exiled with {this}, sacrifice it. If you do, take an extra turn after this one"; + staticText = "you may put one of those cards with that name into its owner's hand. Then if there are " + + "no cards exiled with {this}, sacrifice it. If you do, take an extra turn after this one"; } private SearchTheCityExiledCardToHandEffect(final SearchTheCityExiledCardToHandEffect effect) { @@ -145,33 +143,27 @@ private SearchTheCityExiledCardToHandEffect(final SearchTheCityExiledCardToHandE @Override public boolean apply(Game game, Ability source) { - String cardName = (String) this.getValue("cardName"); Player controller = game.getPlayer(source.getControllerId()); if (controller == null) { return false; } - ExileZone searchTheCityExileZone = game.getExile().getExileZone(source.getSourceId()); - if (cardName != null - && searchTheCityExileZone != null) { - for (Card card : searchTheCityExileZone.getCards(game)) { - if (CardUtil.haveSameNames(card, cardName, game)) { - if (controller.moveCards(card, Zone.HAND, source, game)) { - game.informPlayers("Search the City: put " + card.getName() + " into owner's hand"); - } - searchTheCityExileZone.remove(card); - if (searchTheCityExileZone.isEmpty()) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - permanent.sacrifice(source, game); - // extra turn - game.getState().getTurnMods().add(new TurnMod(source.getControllerId()).withExtraTurn()); - } - } - return true; - } - } + Cards cards = new CardsImpl(getTargetPointer().getTargets(game, source)); + cards.retainZone(Zone.EXILED, game); + TargetCard target = new TargetCardInExile(0, 1, StaticFilters.FILTER_CARD); + controller.choose(outcome, cards, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + controller.moveCards(card, Zone.HAND, source, game); } - return false; + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + if (exileZone != null && !exileZone.isEmpty()) { + return true; + } + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + if (sourcePermanent != null && sourcePermanent.sacrifice(source, game)) { + game.getState().getTurnMods().add(new TurnMod(source.getControllerId()).withExtraTurn()); + } + return true; } @Override diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 1bb403132251..d688aad4054f 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -776,6 +776,10 @@ public static boolean haveSameNames(MageObject object1, MageObject object2) { return object1 != null && object2 != null && haveSameNames(object1.getName(), object2.getName(), false); } + /** + * Replaced by hasName method, kept to reduce refactoring of old cards + */ + @Deprecated public static boolean haveSameNames(MageObject object, String needName, Game game) { return object.hasName(needName, game); } From 7d33b2230dbf81bc7f6ec34871cfab29e246c809 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 20 Sep 2024 17:12:09 -0400 Subject: [PATCH 04/16] various "different name" refactors --- .../mage/cards/a/ApproachOfTheSecondSun.java | 2 +- .../mage/cards/a/AudienceWithTrostani.java | 33 ++++---- .../src/mage/cards/a/AwakenedAmalgam.java | 39 ++++----- .../src/mage/cards/b/BattleForBretagard.java | 22 ++--- .../src/mage/cards/e/EerieUltimatum.java | 24 +++--- .../src/mage/cards/f/FieldOfTheDead.java | 20 ++--- .../mage/cards/g/GimbalGremlinProdigy.java | 35 ++++---- .../src/mage/cards/l/LilianasContract.java | 34 +++----- .../mage/cards/m/MarvinMurderousMimic.java | 3 +- Mage.Sets/src/mage/cards/m/MazesEnd.java | 55 ++++++------- .../mage/cards/m/MonumentToPerfection.java | 20 ++--- .../src/mage/cards/o/OrmosArchiveKeeper.java | 6 +- .../src/mage/cards/s/SandsteppeWarRiders.java | 26 +++--- .../src/mage/cards/s/SignalTheClans.java | 53 +++++------- Mage.Sets/src/mage/cards/t/TheNecrobloom.java | 19 ++--- .../src/mage/cards/t/TibaltsTrickery.java | 81 +++++++++---------- Mage/src/main/java/mage/util/CardUtil.java | 5 ++ 17 files changed, 222 insertions(+), 255 deletions(-) diff --git a/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java b/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java index 1d8e5653f06f..a52372a1decb 100644 --- a/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java +++ b/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java @@ -103,7 +103,7 @@ public ApproachOfTheSecondSunWatcher() { public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.SPELL_CAST) { //A copy of a spell isn’t cast, so it won’t count as the first nor as the second Approach of the Second Sun. (2017-04-18) Spell spell = game.getStack().getSpell(event.getSourceId()); - if (spell != null && spell.getName().equals("Approach of the Second Sun")) { + if (spell != null && spell.hasName("Approach of the Second Sun", game)) { approachesCast.put(event.getPlayerId(), getApproachesCast(event.getPlayerId()) + 1); } } diff --git a/Mage.Sets/src/mage/cards/a/AudienceWithTrostani.java b/Mage.Sets/src/mage/cards/a/AudienceWithTrostani.java index ad9aa3dcaea4..b49c5f3912bf 100644 --- a/Mage.Sets/src/mage/cards/a/AudienceWithTrostani.java +++ b/Mage.Sets/src/mage/cards/a/AudienceWithTrostani.java @@ -1,6 +1,5 @@ package mage.cards.a; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; @@ -11,10 +10,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; -import mage.game.permanent.PermanentToken; import mage.game.permanent.token.PlantToken; +import mage.util.CardUtil; import java.util.UUID; @@ -45,8 +46,14 @@ public AudienceWithTrostani copy() { enum AudienceWithTrostaniValue implements DynamicValue { instance; + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(TokenPredicate.TRUE); + } + private static final Hint hint = new ValueHint( - "Different names among creature tokens you control", instance + "Differently named creature tokens you control", instance ); public static Hint getHint() { @@ -55,19 +62,11 @@ public static Hint getHint() { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return game - .getBattlefield() - .getActivePermanents( - StaticFilters.FILTER_CONTROLLED_CREATURE, - sourceAbility.getControllerId(), sourceAbility, game - ) - .stream() - .filter(PermanentToken.class::isInstance) - .map(MageObject::getName) - .filter(s -> !s.isEmpty()) - .distinct() - .mapToInt(x -> 1) - .sum(); + return CardUtil.differentlyNamedAmongCollection( + game.getBattlefield().getActivePermanents( + filter, sourceAbility.getControllerId(), sourceAbility, game + ), game + ); } @Override diff --git a/Mage.Sets/src/mage/cards/a/AwakenedAmalgam.java b/Mage.Sets/src/mage/cards/a/AwakenedAmalgam.java index 9a2accffcf6b..e5bf4d57b550 100644 --- a/Mage.Sets/src/mage/cards/a/AwakenedAmalgam.java +++ b/Mage.Sets/src/mage/cards/a/AwakenedAmalgam.java @@ -1,25 +1,25 @@ - package mage.cards.a; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.SetBasePowerToughnessSourceEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class AwakenedAmalgam extends CardImpl { @@ -32,8 +32,9 @@ public AwakenedAmalgam(UUID ownerId, CardSetInfo setInfo) { this.toughness = new MageInt(0); // Awakened Amalgam's power and toughness are each equal to the number of differently named lands you control. - DynamicValue value = (new AwakenedAmalgamLandNamesCount()); - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetBasePowerToughnessSourceEffect(value))); + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new SetBasePowerToughnessSourceEffect(AwakenedAmalgamValue.instance) + ).addHint(AwakenedAmalgamValue.getHint())); } private AwakenedAmalgam(final AwakenedAmalgam card) { @@ -46,24 +47,26 @@ public AwakenedAmalgam copy() { } } -class AwakenedAmalgamLandNamesCount implements DynamicValue { +enum AwakenedAmalgamValue implements DynamicValue { + instance; + private static final Hint hint = new ValueHint("Differently named lands you control", instance); - public AwakenedAmalgamLandNamesCount() { + public static Hint getHint() { + return hint; } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - Set landNames = new HashSet<>(); - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(sourceAbility.getControllerId())) { - if (permanent.isLand(game)) { - landNames.add(permanent.getName()); - } - } - return landNames.size(); + return CardUtil.differentlyNamedAmongCollection( + game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, + sourceAbility.getControllerId(), sourceAbility, game + ), game + ); } @Override - public AwakenedAmalgamLandNamesCount copy() { + public AwakenedAmalgamValue copy() { return this; } diff --git a/Mage.Sets/src/mage/cards/b/BattleForBretagard.java b/Mage.Sets/src/mage/cards/b/BattleForBretagard.java index ac11200470e8..1e7f4c746a5e 100644 --- a/Mage.Sets/src/mage/cards/b/BattleForBretagard.java +++ b/Mage.Sets/src/mage/cards/b/BattleForBretagard.java @@ -1,6 +1,5 @@ package mage.cards.b; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SagaAbility; import mage.abilities.effects.OneShotEffect; @@ -131,33 +130,34 @@ public boolean canTarget(UUID playerId, UUID id, Ability ability, Game game) { if (!super.canTarget(playerId, id, ability, game)) { return false; } - Set names = this.getTargets() + Set permanents = this + .getTargets() .stream() .map(game::getPermanent) .filter(Objects::nonNull) - .map(MageObject::getName) .collect(Collectors.toSet()); - names.removeIf(Objects::isNull); - names.removeIf(String::isEmpty); Permanent permanent = game.getPermanent(id); - return permanent != null && !names.contains(permanent.getName()); + return permanent != null + && permanents + .stream() + .noneMatch(p -> p.sharesName(permanent, game)); } @Override public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); - Set names = this.getTargets() + Set permanents = this.getTargets() .stream() .map(game::getPermanent) .filter(Objects::nonNull) - .map(MageObject::getName) .collect(Collectors.toSet()); - names.removeIf(Objects::isNull); - names.removeIf(String::isEmpty); possibleTargets.removeIf(uuid -> { Permanent permanent = game.getPermanent(uuid); - return permanent == null || names.contains(permanent.getName()); + return permanent == null + || permanents + .stream() + .anyMatch(p -> p.sharesName(permanent, game)); }); return possibleTargets; } diff --git a/Mage.Sets/src/mage/cards/e/EerieUltimatum.java b/Mage.Sets/src/mage/cards/e/EerieUltimatum.java index 0ecd4db232ba..151befe4755a 100644 --- a/Mage.Sets/src/mage/cards/e/EerieUltimatum.java +++ b/Mage.Sets/src/mage/cards/e/EerieUltimatum.java @@ -1,6 +1,5 @@ package mage.cards.e; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -90,32 +89,33 @@ public EerieUltimatumTarget copy() { @Override public boolean canTarget(UUID playerId, UUID id, Ability ability, Game game) { - if (super.canTarget(playerId, id, ability, game)) { - Set names = this.getTargets() + if (!super.canTarget(playerId, id, ability, game)) { + return false; + } + Set cards = this.getTargets() .stream() .map(game::getCard) - .map(MageObject::getName) .filter(Objects::nonNull) .collect(Collectors.toSet()); - Card card = game.getCard(id); - return card != null && !names.contains(card.getName()); - } - return false; + Card card = game.getCard(id); + return card != null + && cards + .stream() + .noneMatch(c -> c.sharesName(card, game)); } - + @Override public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); - Set names = this.getTargets() + Set cards = this.getTargets() .stream() .map(game::getCard) - .map(MageObject::getName) .filter(Objects::nonNull) .collect(Collectors.toSet()); possibleTargets.removeIf(uuid -> { Card card = game.getCard(uuid); - return card != null && names.contains(card.getName()); + return card != null && cards.stream().anyMatch(c -> c.sharesName(card, game)); }); return possibleTargets; } diff --git a/Mage.Sets/src/mage/cards/f/FieldOfTheDead.java b/Mage.Sets/src/mage/cards/f/FieldOfTheDead.java index 92c7fdadf5cc..43f5527f53be 100644 --- a/Mage.Sets/src/mage/cards/f/FieldOfTheDead.java +++ b/Mage.Sets/src/mage/cards/f/FieldOfTheDead.java @@ -13,7 +13,7 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.token.ZombieToken; -import mage.players.Player; +import mage.util.CardUtil; import java.util.UUID; @@ -56,17 +56,11 @@ enum FieldOfTheDeadCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - return game - .getBattlefield() - .getAllActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), game) - .stream() - .map(permanent -> permanent.getName()) - .filter(s -> s.length() > 0) - .distinct() - .count() > 6; + return CardUtil.differentlyNamedAmongCollection( + game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, + source.getControllerId(), source, game + ), game + ) >= 7; } } diff --git a/Mage.Sets/src/mage/cards/g/GimbalGremlinProdigy.java b/Mage.Sets/src/mage/cards/g/GimbalGremlinProdigy.java index ff25225f7753..eae1200f3860 100644 --- a/Mage.Sets/src/mage/cards/g/GimbalGremlinProdigy.java +++ b/Mage.Sets/src/mage/cards/g/GimbalGremlinProdigy.java @@ -1,7 +1,6 @@ package mage.cards.g; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -12,14 +11,16 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.CounterType; +import mage.filter.FilterPermanent; import mage.filter.StaticFilters; +import mage.filter.common.FilterArtifactPermanent; +import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.PermanentToken; import mage.game.permanent.token.GremlinArtifactToken; import mage.game.permanent.token.Token; +import mage.util.CardUtil; -import java.util.Objects; import java.util.UUID; /** @@ -60,6 +61,12 @@ public GimbalGremlinProdigy copy() { class GimbalGremlinProdigyEffect extends OneShotEffect { + private static final FilterPermanent filter = new FilterArtifactPermanent(); + + static { + filter.add(TokenPredicate.TRUE); + } + GimbalGremlinProdigyEffect() { super(Outcome.Benefit); staticText = "create a 0/0 red Gremlin artifact creature token. Put X +1/+1 counters on it, " + @@ -79,20 +86,14 @@ public GimbalGremlinProdigyEffect copy() { public boolean apply(Game game, Ability source) { Token token = new GremlinArtifactToken(); token.putOntoBattlefield(1, game, source); - int amount = game - .getBattlefield() - .getActivePermanents( - StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, - source.getControllerId(), source, game - ) - .stream() - .filter(PermanentToken.class::isInstance) - .map(MageObject::getName) - .filter(Objects::nonNull) - .filter(s -> !s.isEmpty()) - .distinct() - .mapToInt(i -> 1) - .sum(); + int amount = CardUtil.differentlyNamedAmongCollection( + game.getBattlefield().getActivePermanents( + filter, source.getControllerId(), source, game + ), game + ); + if (amount < 1) { + return true; + } for (UUID tokenId : token.getLastAddedTokenIds()) { Permanent permanent = game.getPermanent(tokenId); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/l/LilianasContract.java b/Mage.Sets/src/mage/cards/l/LilianasContract.java index 0b255c5a5a78..90d2dac2baff 100644 --- a/Mage.Sets/src/mage/cards/l/LilianasContract.java +++ b/Mage.Sets/src/mage/cards/l/LilianasContract.java @@ -1,8 +1,5 @@ package mage.cards.l; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -16,11 +13,14 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class LilianasContract extends CardImpl { @@ -46,8 +46,8 @@ public LilianasContract(UUID ownerId, CardSetInfo setInfo) { TargetController.YOU, false ), LilianasContractCondition.instance, "At the beginning of your upkeep, " - + "if you control four or more Demons with different names, " - + "you win the game." + + "if you control four or more Demons with different names, " + + "you win the game." )); } @@ -62,24 +62,16 @@ public LilianasContract copy() { } enum LilianasContractCondition implements Condition { - instance; + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.DEMON); @Override public boolean apply(Game game, Ability source) { - Set demonNames = new HashSet<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (permanent == null - || !permanent.isControlledBy(source.getControllerId()) - || !permanent.hasSubtype(SubType.DEMON, game)) { - continue; - } - demonNames.add(permanent.getName()); - if (demonNames.size() > 3) { - return true; - } - } - return false; + return CardUtil.differentlyNamedAmongCollection( + game.getBattlefield().getActivePermanents( + filter, source.getControllerId(), source, game + ), game + ) >= 4; } @Override diff --git a/Mage.Sets/src/mage/cards/m/MarvinMurderousMimic.java b/Mage.Sets/src/mage/cards/m/MarvinMurderousMimic.java index 0cb39a828ce1..c5fcdf24e830 100644 --- a/Mage.Sets/src/mage/cards/m/MarvinMurderousMimic.java +++ b/Mage.Sets/src/mage/cards/m/MarvinMurderousMimic.java @@ -10,7 +10,6 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.util.CardUtil; import java.util.Collection; import java.util.List; @@ -74,7 +73,7 @@ public boolean apply(Game game, Ability source) { source.getControllerId(), source, game ) .stream() - .filter(p -> !CardUtil.haveSameNames(p, permanent)) + .filter(p -> !p.sharesName(permanent, game)) .map(p -> p.getAbilities(game)) .flatMap(Collection::stream) .filter(Ability::isActivatedAbility) diff --git a/Mage.Sets/src/mage/cards/m/MazesEnd.java b/Mage.Sets/src/mage/cards/m/MazesEnd.java index 1c4f5b6d9539..a50bd0989980 100644 --- a/Mage.Sets/src/mage/cards/m/MazesEnd.java +++ b/Mage.Sets/src/mage/cards/m/MazesEnd.java @@ -10,6 +10,7 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.hint.Hint; import mage.abilities.hint.ValueHint; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; @@ -17,15 +18,14 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; /** @@ -43,20 +43,20 @@ public final class MazesEnd extends CardImpl { public MazesEnd(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - // Maze's End enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); // {T}: Add 1. this.addAbility(new ColorlessManaAbility()); - // 3, {T}, Return Maze's End to its owner's hand: Search your library for a Gate card, put it onto the battlefield, then shuffle your library. If you control ten or more Gates with different names, you win the game. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filterCard)), new GenericManaCost(3)); - ability.addEffect(new MazesEndEffect()); + // {3}, {T}, Return Maze's End to its owner's hand: Search your library for a Gate card, put it onto the battlefield, then shuffle your library. If you control ten or more Gates with different names, you win the game. + Ability ability = new SimpleActivatedAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filterCard)), new GenericManaCost(3) + ); ability.addCost(new TapSourceCost()); ability.addCost(new ReturnToHandFromBattlefieldSourceCost()); - ability.addHint(new ValueHint("Gates with different names you control", GatesWithDifferentNamesYouControlCount.instance)); - this.addAbility(ability); + ability.addEffect(new MazesEndEffect()); + this.addAbility(ability.addHint(GatesWithDifferentNamesYouControlCount.getHint())); } private MazesEnd(final MazesEnd card) { @@ -70,20 +70,21 @@ public MazesEnd copy() { } enum GatesWithDifferentNamesYouControlCount implements DynamicValue { - instance; + private static final FilterPermanent filter = new FilterControlledPermanent(SubType.GATE); + private static final Hint hint = new ValueHint("Gates with different names you control", instance); + + public static Hint getHint() { + return hint; + } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - List names = new ArrayList<>(); - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(sourceAbility.getControllerId())) { - if (permanent.hasSubtype(SubType.GATE, game)) { - if (!names.contains(permanent.getName())) { - names.add(permanent.getName()); - } - } - } - return names.size(); + return CardUtil.differentlyNamedAmongCollection( + game.getBattlefield().getActivePermanents( + filter, sourceAbility.getControllerId(), sourceAbility, game + ), game + ); } @Override @@ -121,13 +122,13 @@ public MazesEndEffect copy() { @Override public boolean apply(Game game, Ability source) { - int count = GatesWithDifferentNamesYouControlCount.instance.calculate(game, source, this); - if (count >= 10) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.won(game); - } + if (GatesWithDifferentNamesYouControlCount.instance.calculate(game, source, this) < 10) { + return false; + } + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + controller.won(game); } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/m/MonumentToPerfection.java b/Mage.Sets/src/mage/cards/m/MonumentToPerfection.java index 45371e919543..b048d06db7ff 100644 --- a/Mage.Sets/src/mage/cards/m/MonumentToPerfection.java +++ b/Mage.Sets/src/mage/cards/m/MonumentToPerfection.java @@ -1,8 +1,5 @@ package mage.cards.m; -import java.util.UUID; - -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -28,6 +25,9 @@ import mage.game.Game; import mage.game.permanent.token.custom.CreatureToken; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.UUID; /** * @author TheElk801 @@ -96,15 +96,11 @@ enum MonumentToPerfectionValue implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return game - .getBattlefield() - .getActivePermanents(filter, sourceAbility.getControllerId(), game) - .stream() - .map(MageObject::getName) - .filter(s -> s.length() > 0) - .distinct() - .mapToInt(x -> 1) - .sum(); + return CardUtil.differentlyNamedAmongCollection( + game.getBattlefield().getActivePermanents( + filter, sourceAbility.getControllerId(), sourceAbility, game + ), game + ); } @Override diff --git a/Mage.Sets/src/mage/cards/o/OrmosArchiveKeeper.java b/Mage.Sets/src/mage/cards/o/OrmosArchiveKeeper.java index 1adb6e54c7cc..d223b1cc8912 100644 --- a/Mage.Sets/src/mage/cards/o/OrmosArchiveKeeper.java +++ b/Mage.Sets/src/mage/cards/o/OrmosArchiveKeeper.java @@ -1,7 +1,6 @@ package mage.cards.o; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -127,15 +126,14 @@ public OrmosArchiveKeeperTarget copy() { @Override public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); - Set names = this.getTargets() + Set cards = this.getTargets() .stream() .map(game::getCard) - .map(MageObject::getName) .filter(Objects::nonNull) .collect(Collectors.toSet()); possibleTargets.removeIf(uuid -> { Card card = game.getCard(uuid); - return card != null && names.contains(card.getName()); + return card != null && cards.stream().anyMatch(c -> c.sharesName(card, game)); }); return possibleTargets; } diff --git a/Mage.Sets/src/mage/cards/s/SandsteppeWarRiders.java b/Mage.Sets/src/mage/cards/s/SandsteppeWarRiders.java index bbe144e2b696..b0a58957aff9 100644 --- a/Mage.Sets/src/mage/cards/s/SandsteppeWarRiders.java +++ b/Mage.Sets/src/mage/cards/s/SandsteppeWarRiders.java @@ -1,7 +1,6 @@ package mage.cards.s; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfCombatTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; @@ -19,8 +18,8 @@ import mage.filter.common.FilterControlledArtifactPermanent; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; +import mage.util.CardUtil; -import java.util.Objects; import java.util.UUID; /** @@ -40,7 +39,9 @@ public SandsteppeWarRiders(UUID ownerId, CardSetInfo setInfo) { this.addAbility(TrampleAbility.getInstance()); // At the beginning of combat on your turn, bolster X, where X is the number of differently named artifact tokens you control. - this.addAbility(new BeginningOfCombatTriggeredAbility(new BolsterEffect(SandsteppeWarRidersValue.instance), TargetController.YOU, false)); + this.addAbility(new BeginningOfCombatTriggeredAbility( + new BolsterEffect(SandsteppeWarRidersValue.instance), TargetController.YOU, false + ).addHint(SandsteppeWarRidersValue.getHint())); } private SandsteppeWarRiders(final SandsteppeWarRiders card) { @@ -63,18 +64,17 @@ enum SandsteppeWarRidersValue implements DynamicValue { private static final Hint hint = new ValueHint("Different artifact token names you control", instance); + public static Hint getHint() { + return hint; + } + @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return game - .getBattlefield() - .getActivePermanents(filter, sourceAbility.getControllerId(), sourceAbility, game) - .stream() - .map(MageObject::getName) - .filter(Objects::nonNull) - .filter(s -> !s.isEmpty()) - .distinct() - .mapToInt(x -> 1) - .sum(); + return CardUtil.differentlyNamedAmongCollection( + game.getBattlefield().getActivePermanents( + filter, sourceAbility.getControllerId(), sourceAbility, game + ), game + ); } @Override diff --git a/Mage.Sets/src/mage/cards/s/SignalTheClans.java b/Mage.Sets/src/mage/cards/s/SignalTheClans.java index 5de113017745..5c96542de347 100644 --- a/Mage.Sets/src/mage/cards/s/SignalTheClans.java +++ b/Mage.Sets/src/mage/cards/s/SignalTheClans.java @@ -1,12 +1,11 @@ package mage.cards.s; -import java.util.UUID; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.SearchEffect; -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; @@ -14,9 +13,11 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Plopman */ public final class SignalTheClans extends CardImpl { @@ -61,32 +62,22 @@ public boolean apply(Game game, Ability source) { return false; } //Search your library for three creature cards - if (controller.searchLibrary(target, source, game)) { - boolean shuffleDone = false; - if (!target.getTargets().isEmpty()) { - Cards cards = new CardsImpl(target.getTargets()); - //Reveal them - controller.revealCards(source, cards, game); - Card cardsArray[] = cards.getCards(game).toArray(new Card[0]); - //If you reveal three cards with different names - if (Stream.of(cardsArray).map(MageObject::getName).collect(Collectors.toSet()).size() == 3) { - //Choose one of them at random and put that card into your hand - Card randomCard = cards.getRandom(game); - controller.moveCards(randomCard, Zone.HAND, source, game); - cards.remove(randomCard); - } - // Shuffle the rest into your library - if (!cards.isEmpty()) { - controller.shuffleCardsToLibrary(cards, game, source); - shuffleDone = true; - } - } - if (!shuffleDone) { - controller.shuffleLibrary(source, game); - } - return true; + controller.searchLibrary(target, source, game); + Cards cards = new CardsImpl(target.getTargets()); + //Reveal them + controller.revealCards(source, cards, game); + //If you reveal three cards with different names + if (CardUtil.differentlyNamedAmongCollection(cards.getCards(game), game) >= 3) { + //Choose one of them at random and put that card into your hand + controller.moveCards(cards.getRandom(game), Zone.HAND, source, game); + } + cards.retainZone(Zone.LIBRARY, game); + // Shuffle the rest into your library + if (!cards.isEmpty()) { + controller.shuffleCardsToLibrary(cards, game, source); } - return false; + controller.shuffleLibrary(source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/t/TheNecrobloom.java b/Mage.Sets/src/mage/cards/t/TheNecrobloom.java index d281200b1a66..ff333134074d 100644 --- a/Mage.Sets/src/mage/cards/t/TheNecrobloom.java +++ b/Mage.Sets/src/mage/cards/t/TheNecrobloom.java @@ -18,6 +18,7 @@ import mage.game.permanent.token.PlantToken; import mage.game.permanent.token.ZombieToken; import mage.players.Player; +import mage.util.CardUtil; import java.util.UUID; @@ -63,18 +64,12 @@ enum TheNecrobloomCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - return game - .getBattlefield() - .getAllActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), game) - .stream() - .map(permanent -> permanent.getName()) - .filter(s -> s.length() > 0) - .distinct() - .count() > 6; + return CardUtil.differentlyNamedAmongCollection( + game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, + source.getControllerId(), source, game + ), game + ) >= 7; } } diff --git a/Mage.Sets/src/mage/cards/t/TibaltsTrickery.java b/Mage.Sets/src/mage/cards/t/TibaltsTrickery.java index 39075607b9f2..c47280b35932 100644 --- a/Mage.Sets/src/mage/cards/t/TibaltsTrickery.java +++ b/Mage.Sets/src/mage/cards/t/TibaltsTrickery.java @@ -1,9 +1,5 @@ package mage.cards.t; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; - import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -12,9 +8,6 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.NamePredicate; import mage.game.ExileZone; import mage.game.Game; import mage.game.stack.Spell; @@ -23,8 +16,11 @@ import mage.util.CardUtil; import mage.util.RandomUtil; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class TibaltsTrickery extends CardImpl { @@ -72,43 +68,40 @@ public TibaltsTrickeryEffect copy() { @Override public boolean apply(Game game, Ability source) { Spell spell = game.getStack().getSpell(getTargetPointer().getFirst(game, source)); - if (spell != null) { - String spellName = spell.getName(); - Player controller = game.getPlayer(spell.getControllerId()); - game.getStack().counter(spell.getId(), source, game); - if (controller != null) { - int random = RandomUtil.nextInt(3) + 1; - game.informPlayers(random + " was chosen at random"); - controller.millCards(random, source, game); - Card cardToCast = null; - Set cardsToExile = new HashSet<>(); - FilterCard filter = new FilterCard(); - filter.add(Predicates.not(CardType.LAND.getPredicate())); - filter.add(Predicates.not(new NamePredicate(spellName))); - for (Card card : controller.getLibrary().getCards(game)) { - cardsToExile.add(card); - if (filter.match(card, game)) { - cardToCast = card; - break; - } - } - controller.moveCardsToExile(cardsToExile, source, game, true, source.getSourceId(), - CardUtil.createObjectRealtedWindowTitle(source, game, null)); - if (cardToCast != null) { - if (controller.chooseUse(Outcome.PlayForFree, "Cast " + cardToCast.getLogName() + " for free?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(cardToCast, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null); - } - } - ExileZone exile = game.getExile().getExileZone(source.getSourceId()); - if (exile != null) { - controller.putCardsOnBottomOfLibrary(exile, game, source, false); - } - } + if (spell == null) { + return false; + } + Player controller = game.getPlayer(spell.getControllerId()); + game.getStack().counter(spell.getId(), source, game); + if (controller == null) { return true; } - return false; + int random = RandomUtil.nextInt(3) + 1; + game.informPlayers(random + " was chosen at random"); + controller.millCards(random, source, game); + Card cardToCast = null; + Set cardsToExile = new HashSet<>(); + for (Card card : controller.getLibrary().getCards(game)) { + cardsToExile.add(card); + if (card != null && !card.isLand(game) && !card.sharesName(spell, game)) { + cardToCast = card; + break; + } + } + controller.moveCardsToExile(cardsToExile, source, game, true, source.getSourceId(), + CardUtil.createObjectRealtedWindowTitle(source, game, null)); + if (cardToCast != null) { + if (controller.chooseUse(Outcome.PlayForFree, "Cast " + cardToCast.getLogName() + " for free?", source, game)) { + game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), Boolean.TRUE); + controller.cast(controller.chooseAbilityForCast(cardToCast, game, true), + game, true, new ApprovingObject(source, game)); + game.getState().setValue("PlayFromNotOwnHandZone" + cardToCast.getId(), null); + } + } + ExileZone exile = game.getExile().getExileZone(source.getSourceId()); + if (exile != null) { + controller.putCardsOnBottomOfLibrary(exile, game, source, false); + } + return true; } } diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index d688aad4054f..de2499820490 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -794,6 +794,11 @@ public static boolean haveEmptyName(MageObject object) { return object == null || haveEmptyName(object.getName()); } + public static int differentlyNamedAmongCollection(Collection collection, Game game) { + // TODO: Implement this + return 0; + } + public static UUID getMainCardId(Game game, UUID objectId) { Card card = game.getCard(objectId); return card != null ? card.getMainCard().getId() : objectId; From c07b9680bdac593893bed2d39a39064f422490ba Mon Sep 17 00:00:00 2001 From: theelk801 Date: Mon, 23 Sep 2024 19:38:58 -0400 Subject: [PATCH 05/16] some more refactoring --- Mage.Sets/src/mage/cards/a/AssemblyHall.java | 14 +-- Mage.Sets/src/mage/cards/a/AvenShrine.java | 109 ++++++------------ Mage.Sets/src/mage/cards/b/Banishment.java | 9 +- .../src/mage/cards/b/BazaarOfWonders.java | 31 ++--- Mage.Sets/src/mage/cards/b/Bifurcate.java | 12 +- .../src/mage/cards/b/BloodbondMarch.java | 8 +- Mage.Sets/src/mage/cards/c/CabalShrine.java | 108 ++++++----------- .../src/mage/cards/c/CurseOfMisfortunes.java | 59 +++++----- .../src/mage/cards/e/EchoingCourage.java | 43 +++---- Mage.Sets/src/mage/cards/e/EchoingDecay.java | 42 ++++--- Mage.Sets/src/mage/cards/e/EchoingTruth.java | 49 ++++---- .../src/mage/cards/g/GuardianProject.java | 36 ++---- .../src/mage/cards/h/HomingLightning.java | 32 ++--- Mage.Sets/src/mage/cards/i/InfernalTutor.java | 58 ++++------ .../src/mage/cards/i/IzzetStaticaster.java | 35 +++--- .../DestroyAllNamedPermanentsEffect.java | 15 ++- .../mage/abilities/keyword/RippleAbility.java | 7 +- .../mageobject/SharesNamePredicate.java | 22 ++++ 18 files changed, 300 insertions(+), 389 deletions(-) create mode 100644 Mage/src/main/java/mage/filter/predicate/mageobject/SharesNamePredicate.java diff --git a/Mage.Sets/src/mage/cards/a/AssemblyHall.java b/Mage.Sets/src/mage/cards/a/AssemblyHall.java index 8cdd37df5b85..f63ed694fa4a 100644 --- a/Mage.Sets/src/mage/cards/a/AssemblyHall.java +++ b/Mage.Sets/src/mage/cards/a/AssemblyHall.java @@ -15,13 +15,12 @@ import mage.constants.Outcome; import mage.filter.FilterCard; import mage.filter.StaticFilters; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.mageobject.SharesNamePredicate; import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInLibrary; -import mage.util.CardUtil; import java.util.UUID; @@ -74,19 +73,16 @@ public boolean apply(Game game, Ability source) { if (controller == null || controller.getHand().isEmpty() || sourceObject == null) { return false; } - Card cardToReveal = null; Target target = new TargetCardInHand(StaticFilters.FILTER_CARD_CREATURE); target.withNotTarget(true); - if (controller.chooseTarget(outcome, target, source, game)) { - cardToReveal = game.getCard(target.getFirstTarget()); - } + controller.chooseTarget(outcome, target, source, game); + Card cardToReveal = game.getCard(target.getFirstTarget()); if (cardToReveal == null) { return false; } controller.revealCards("from hand :" + sourceObject.getName(), new CardsImpl(cardToReveal), game); - String nameToSearch = CardUtil.getCardNameForSameNameSearch(cardToReveal); - FilterCard filterCard = new FilterCard("card named " + nameToSearch); - filterCard.add(new NamePredicate(nameToSearch)); + FilterCard filterCard = new FilterCard("card with the same name as " + cardToReveal.getName()); + filterCard.add(new SharesNamePredicate(cardToReveal)); return new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filterCard), true).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/a/AvenShrine.java b/Mage.Sets/src/mage/cards/a/AvenShrine.java index 91f750138146..1a38f94b0a5e 100644 --- a/Mage.Sets/src/mage/cards/a/AvenShrine.java +++ b/Mage.Sets/src/mage/cards/a/AvenShrine.java @@ -1,27 +1,24 @@ - package mage.cards.a; -import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SpellCastAllTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.constants.SetTargetPointer; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; import mage.players.Player; +import java.util.Collection; +import java.util.Objects; +import java.util.UUID; + /** - * - * @author jeffwadsworth + * @author TheElk801 */ public final class AvenShrine extends CardImpl { @@ -29,8 +26,10 @@ public AvenShrine(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{W}"); // Whenever a player casts a spell, that player gains X life, where X is the number of cards in all graveyards with the same name as that spell. - this.addAbility(new AvenShrineTriggeredAbility()); - + this.addAbility(new SpellCastAllTriggeredAbility( + new AvenShrineEffect(), StaticFilters.FILTER_SPELL_A, + false, SetTargetPointer.PLAYER + )); } private AvenShrine(final AvenShrine card) { @@ -43,44 +42,12 @@ public AvenShrine copy() { } } -class AvenShrineTriggeredAbility extends TriggeredAbilityImpl { - - public AvenShrineTriggeredAbility() { - super(Zone.BATTLEFIELD, new AvenShrineEffect(), false); - } - - private AvenShrineTriggeredAbility(final AvenShrineTriggeredAbility ability) { - super(ability); - } - - @Override - public AvenShrineTriggeredAbility copy() { - return new AvenShrineTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - MageObject mageObject = game.getObject(sourceId); - if (spell != null && mageObject != null) { - game.getState().setValue("avenShrine" + mageObject, spell); - return true; - } - return false; - } - -} - class AvenShrineEffect extends OneShotEffect { AvenShrineEffect() { - super(Outcome.GainLife); - staticText = "Whenever a player casts a spell, that player gains X life, where X is the number of cards in all graveyards with the same name as that spell"; + super(Outcome.Benefit); + staticText = "that player gains X life, where X is the number " + + "of cards in all graveyards with the same name as that spell"; } private AvenShrineEffect(final AvenShrineEffect effect) { @@ -88,33 +55,29 @@ private AvenShrineEffect(final AvenShrineEffect effect) { } @Override - public boolean apply(Game game, Ability source) { - int count = 0; - MageObject mageObject = game.getObject(source); - if(mageObject != null) { - Spell spell = (Spell) game.getState().getValue("avenShrine" + mageObject); - if (spell != null) { - Player controller = game.getPlayer(spell.getControllerId()); - if (controller != null) { - String name = spell.getName(); - FilterCard filterCardName = new FilterCard(); - filterCardName.add(new NamePredicate(name)); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - count += player.getGraveyard().count(filterCardName, game); - } - } - controller.gainLife(count, game, source); - return true; - } - } - } - return false; + public AvenShrineEffect copy() { + return new AvenShrineEffect(this); } @Override - public AvenShrineEffect copy() { - return new AvenShrineEffect(this); + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + Spell spell = (Spell) getValue("spellCast"); + if (player == null || spell == null) { + return false; + } + int count = game + .getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getGraveyard) + .map(g -> g.getCards(game)) + .flatMap(Collection::stream) + .filter(c -> c.sharesName(spell, game)) + .mapToInt(x -> 1) + .sum(); + return player.gainLife(count, game, source) > 0; } } diff --git a/Mage.Sets/src/mage/cards/b/Banishment.java b/Mage.Sets/src/mage/cards/b/Banishment.java index 9e0695d1dd5a..75b2ab6909ee 100644 --- a/Mage.Sets/src/mage/cards/b/Banishment.java +++ b/Mage.Sets/src/mage/cards/b/Banishment.java @@ -13,7 +13,7 @@ import mage.constants.TargetController; import mage.filter.FilterPermanent; import mage.filter.common.FilterNonlandPermanent; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.mageobject.SharesNamePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -26,7 +26,6 @@ import java.util.stream.Collectors; /** - * * @author freaisdead */ public final class Banishment extends CardImpl { @@ -39,7 +38,7 @@ public final class Banishment extends CardImpl { public Banishment(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); - + // Flash this.addAbility(FlashAbility.getInstance()); @@ -85,10 +84,10 @@ public boolean apply(Game game, Ability source) { } FilterPermanent filter = new FilterNonlandPermanent(); - filter.add(new NamePredicate(targeted.getName())); + filter.add(new SharesNamePredicate(targeted)); Set toExile = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game) - .stream().filter(p -> controller.hasOpponent(p.getControllerId(),game)) + .stream().filter(p -> controller.hasOpponent(p.getControllerId(), game)) .collect(Collectors.toCollection(LinkedHashSet::new)); if (!toExile.isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/b/BazaarOfWonders.java b/Mage.Sets/src/mage/cards/b/BazaarOfWonders.java index 21b4231ef811..86d85fc748e0 100644 --- a/Mage.Sets/src/mage/cards/b/BazaarOfWonders.java +++ b/Mage.Sets/src/mage/cards/b/BazaarOfWonders.java @@ -1,28 +1,26 @@ package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SpellCastAllTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileGraveyardAllPlayersEffect; -import mage.constants.SuperType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.SetTargetPointer; +import mage.constants.SuperType; import mage.filter.FilterCard; import mage.filter.FilterPermanent; -import mage.filter.StaticFilters; -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.stack.Spell; import mage.players.Player; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class BazaarOfWonders extends CardImpl { @@ -37,8 +35,7 @@ public BazaarOfWonders(UUID ownerId, CardSetInfo setInfo) { // Whenever a player casts a spell, counter it if a card with the same name is in // a graveyard or a nontoken permanent with the same name is on the battlefield. - this.addAbility(new SpellCastAllTriggeredAbility(new BazaarOfWondersEffect(), - StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.SPELL)); + this.addAbility(new SpellCastAllTriggeredAbility(new BazaarOfWondersEffect(), false)); } private BazaarOfWonders(final BazaarOfWonders card) { @@ -70,27 +67,21 @@ public BazaarOfWondersEffect copy() { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getSpell(getTargetPointer().getFirst(game, source)); + Spell spell = (Spell) getValue("spellCast"); if (spell == null) { return false; } - String spellName = spell.getName(); FilterPermanent filter1 = new FilterPermanent(); - filter1.add(new NamePredicate(spellName)); + filter1.add(new SharesNamePredicate(spell)); filter1.add(TokenPredicate.FALSE); - if (!game.getBattlefield().getActivePermanents(filter1, - source.getControllerId(), game).isEmpty()) { - game.getStack().counter(spell.getId(), source, game); - return true; + if (!game.getBattlefield().contains(filter1, source, game, 1)) { + return game.getStack().counter(spell.getId(), source, game); } FilterCard filter2 = new FilterCard(); - filter2.add(new NamePredicate(spellName)); + filter2.add(new SharesNamePredicate(spell)); for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); - if (player == null) { - continue; - } - if (player.getGraveyard().count(filter2, game) > 0) { + if (player != null && player.getGraveyard().count(filter2, game) > 0) { return game.getStack().counter(spell.getId(), source, game); } } diff --git a/Mage.Sets/src/mage/cards/b/Bifurcate.java b/Mage.Sets/src/mage/cards/b/Bifurcate.java index da513140c6ec..98ba0b4a2473 100644 --- a/Mage.Sets/src/mage/cards/b/Bifurcate.java +++ b/Mage.Sets/src/mage/cards/b/Bifurcate.java @@ -1,4 +1,3 @@ - package mage.cards.b; import mage.abilities.Ability; @@ -11,7 +10,7 @@ import mage.filter.FilterCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterPermanentCard; -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.permanent.Permanent; @@ -21,10 +20,10 @@ import java.util.UUID; /** - * * @author ciaccona007 */ public final class Bifurcate extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creatures"); static { @@ -67,9 +66,12 @@ public BifurcateEffect copy() { @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; + } FilterCard filter = new FilterPermanentCard(); - filter.add(new NamePredicate(permanent.getName())); + filter.add(new SharesNamePredicate(permanent)); return new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter)).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/b/BloodbondMarch.java b/Mage.Sets/src/mage/cards/b/BloodbondMarch.java index 1acfeca7b438..ce791d4dff60 100644 --- a/Mage.Sets/src/mage/cards/b/BloodbondMarch.java +++ b/Mage.Sets/src/mage/cards/b/BloodbondMarch.java @@ -1,6 +1,5 @@ package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SpellCastAllTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -12,13 +11,14 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureSpell; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.mageobject.SharesNamePredicate; import mage.game.Game; import mage.game.stack.Spell; import mage.players.Player; +import java.util.UUID; + /** - * * @author JRHerlehy */ public final class BloodbondMarch extends CardImpl { @@ -66,7 +66,7 @@ public boolean apply(Game game, Ability source) { } FilterCard filter = new FilterCard(); - filter.add(new NamePredicate(spell.getName())); + filter.add(new SharesNamePredicate(spell)); for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); diff --git a/Mage.Sets/src/mage/cards/c/CabalShrine.java b/Mage.Sets/src/mage/cards/c/CabalShrine.java index ec4d9f8fdc38..ba2ccaed5cb1 100644 --- a/Mage.Sets/src/mage/cards/c/CabalShrine.java +++ b/Mage.Sets/src/mage/cards/c/CabalShrine.java @@ -1,36 +1,34 @@ - package mage.cards.c; -import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SpellCastAllTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.constants.SetTargetPointer; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; import mage.players.Player; +import java.util.Collection; +import java.util.Objects; +import java.util.UUID; + /** - * - * @author jeffwadsworth + * @author TheElk801 */ public final class CabalShrine extends CardImpl { public CabalShrine(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); - // Whenever a player casts a spell, that player discards X cards, where X is the number of cards in all graveyards with the same name as that spell. - this.addAbility(new CabalShrineTriggeredAbility()); + this.addAbility(new SpellCastAllTriggeredAbility( + new CabalShrineEffect(), StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.PLAYER + )); } private CabalShrine(final CabalShrine card) { @@ -43,44 +41,12 @@ public CabalShrine copy() { } } -class CabalShrineTriggeredAbility extends TriggeredAbilityImpl { - - public CabalShrineTriggeredAbility() { - super(Zone.BATTLEFIELD, new CabalShrineEffect(), false); - } - - private CabalShrineTriggeredAbility(final CabalShrineTriggeredAbility ability) { - super(ability); - } - - @Override - public CabalShrineTriggeredAbility copy() { - return new CabalShrineTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - MageObject mageObject = game.getObject(sourceId); - if (spell != null && mageObject != null) { - game.getState().setValue("cabalShrine" + mageObject, spell); - return true; - } - return false; - } - -} - class CabalShrineEffect extends OneShotEffect { CabalShrineEffect() { - super(Outcome.Discard); - staticText = "Whenever a player casts a spell, that player discards X cards, where X is the number of cards in all graveyards with the same name as that spell"; + super(Outcome.Benefit); + staticText = "that player discards X cards, where X is the number " + + "of cards in all graveyards with the same name as that spell"; } private CabalShrineEffect(final CabalShrineEffect effect) { @@ -88,33 +54,29 @@ private CabalShrineEffect(final CabalShrineEffect effect) { } @Override - public boolean apply(Game game, Ability source) { - int count = 0; - MageObject mageObject = game.getObject(source); - if(mageObject != null) { - Spell spell = (Spell) game.getState().getValue("cabalShrine" + mageObject); - if (spell != null) { - Player controller = game.getPlayer(spell.getControllerId()); - if (controller != null) { - String name = spell.getName(); - FilterCard filterCardName = new FilterCard(); - filterCardName.add(new NamePredicate(name)); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - count += player.getGraveyard().count(filterCardName, game); - } - } - controller.discard(count, false, false, source, game); - return true; - } - } - } - return false; + public CabalShrineEffect copy() { + return new CabalShrineEffect(this); } @Override - public CabalShrineEffect copy() { - return new CabalShrineEffect(this); + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + Spell spell = (Spell) getValue("spellCast"); + if (player == null || spell == null) { + return false; + } + int amount = game + .getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getGraveyard) + .map(g -> g.getCards(game)) + .flatMap(Collection::stream) + .filter(c -> c.sharesName(spell, game)) + .mapToInt(x -> 1) + .sum(); + return amount > 0 && !player.discard(amount, false, false, source, game).isEmpty(); } } diff --git a/Mage.Sets/src/mage/cards/c/CurseOfMisfortunes.java b/Mage.Sets/src/mage/cards/c/CurseOfMisfortunes.java index a47226e30e8d..c1148648b052 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfMisfortunes.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfMisfortunes.java @@ -15,7 +15,7 @@ import mage.constants.Zone; 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.permanent.Permanent; @@ -27,13 +27,12 @@ import java.util.UUID; /** - * * @author BetaSteward */ public final class CurseOfMisfortunes extends CardImpl { public CurseOfMisfortunes(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}"); this.subtype.add(SubType.AURA, SubType.CURSE); @@ -72,35 +71,35 @@ private CurseOfMisfortunesEffect(final CurseOfMisfortunesEffect effect) { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent enchantment = game.getPermanent(source.getSourceId()); - if (controller != null && enchantment != null && enchantment.getAttachedTo() != null) { - Player targetPlayer = game.getPlayer(enchantment.getAttachedTo()); - Player player = game.getPlayer(source.getControllerId()); - if (player != null && targetPlayer != null) { - FilterCard filter = new FilterCard("Curse card that doesn't have the same name as a Curse attached to enchanted player"); - filter.add(SubType.CURSE.getPredicate()); - // get the names of attached Curses - for (UUID attachmentId: targetPlayer.getAttachments()) { - Permanent attachment = game.getPermanent(attachmentId); - if (attachment != null && attachment.hasSubtype(SubType.CURSE, game)) { - filter.add(Predicates.not(new NamePredicate(attachment.getName()))); - } - } - TargetCardInLibrary targetCard = new TargetCardInLibrary(filter); - if (player.searchLibrary(targetCard, source, game)) { - Card card = game.getCard(targetCard.getFirstTarget()); - if (card != null) { - this.setTargetPointer(new FixedTarget(targetPlayer.getId())); - game.getState().setValue("attachTo:" + card.getId(), targetPlayer.getId()); - if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { - targetPlayer.addAttachment(card.getId(), source, game); - } - } - } - player.shuffleLibrary(source, game); - } + if (controller == null || enchantment == null || enchantment.getAttachedTo() == null) { + return false; + } + Player targetPlayer = game.getPlayer(enchantment.getAttachedTo()); + Player player = game.getPlayer(source.getControllerId()); + if (player == null || targetPlayer == null) { return true; } - return false; + FilterCard filter = new FilterCard("Curse card that doesn't have the same name as a Curse attached to enchanted player"); + filter.add(SubType.CURSE.getPredicate()); + // get the names of attached Curses + for (UUID attachmentId : targetPlayer.getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + if (attachment != null && attachment.hasSubtype(SubType.CURSE, game)) { + filter.add(Predicates.not(new SharesNamePredicate(attachment))); + } + } + TargetCardInLibrary targetCard = new TargetCardInLibrary(filter); + player.searchLibrary(targetCard, source, game); + Card card = player.getLibrary().getCard(targetCard.getFirstTarget(), game); + if (card != null) { + this.setTargetPointer(new FixedTarget(targetPlayer.getId())); + game.getState().setValue("attachTo:" + card.getId(), targetPlayer.getId()); + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + targetPlayer.addAttachment(card.getId(), source, game); + } + } + player.shuffleLibrary(source, game); + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/e/EchoingCourage.java b/Mage.Sets/src/mage/cards/e/EchoingCourage.java index 819a311b6fda..cd1f97758699 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingCourage.java +++ b/Mage.Sets/src/mage/cards/e/EchoingCourage.java @@ -1,23 +1,22 @@ package mage.cards.e; import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; import mage.constants.Outcome; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; -import mage.util.CardUtil; +import mage.target.targetpointer.FixedTargets; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author LevelX2 @@ -27,7 +26,6 @@ public final class EchoingCourage extends CardImpl { public EchoingCourage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); - // Target creature and all other creatures with the same name as that creature get +2/+2 until end of turn. this.getSpellAbility().addEffect(new EchoingCourageEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); @@ -47,7 +45,8 @@ class EchoingCourageEffect extends OneShotEffect { EchoingCourageEffect() { super(Outcome.Benefit); - this.staticText = "Target creature and all other creatures with the same name as that creature get +2/+2 until end of turn"; + this.staticText = "target creature and all other creatures with the " + + "same name as that creature get +2/+2 until end of turn"; } private EchoingCourageEffect(final EchoingCourageEffect effect) { @@ -62,17 +61,21 @@ public EchoingCourageEffect copy() { @Override public boolean apply(Game game, Ability source) { Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (targetPermanent != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (CardUtil.haveEmptyName(targetPermanent)) { - filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected - } else { - filter.add(new NamePredicate(targetPermanent.getName())); - } - ContinuousEffect effect = new BoostAllEffect(2, 2, Duration.EndOfTurn, filter, false); - game.addEffect(effect, source); - return true; + if (targetPermanent == null) { + return false; } - return false; + Set set = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, + source.getControllerId(), source, game + ) + .stream() + .filter(permanent -> permanent.sharesName(targetPermanent, game)) + .collect(Collectors.toSet()); + set.add(targetPermanent); + game.addEffect(new BoostTargetEffect(2, 2) + .setTargetPointer(new FixedTargets(set, game)), source); + return true; } } diff --git a/Mage.Sets/src/mage/cards/e/EchoingDecay.java b/Mage.Sets/src/mage/cards/e/EchoingDecay.java index 74dc1b019afb..fdbeed09f90a 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingDecay.java +++ b/Mage.Sets/src/mage/cards/e/EchoingDecay.java @@ -1,23 +1,22 @@ package mage.cards.e; import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; import mage.constants.Outcome; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; -import mage.util.CardUtil; +import mage.target.targetpointer.FixedTargets; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author fireshoes @@ -46,7 +45,8 @@ class EchoingDecayEffect extends OneShotEffect { EchoingDecayEffect() { super(Outcome.Benefit); - this.staticText = "Target creature and all other creatures with the same name as that creature get -2/-2 until end of turn"; + this.staticText = "target creature and all other creatures with the " + + "same name as that creature get -2/-2 until end of turn"; } private EchoingDecayEffect(final EchoingDecayEffect effect) { @@ -61,17 +61,21 @@ public EchoingDecayEffect copy() { @Override public boolean apply(Game game, Ability source) { Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (targetPermanent != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (CardUtil.haveEmptyName(targetPermanent)) { - filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected - } else { - filter.add(new NamePredicate(targetPermanent.getName())); - } - ContinuousEffect effect = new BoostAllEffect(-2, -2, Duration.EndOfTurn, filter, false); - game.addEffect(effect, source); - return true; + if (targetPermanent == null) { + return false; } - return false; + Set set = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, + source.getControllerId(), source, game + ) + .stream() + .filter(permanent -> permanent.sharesName(targetPermanent, game)) + .collect(Collectors.toSet()); + set.add(targetPermanent); + game.addEffect(new BoostTargetEffect(-2, -2) + .setTargetPointer(new FixedTargets(set, game)), source); + return true; } } diff --git a/Mage.Sets/src/mage/cards/e/EchoingTruth.java b/Mage.Sets/src/mage/cards/e/EchoingTruth.java index f7b9362a7579..fc46b3bb1c36 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingTruth.java +++ b/Mage.Sets/src/mage/cards/e/EchoingTruth.java @@ -1,26 +1,22 @@ package mage.cards.e; import mage.abilities.Ability; -import mage.abilities.Mode; 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; import mage.constants.Zone; -import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.Target; import mage.target.common.TargetNonlandPermanent; -import mage.util.CardUtil; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author LevelX2 @@ -31,9 +27,8 @@ public EchoingTruth(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Return target nonland permanent and all other permanents with the same name as that permanent to their owners' hands. - Target target = new TargetNonlandPermanent(); - this.getSpellAbility().addTarget(target); this.getSpellAbility().addEffect(new ReturnToHandAllNamedPermanentsEffect()); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); } private EchoingTruth(final EchoingTruth card) { @@ -50,7 +45,8 @@ class ReturnToHandAllNamedPermanentsEffect extends OneShotEffect { ReturnToHandAllNamedPermanentsEffect() { super(Outcome.ReturnToHand); - this.staticText = "Return target nonland permanent and all other permanents with the same name as that permanent to their owners' hands"; + this.staticText = "return target nonland permanent and all other permanents " + + "with the same name as that permanent to their owners' hands"; } private ReturnToHandAllNamedPermanentsEffect(final ReturnToHandAllNamedPermanentsEffect effect) { @@ -64,22 +60,21 @@ public ReturnToHandAllNamedPermanentsEffect copy() { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (controller != null && permanent != null) { - FilterPermanent filter = new FilterPermanent(); - if (CardUtil.haveEmptyName(permanent)) { - filter.add(new PermanentIdPredicate(permanent.getId())); // if no name (face down creature) only the creature itself is selected - } else { - filter.add(new NamePredicate(permanent.getName())); - } - Cards cardsToHand = new CardsImpl(); - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - cardsToHand.add(perm); - } - controller.moveCards(cardsToHand, Zone.HAND, source, game); - return true; + Player player = game.getPlayer(source.getControllerId()); + Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (player == null || targetPermanent == null) { + return false; } - return true; + Set set = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_PERMANENT, + source.getControllerId(), source, game + ) + .stream() + .filter(permanent -> permanent.sharesName(targetPermanent, game)) + .collect(Collectors.toSet()); + set.add(targetPermanent); + return player.moveCards(set, Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/g/GuardianProject.java b/Mage.Sets/src/mage/cards/g/GuardianProject.java index a8c016fda54c..5f56b3d8a5d1 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianProject.java +++ b/Mage.Sets/src/mage/cards/g/GuardianProject.java @@ -8,15 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.filter.FilterCard; -import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.card.OwnerIdPredicate; -import mage.filter.predicate.mageobject.CardIdPredicate; -import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; @@ -87,22 +79,18 @@ public String getRule() { // This is needed as checkInterveningIfClause can't access trigger event information static boolean checkCondition(Permanent permanent, UUID controllerId, Game game) { Player player = game.getPlayer(controllerId); - if (player == null) { - return false; - } - if (!permanent.getName().isEmpty()) { - FilterCard filterCard = new FilterCard(); - filterCard.add(new NamePredicate(permanent.getName())); - filterCard.add(new OwnerIdPredicate(controllerId)); - if (player.getGraveyard().count(filterCard, game) > 0) { - return false; - } - } - FilterPermanent filterPermanent = new FilterCreaturePermanent(); - filterPermanent.add(new NamePredicate(permanent.getName())); - filterPermanent.add(Predicates.not(new CardIdPredicate(permanent.getId()))); - filterPermanent.add(new ControllerIdPredicate(controllerId)); - return game.getBattlefield().getActivePermanents(filterPermanent, controllerId, game).isEmpty(); + return player != null + && player + .getGraveyard() + .getCards(game) + .stream() + .noneMatch(card -> card.sharesName(permanent, game)) + && game + .getBattlefield() + .getActivePermanents(StaticFilters.FILTER_CONTROLLED_CREATURE, controllerId, game) + .stream() + .filter(p -> !p.getId().equals(permanent.getId())) + .noneMatch(p -> p.sharesName(permanent, game)); } } diff --git a/Mage.Sets/src/mage/cards/h/HomingLightning.java b/Mage.Sets/src/mage/cards/h/HomingLightning.java index 8fa98cfcfb8d..9b920eb57286 100644 --- a/Mage.Sets/src/mage/cards/h/HomingLightning.java +++ b/Mage.Sets/src/mage/cards/h/HomingLightning.java @@ -6,15 +6,14 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; -import mage.util.CardUtil; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author jeffwadsworth @@ -24,7 +23,6 @@ public final class HomingLightning extends CardImpl { public HomingLightning(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}{R}"); - // Homing Lightning deals 4 damage to target creature and each other creature with the same name as that creature. this.getSpellAbility().addEffect(new HomingLightningEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); @@ -53,20 +51,22 @@ private HomingLightningEffect(final HomingLightningEffect effect) { @Override public boolean apply(Game game, Ability source) { - Permanent targetPermanent = game.getPermanent(source.getFirstTarget()); + Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (targetPermanent == null) { return false; } - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (CardUtil.haveEmptyName(targetPermanent)) { - filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected - } else { - filter.add(new NamePredicate(targetPermanent.getName())); - } - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - if (creature != null) { - creature.damage(4, source.getSourceId(), source, game, false, true); - } + Set set = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, + source.getControllerId(), source, game + ) + .stream() + .filter(permanent -> permanent.sharesName(targetPermanent, game)) + .collect(Collectors.toSet()); + set.add(targetPermanent); + for (Permanent creature : set) { + creature.damage(4, source, game); } return true; } diff --git a/Mage.Sets/src/mage/cards/i/InfernalTutor.java b/Mage.Sets/src/mage/cards/i/InfernalTutor.java index ffa1e548b5ad..bcafbcb509d7 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalTutor.java +++ b/Mage.Sets/src/mage/cards/i/InfernalTutor.java @@ -4,7 +4,6 @@ import mage.abilities.Ability; import mage.abilities.condition.common.HellbentCondition; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.Card; @@ -15,13 +14,12 @@ import mage.constants.Outcome; import mage.filter.FilterCard; import mage.filter.StaticFilters; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.mageobject.SharesNamePredicate; import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInLibrary; -import mage.util.CardUtil; import java.util.UUID; @@ -34,14 +32,14 @@ public InfernalTutor(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); // Reveal a card from your hand. Search your library for a card with the same name as that card, reveal it, put it into your hand, then shuffle your library. - this.getSpellAbility().addEffect(new InfernalTutorEffect()); // Hellbent - If you have no cards in hand, instead search your library for a card, put it into your hand, then shuffle your library. - Effect effect = new ConditionalOneShotEffect( + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD), false), - HellbentCondition.instance, - "

Hellbent — If you have no cards in hand, instead search your library for a card, put it into your hand, then shuffle"); - this.getSpellAbility().addEffect(effect); - + new InfernalTutorEffect(), HellbentCondition.instance, "Reveal a card from your hand. " + + "Search your library for a card with the same name as that card, reveal it, put it into your hand, " + + "then shuffle.
Hellbent — If you have no cards in hand, " + + "instead search your library for a card, put it into your hand, then shuffle" + )); } private InfernalTutor(final InfernalTutor card) { @@ -58,7 +56,6 @@ class InfernalTutorEffect extends OneShotEffect { InfernalTutorEffect() { super(Outcome.Benefit); - this.staticText = "Reveal a card from your hand. Search your library for a card with the same name as that card, reveal it, put it into your hand, then shuffle"; } private InfernalTutorEffect(final InfernalTutorEffect effect) { @@ -74,32 +71,21 @@ public InfernalTutorEffect copy() { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source); - if (controller != null && sourceObject != null) { - if (!controller.getHand().isEmpty()) { - Card cardToReveal = null; - if (controller.getHand().size() > 1) { - Target target = new TargetCardInHand(StaticFilters.FILTER_CARD); - target.withNotTarget(true); - if (controller.chooseTarget(outcome, target, source, game)) { - cardToReveal = game.getCard(target.getFirstTarget()); - } - } else { - cardToReveal = controller.getHand().getRandom(game); - } - FilterCard filterCard; - if (cardToReveal != null) { - controller.revealCards("from hand :" + sourceObject.getName(), new CardsImpl(cardToReveal), game); - String nameToSearch = CardUtil.getCardNameForSameNameSearch(cardToReveal); - filterCard = new FilterCard("card named " + nameToSearch); - filterCard.add(new NamePredicate(nameToSearch)); - } else { - filterCard = new FilterCard(); - } - return new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filterCard), true).apply(game, source); - - } - return true; + if (controller == null || sourceObject == null) { + return false; + } + Card cardToReveal; + if (controller.getHand().size() > 1) { + Target target = new TargetCardInHand(StaticFilters.FILTER_CARD); + target.withNotTarget(true); + controller.chooseTarget(outcome, target, source, game); + cardToReveal = game.getCard(target.getFirstTarget()); + } else { + cardToReveal = controller.getHand().getRandom(game); } - return false; + controller.revealCards("from hand :" + sourceObject.getName(), new CardsImpl(cardToReveal), game); + FilterCard filterCard = new FilterCard("card with the same name as the revealed card"); + filterCard.add(new SharesNamePredicate(cardToReveal)); + return new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filterCard), true).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java b/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java index 47b212807e13..13af192cd33f 100644 --- a/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java +++ b/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java @@ -13,15 +13,14 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; -import mage.util.CardUtil; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author LevelX2 @@ -77,18 +76,22 @@ public IzzetStaticasterDamageEffect copy() { @Override public boolean apply(Game game, Ability source) { Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (targetPermanent != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (CardUtil.haveEmptyName(targetPermanent)) { - filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected - } else { - filter.add(new NamePredicate(targetPermanent.getName())); - } - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { - permanent.damage(1, source.getSourceId(), source, game, false, true); - } - return true; + if (targetPermanent == null) { + return false; } - return false; + Set set = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, + source.getControllerId(), source, game + ) + .stream() + .filter(permanent -> permanent.sharesName(targetPermanent, game)) + .collect(Collectors.toSet()); + set.add(targetPermanent); + for (Permanent creature : set) { + creature.damage(1, source, game); + } + return true; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DestroyAllNamedPermanentsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DestroyAllNamedPermanentsEffect.java index cf1270881b8c..b76871ef1a0d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DestroyAllNamedPermanentsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DestroyAllNamedPermanentsEffect.java @@ -5,11 +5,11 @@ import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SharesNamePredicate; import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.util.CardUtil; /** * @author BetaSteward_at_googlemail.com @@ -36,12 +36,11 @@ public boolean apply(Game game, Ability source) { return false; } FilterPermanent filter = new FilterPermanent(); - if (CardUtil.haveEmptyName(targetPermanent)) { - filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected - } else { - filter.add(new NamePredicate(targetPermanent.getName())); - } - for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { + filter.add(Predicates.or( + new SharesNamePredicate(targetPermanent), + new PermanentIdPredicate(targetPermanent.getId()) + )); + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { perm.destroy(source, game, false); } return true; diff --git a/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java b/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java index c47f59dbfa02..b18df245aa3b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/RippleAbility.java @@ -11,7 +11,7 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; -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; @@ -94,9 +94,8 @@ public boolean apply(Game game, Ability source) { player.revealCards(sourceObject.getIdName(), cards, game); // determine which card should be rippled - String cardNameToRipple = sourceObject.getName(); - FilterCard sameNameFilter = new FilterCard("card(s) with the name: \"" + cardNameToRipple + "\" to cast without paying their mana cost"); - sameNameFilter.add(new NamePredicate(cardNameToRipple)); + FilterCard sameNameFilter = new FilterCard("card(s) to cast without paying their mana cost"); + sameNameFilter.add(new SharesNamePredicate(sourceObject)); TargetCard target1 = new TargetCard(Zone.LIBRARY, sameNameFilter); target1.setRequired(false); diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/SharesNamePredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/SharesNamePredicate.java new file mode 100644 index 000000000000..7272a5f5e483 --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/SharesNamePredicate.java @@ -0,0 +1,22 @@ +package mage.filter.predicate.mageobject; + +import mage.MageObject; +import mage.filter.predicate.Predicate; +import mage.game.Game; + +/** + * @author TheElk801 + */ +public class SharesNamePredicate implements Predicate { + + private final MageObject mageObject; + + public SharesNamePredicate(MageObject mageObject) { + this.mageObject = mageObject; + } + + @Override + public boolean apply(MageObject input, Game game) { + return input.sharesName(mageObject, game); + } +} From b9b69586dc16e8da5569d628739a672d37ab15b3 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 26 Sep 2024 18:49:00 -0400 Subject: [PATCH 06/16] add some new cardutil stuff --- .../src/mage/cards/c/ChromeReplicator.java | 21 +-- .../src/mage/cards/s/SphinxOfTheChimes.java | 157 +++++------------- Mage/src/main/java/mage/util/CardUtil.java | 60 +++++++ 3 files changed, 110 insertions(+), 128 deletions(-) diff --git a/Mage.Sets/src/mage/cards/c/ChromeReplicator.java b/Mage.Sets/src/mage/cards/c/ChromeReplicator.java index 20cd72260107..70e11d2469d5 100644 --- a/Mage.Sets/src/mage/cards/c/ChromeReplicator.java +++ b/Mage.Sets/src/mage/cards/c/ChromeReplicator.java @@ -1,7 +1,6 @@ package mage.cards.c; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; @@ -19,9 +18,6 @@ import mage.game.permanent.token.Construct4Token; import mage.util.CardUtil; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; import java.util.UUID; /** @@ -66,16 +62,11 @@ enum ChromeReplicatorCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Map nameMap = new HashMap<>(); - return game - .getBattlefield() - .getActivePermanents( - filter, source.getControllerId(), source, game - ).stream() - .filter(Objects::nonNull) - .map(MageObject::getName) - .filter(Objects::nonNull) - .filter(s -> !s.isEmpty()) - .anyMatch(s -> nameMap.compute(s, CardUtil::setOrIncrementValue) >= 2); + return CardUtil + .checkAnyPairs( + game.getBattlefield().getActivePermanents( + filter, source.getControllerId(), source, game + ), (p1, p2) -> p1.sharesName(p2, game) + ); } } diff --git a/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java b/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java index b8fc0a5eb21f..3faa7800b31a 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java +++ b/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java @@ -6,22 +6,21 @@ import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.FlyingAbility; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterNonlandCard; -import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCardInHand; import mage.util.CardUtil; -import java.util.HashSet; -import java.util.Map; 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 @@ -39,9 +38,9 @@ public SphinxOfTheChimes(UUID ownerId, CardSetInfo setInfo) { this.addAbility(FlyingAbility.getInstance()); // Discard two nonland cards with the same name: Draw four cards. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(4), new DiscardTwoNonlandCardsWithTheSameNameCost()); - this.addAbility(ability); - + this.addAbility(new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(4), new DiscardTargetCost(new SphinxOfTheChimesTarget()) + )); } private SphinxOfTheChimes(final SphinxOfTheChimes card) { @@ -54,122 +53,54 @@ public SphinxOfTheChimes copy() { } } -class DiscardTwoNonlandCardsWithTheSameNameCost extends DiscardTargetCost { - - public DiscardTwoNonlandCardsWithTheSameNameCost() { - super(new TargetTwoNonLandCardsWithSameNameInHand()); - } - - private DiscardTwoNonlandCardsWithTheSameNameCost(final DiscardTwoNonlandCardsWithTheSameNameCost cost) { - super(cost); - } - - @Override - public DiscardTwoNonlandCardsWithTheSameNameCost copy() { - return new DiscardTwoNonlandCardsWithTheSameNameCost(this); - } - -} +class SphinxOfTheChimesTarget extends TargetCardInHand { -class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand { + private static final FilterCard filter = new FilterNonlandCard("nonland cards with the same name"); - public TargetTwoNonLandCardsWithSameNameInHand() { - super(2, 2, new FilterNonlandCard("nonland cards with the same name")); + public SphinxOfTheChimesTarget() { + super(2, 2, filter); } - private TargetTwoNonLandCardsWithSameNameInHand(final TargetTwoNonLandCardsWithSameNameInHand target) { + private SphinxOfTheChimesTarget(final SphinxOfTheChimesTarget target) { super(target); } @Override - public Set possibleTargets(UUID sourceControllerId, Game game) { - Set newPossibleTargets = new HashSet<>(); - Set possibleTargets = new HashSet<>(); - Player player = game.getPlayer(sourceControllerId); - if (player == null) { - return newPossibleTargets; - } - for (Card card : player.getHand().getCards(filter, game)) { - possibleTargets.add(card.getId()); - } - - Cards cardsToCheck = new CardsImpl(); - cardsToCheck.addAll(possibleTargets); - if (targets.size() == 1) { - // first target is laready chosen, now only targets with the same name are selectable - for (Map.Entry entry : targets.entrySet()) { - Card chosenCard = cardsToCheck.get(entry.getKey(), game); - if (chosenCard != null) { - for (UUID cardToCheck : cardsToCheck) { - if (!cardToCheck.equals(chosenCard.getId()) && chosenCard.getName().equals(game.getCard(cardToCheck).getName())) { - newPossibleTargets.add(cardToCheck); - } - } - } - } - } else { - for (UUID cardToCheck : cardsToCheck) { - Card card = game.getCard(cardToCheck); - if (card != null) { - String nameToSearch = CardUtil.getCardNameForSameNameSearch(card); - FilterCard nameFilter = new FilterCard(); - nameFilter.add(new NamePredicate(nameToSearch)); - - if (cardsToCheck.count(nameFilter, game) > 1) { - newPossibleTargets.add(cardToCheck); - } - } - } - } - return newPossibleTargets; - } - - @Override - public boolean canChoose(UUID sourceControllerId, Game game) { - Cards cardsToCheck = new CardsImpl(); - Player player = game.getPlayer(sourceControllerId); - if (player == null) { - return false; - } - for (Card card : player.getHand().getCards(filter, game)) { - cardsToCheck.add(card.getId()); - } - int possibleCards = 0; - for (Card card : cardsToCheck.getCards(game)) { - String nameToSearch = CardUtil.getCardNameForSameNameSearch(card); - FilterCard nameFilter = new FilterCard(); - nameFilter.add(new NamePredicate(nameToSearch)); - - if (cardsToCheck.count(nameFilter, game) > 1) { - ++possibleCards; - } - } - return possibleCards > 0; - } - - @Override - public boolean canTarget(UUID id, Game game) { - if (super.canTarget(id, game)) { - Card card = game.getCard(id); - if (card != null) { - if (targets.size() == 1) { - Card card2 = game.getCard(targets.entrySet().iterator().next().getKey()); - return CardUtil.haveSameNames(card2, card); - } else { - String nameToSearch = CardUtil.getCardNameForSameNameSearch(card); - FilterCard nameFilter = new FilterCard(); - nameFilter.add(new NamePredicate(nameToSearch)); - - Player player = game.getPlayer(card.getOwnerId()); - return player != null && player.getHand().getCards(nameFilter, game).size() > 1; + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); + switch (this.getTargets().size()) { + case 0: + if (possibleTargets.size() < 2) { + possibleTargets.clear(); + break; } - } + Set set = CardUtil + .streamPairsWithMap( + possibleTargets, + (u1, u2) -> game.getCard(u1).sharesName(game.getCard(u2), game) + ? Stream.of(u1, u2) + : Stream.empty() + ) + .flatMap(Function.identity()) + .collect(Collectors.toSet()); + possibleTargets.clear(); + possibleTargets.addAll(set); + break; + case 1: + possibleTargets.removeIf( + uuid -> !game + .getCard(uuid) + .sharesName(game.getCard(this.getTargets().get(0)), game) + ); + break; + default: + possibleTargets.clear(); } - return false; + return possibleTargets; } @Override - public TargetTwoNonLandCardsWithSameNameInHand copy() { - return new TargetTwoNonLandCardsWithSameNameInHand(this); + public SphinxOfTheChimesTarget copy() { + return new SphinxOfTheChimesTarget(this); } } diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index de2499820490..829ef95a1ec9 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -56,6 +56,8 @@ import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.*; +import java.util.function.BiFunction; +import java.util.function.BiPredicate; import java.util.function.ToIntFunction; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -2167,6 +2169,64 @@ public static Stream castStream(Stream stream, Class clazz) { return stream.filter(clazz::isInstance).map(clazz::cast).filter(Objects::nonNull); } + private static class IntPairIterator implements Iterator> { + private final int amount; + private int firstCounter = 0; + private int secondCounter = 1; + + IntPairIterator(int amount) { + this.amount = amount; + } + + @Override + public boolean hasNext() { + return firstCounter + 1 < amount; + } + + @Override + public AbstractMap.SimpleImmutableEntry next() { + AbstractMap.SimpleImmutableEntry value + = new AbstractMap.SimpleImmutableEntry(firstCounter, secondCounter); + secondCounter++; + if (secondCounter == amount) { + firstCounter++; + secondCounter = firstCounter + 1; + } + return value; + } + + public int getMax() { + // amount choose 2 + return (amount * amount - amount) / 2; + } + } + + public static boolean checkAnyPairs(Collection collection, BiPredicate predicate) { + return streamPairsWithMap(collection, (t1, t2) -> predicate.test(t1, t2)).anyMatch(x -> x); + } + + public static Stream streamPairsWithMap( + Collection collection, + BiFunction function) { + if (collection.size() < 2) { + return Stream.empty(); + } + List list; + if (collection instanceof List) { + list = (List) collection; + } else { + list = new ArrayList<>(collection); + } + IntPairIterator it = new IntPairIterator(list.size()); + return Stream + .generate(it::next) + .limit(it.getMax()) + .map(pair -> function.apply( + list.get(pair.getKey()), + list.get(pair.getValue()) + )); + } + public static void AssertNoControllerOwnerPredicates(Target target) { List list = new ArrayList<>(); Predicates.collectAllComponents(target.getFilter().getPredicates(), target.getFilter().getExtraPredicates(), list); From a519d687dac01e28e897caccd39f4d8c00d2e567 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 26 Sep 2024 18:49:24 -0400 Subject: [PATCH 07/16] more refactoring --- .../src/mage/cards/c/CephalidShrine.java | 129 ++++++----------- .../src/mage/cards/d/DeputyOfDetention.java | 50 +++---- Mage.Sets/src/mage/cards/d/DwarvenShrine.java | 92 ++++-------- .../src/mage/cards/h/HarnessTheStorm.java | 91 +++++------- .../src/mage/cards/l/LegionsToAshes.java | 38 ++--- .../src/mage/cards/m/MaskOfTheMimic.java | 26 ++-- Mage.Sets/src/mage/cards/m/Mimeofacture.java | 13 +- .../mage/cards/m/MishraArtificerProdigy.java | 132 ++++++------------ .../src/mage/cards/m/MitoticManipulation.java | 99 ++++--------- .../src/mage/cards/m/MoratoriumStone.java | 48 +++++-- Mage.Sets/src/mage/cards/n/NantukoShrine.java | 52 ++++--- Mage.Sets/src/mage/cards/p/PackHunt.java | 22 +-- Mage.Sets/src/mage/cards/r/Remembrance.java | 74 ++++------ Mage.Sets/src/mage/cards/s/SecretSalvage.java | 8 +- .../src/mage/cards/s/SeverTheBloodline.java | 37 ++--- Mage.Sets/src/mage/cards/s/StrataScythe.java | 86 ++++++------ .../src/mage/cards/t/TheApprenticesFolly.java | 25 ++-- .../src/mage/cards/v/VerdantSuccession.java | 120 +++++----------- Mage.Sets/src/mage/cards/w/Winnow.java | 31 ++-- 19 files changed, 450 insertions(+), 723 deletions(-) diff --git a/Mage.Sets/src/mage/cards/c/CephalidShrine.java b/Mage.Sets/src/mage/cards/c/CephalidShrine.java index 7c096da98e6e..3d6ad446ae1b 100644 --- a/Mage.Sets/src/mage/cards/c/CephalidShrine.java +++ b/Mage.Sets/src/mage/cards/c/CephalidShrine.java @@ -1,37 +1,37 @@ package mage.cards.c; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SpellCastAllTriggeredAbility; import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.constants.SetTargetPointer; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; import mage.players.Player; -import mage.util.ManaUtil; +import java.util.Collection; +import java.util.Objects; import java.util.UUID; /** - * @author jeffwadsworth + * @author TheElk801 */ public final class CephalidShrine extends CardImpl { public CephalidShrine(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}{U}"); - // Whenever a player casts a spell, counter that spell unless that player - // pays {X}, where X is the number of cards in all graveyards with the same name as the spell. - this.addAbility(new CephalidShrineTriggeredAbility()); + // Whenever a player casts a spell, counter that spell unless that player pays {X}, where X is the number of cards in all graveyards with the same name as the spell. + this.addAbility(new SpellCastAllTriggeredAbility( + new CephalidShrineEffect(), StaticFilters.FILTER_SPELL_A, + false, SetTargetPointer.PLAYER + )); } private CephalidShrine(final CephalidShrine card) { @@ -44,48 +44,12 @@ public CephalidShrine copy() { } } -class CephalidShrineTriggeredAbility extends TriggeredAbilityImpl { - - public CephalidShrineTriggeredAbility() { - super(Zone.BATTLEFIELD, new CephalidShrineEffect(), false); - } - - private CephalidShrineTriggeredAbility(final CephalidShrineTriggeredAbility ability) { - super(ability); - } - - @Override - public CephalidShrineTriggeredAbility copy() { - return new CephalidShrineTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - MageObject mageObject = game.getObject(sourceId); - if (spell != null - && mageObject != null) { - game.getState().setValue("cephalidShrine" + mageObject, spell); - return true; - } - return false; - } - -} - class CephalidShrineEffect extends OneShotEffect { CephalidShrineEffect() { - super(Outcome.Detriment); - staticText = "Whenever a player casts a spell, counter that " - + "spell unless that player pays {X}, where X is the " - + "number of cards in all graveyards with the same name " - + "as the spell"; + super(Outcome.Benefit); + staticText = "counter that spell unless that player pays {X}, " + + "where X is the number of cards in all graveyards with the same name as the spell"; } private CephalidShrineEffect(final CephalidShrineEffect effect) { @@ -93,46 +57,33 @@ private CephalidShrineEffect(final CephalidShrineEffect effect) { } @Override - public boolean apply(Game game, Ability source) { - int count = 0; - MageObject mageObject = game.getObject(source); - if (mageObject != null) { - Spell spell = (Spell) game.getState().getValue("cephalidShrine" + mageObject); - if (spell != null) { - Player controller = game.getPlayer(spell.getControllerId()); - if (controller != null) { - String name = spell.getName(); - FilterCard filterCardName = new FilterCard(); - filterCardName.add(new NamePredicate(name)); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - count += player.getGraveyard().count(filterCardName, game); - } - } - // even if the cost is 0, we still offer - Cost cost = ManaUtil.createManaCost(count, true); - if (game.getStack().contains(spell) - && cost.canPay(source, source, controller.getId(), game) - && controller.chooseUse(outcome, "Pay " + cost.getText() - + " to prevent countering " + spell.getName() + "?", source, game) - && cost.pay(source, game, source, controller.getId(), false) - && cost.isPaid()) { - return false; - } else { - game.getStack().counter(spell.getId(), source, game); - game.informPlayers(spell.getName() + " has been countered due to " - + controller.getName() + " not paying " + cost.getText()); - return true; - } - } - } - } - return false; + public CephalidShrineEffect copy() { + return new CephalidShrineEffect(this); } @Override - public CephalidShrineEffect copy() { - return new CephalidShrineEffect(this); + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + Spell spell = (Spell) getValue("spellCast"); + if (player == null || spell == null) { + return false; + } + int amount = game + .getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getGraveyard) + .map(g -> g.getCards(game)) + .flatMap(Collection::stream) + .filter(card -> card.sharesName(spell, game)) + .mapToInt(x -> 1) + .sum(); + Cost cost = new GenericManaCost(amount); + return (cost.canPay(source, source, player.getId(), game) + && player.chooseUse(outcome, "Pay {" + amount + "}?", source, game) + && cost.pay(source, game, source, player.getId(), false)) + || game.getStack().counter(spell.getId(), source, game); } } diff --git a/Mage.Sets/src/mage/cards/d/DeputyOfDetention.java b/Mage.Sets/src/mage/cards/d/DeputyOfDetention.java index f64494d42a54..14ce2df4819d 100644 --- a/Mage.Sets/src/mage/cards/d/DeputyOfDetention.java +++ b/Mage.Sets/src/mage/cards/d/DeputyOfDetention.java @@ -3,40 +3,30 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.common.delayed.OnLeaveReturnExiledAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; 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.constants.TargetController; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterNonlandPermanent; -import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; -import mage.util.CardUtil; +import mage.target.targetpointer.FixedTargets; -import java.util.LinkedHashSet; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author TheElk801 */ public final class DeputyOfDetention extends CardImpl { - private static final FilterPermanent filter = new FilterNonlandPermanent("nonland permanent an opponent controls"); - - static { - filter.add(TargetController.OPPONENT.getControllerPredicate()); - } - public DeputyOfDetention(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); @@ -47,7 +37,7 @@ public DeputyOfDetention(UUID ownerId, CardSetInfo setInfo) { // When Deputy of Detention enters the battlefield, exile target nonland permanent an opponent controls and all other nonland permanents that player controls with the same name as that permanent until Deputy of Detention leaves the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new DeputyOfDetentionExileEffect(), false); - ability.addTarget(new TargetPermanent(filter)); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_NON_LAND)); this.addAbility(ability); } @@ -78,31 +68,25 @@ private DeputyOfDetentionExileEffect(final DeputyOfDetentionExileEffect effect) public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = source.getSourcePermanentIfItStillExists(game); - Permanent targeted = game.getPermanent(source.getFirstTarget()); - + Permanent targeted = game.getPermanent(getTargetPointer().getFirst(game, source)); if (permanent == null || controller == null || targeted == null) { return false; } - - FilterPermanent filter = new FilterNonlandPermanent(); - filter.add(new ControllerIdPredicate(targeted.getControllerId())); - filter.add(new NamePredicate(targeted.getName())); - - Set toExile = new LinkedHashSet<>(); - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, controller.getId(), game)) { - toExile.add(creature); - } - - if (!toExile.isEmpty()) { - controller.moveCardsToExile(toExile, source, game, true, CardUtil.getCardExileZoneId(game, source), permanent.getIdName()); - game.addDelayedTriggeredAbility(new OnLeaveReturnExiledAbility(), source); - } - return true; + Set set = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND, + targeted.getControllerId(), source, game + ) + .stream() + .filter(p -> p.sharesName(targeted, game)) + .collect(Collectors.toSet()); + set.add(targeted); + return new ExileUntilSourceLeavesEffect().setTargetPointer(new FixedTargets(set, game)).apply(game, source); } @Override public DeputyOfDetentionExileEffect copy() { return new DeputyOfDetentionExileEffect(this); } - } diff --git a/Mage.Sets/src/mage/cards/d/DwarvenShrine.java b/Mage.Sets/src/mage/cards/d/DwarvenShrine.java index 50900243e683..fd7bfe62f53e 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenShrine.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenShrine.java @@ -1,35 +1,34 @@ package mage.cards.d; -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SpellCastAllTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.constants.SetTargetPointer; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; import mage.players.Player; +import java.util.Collection; +import java.util.Objects; import java.util.UUID; /** - * @author jeffwadsworth + * @author TheElk801 */ public final class DwarvenShrine extends CardImpl { public DwarvenShrine(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{R}"); - // Whenever a player casts a spell, Dwarven Shrine deals X damage to that player, where X is twice the number of cards in all graveyards with the same name as that spell. - this.addAbility(new DwarvenShrineTriggeredAbility()); + this.addAbility(new SpellCastAllTriggeredAbility( + new DwarvenShrineEffect(), StaticFilters.FILTER_SPELL_A, false, SetTargetPointer.PLAYER + )); } private DwarvenShrine(final DwarvenShrine card) { @@ -42,43 +41,12 @@ public DwarvenShrine copy() { } } -class DwarvenShrineTriggeredAbility extends TriggeredAbilityImpl { - - public DwarvenShrineTriggeredAbility() { - super(Zone.BATTLEFIELD, new DwarvenShrineEffect(), false); - } - - private DwarvenShrineTriggeredAbility(final DwarvenShrineTriggeredAbility ability) { - super(ability); - } - - @Override - public DwarvenShrineTriggeredAbility copy() { - return new DwarvenShrineTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - MageObject mageObject = game.getObject(sourceId); - if (spell != null && mageObject != null) { - game.getState().setValue("dwarvenShrine" + mageObject, spell); - return true; - } - return false; - } -} - class DwarvenShrineEffect extends OneShotEffect { DwarvenShrineEffect() { super(Outcome.Detriment); - staticText = "Whenever a player casts a spell, {this} deals X damage to that player, where X is twice the number of cards in all graveyards with the same name as that spell."; + staticText = "{this} deals X damage to that player, where X is twice " + + "the number of cards in all graveyards with the same name as that spell."; } private DwarvenShrineEffect(final DwarvenShrineEffect effect) { @@ -87,28 +55,24 @@ private DwarvenShrineEffect(final DwarvenShrineEffect effect) { @Override public boolean apply(Game game, Ability source) { - int count = 0; - MageObject mageObject = game.getObject(source); - if (mageObject != null) { - Spell spell = (Spell) game.getState().getValue("dwarvenShrine" + mageObject); - if (spell != null) { - Player controller = game.getPlayer(spell.getControllerId()); - if (controller != null) { - String name = spell.getName(); - FilterCard filterCardName = new FilterCard(); - filterCardName.add(new NamePredicate(name)); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - count += player.getGraveyard().count(filterCardName, game); - } - } - controller.damage(count * 2, mageObject.getId(), source, game); - return true; - } - } + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + Spell spell = (Spell) getValue("spellCast"); + if (player == null || spell == null) { + return false; } - return false; + int count = game + .getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getGraveyard) + .map(g -> g.getCards(game)) + .flatMap(Collection::stream) + .filter(c -> c.sharesName(spell, game)) + .mapToInt(x -> 1) + .sum(); + return count > 0 && player.damage(2 * count, source, game) > 0; } @Override diff --git a/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java b/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java index 2f5fe12510c4..2a0be75a6570 100644 --- a/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java +++ b/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java @@ -1,6 +1,5 @@ package mage.cards.h; -import mage.ApprovingObject; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -9,30 +8,42 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.common.FilterInstantOrSorcerySpell; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.StaticFilters; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; -import mage.watchers.common.CastFromHandWatcher; +import mage.util.CardUtil; import java.util.UUID; /** - * * @author LevelX2 */ public final class HarnessTheStorm extends CardImpl { + private static final FilterCard filter = new FilterCard("card with the same name as that spell from your graveyard"); + + static { + filter.add(HarnessTheStormPredicate.instance); + } + public HarnessTheStorm(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); - // Whenever you cast an instant or sorcery spell from your hand, you may cast - // target card with the same name as that spell from your graveyard. - this.addAbility(new HarnessTheStormTriggeredAbility(), new CastFromHandWatcher()); + // Whenever you cast an instant or sorcery spell from your hand, you may cast target card with the same name as that spell from your graveyard. + Ability ability = new SpellCastControllerTriggeredAbility( + Zone.BATTLEFIELD, new HarnessTheStormEffect(), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, + false, SetTargetPointer.NONE, Zone.HAND + ); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); } private HarnessTheStorm(final HarnessTheStorm card) { @@ -46,41 +57,21 @@ public HarnessTheStorm copy() { } -class HarnessTheStormTriggeredAbility extends SpellCastControllerTriggeredAbility { - - private static final FilterInstantOrSorcerySpell filterSpell = new FilterInstantOrSorcerySpell("an instant or sorcery spell from your hand"); - - HarnessTheStormTriggeredAbility() { - super(new HarnessTheStormEffect(), filterSpell, false); - } - - private HarnessTheStormTriggeredAbility(final HarnessTheStormTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (super.checkTrigger(event, game)) { - CastFromHandWatcher watcher = game.getState().getWatcher(CastFromHandWatcher.class); - if (watcher != null && watcher.spellWasCastFromHand(event.getSourceId())) { - Spell spell = game.getState().getStack().getSpell(event.getSourceId()); - if (spell != null) { - FilterCard filterCard = new FilterCard("a card named " + spell.getName() + " in your graveyard"); - filterCard.add(new NamePredicate(spell.getName())); - this.getTargets().clear(); - this.getTargets().add(new TargetCardInYourGraveyard(filterCard)); - return true; - } - } - } - return false; - } +enum HarnessTheStormPredicate implements ObjectSourcePlayerPredicate { + instance; @Override - public HarnessTheStormTriggeredAbility copy() { - return new HarnessTheStormTriggeredAbility(this); + public boolean apply(ObjectSourcePlayer input, Game game) { + return input + .getSource() + .getEffects() + .stream() + .map(effect -> effect.getValue("spellCast")) + .map(Spell.class::cast) + .findFirst() + .map(spell -> spell.sharesName(input.getObject(), game)) + .orElse(false); } - } class HarnessTheStormEffect extends OneShotEffect { @@ -103,20 +94,8 @@ public HarnessTheStormEffect copy() { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - Card card = controller.getGraveyard().get(getTargetPointer().getFirst(game, source), game); - if (card == null) { - return false; - } - if (controller.chooseUse(outcome, "Cast " + card.getIdName() + " from your graveyard?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(card, game, false), - game, false, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - return true; - + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + return controller != null && card != null + && CardUtil.castSpellWithAttributesForFree(controller, source, game, card); } } diff --git a/Mage.Sets/src/mage/cards/l/LegionsToAshes.java b/Mage.Sets/src/mage/cards/l/LegionsToAshes.java index eb7be9f735cf..56413c3a14e5 100644 --- a/Mage.Sets/src/mage/cards/l/LegionsToAshes.java +++ b/Mage.Sets/src/mage/cards/l/LegionsToAshes.java @@ -1,27 +1,24 @@ package mage.cards.l; -import java.util.HashSet; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetNonlandPermanent; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + /** - * * @author weirddan455 */ public final class LegionsToAshes extends CardImpl { @@ -48,7 +45,8 @@ class LegionsToAshesEffect extends OneShotEffect { LegionsToAshesEffect() { super(Outcome.Exile); - this.staticText = "Exile target nonland permanent an opponent controls and all tokens that player controls with the same name as that permanent."; + this.staticText = "Exile target nonland permanent an opponent controls " + + "and all tokens that player controls with the same name as that permanent."; } private LegionsToAshesEffect(final LegionsToAshesEffect effect) { @@ -63,17 +61,21 @@ public LegionsToAshesEffect copy() { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent targetPermanent = game.getPermanent(source.getFirstTarget()); + Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (controller == null || targetPermanent == null) { return false; } - FilterPermanent filter = new FilterPermanent(); - filter.add(TokenPredicate.TRUE); - filter.add(new ControllerIdPredicate(targetPermanent.getControllerId())); - filter.add(new NamePredicate(targetPermanent.getName())); - HashSet toExile = new HashSet<>(game.getBattlefield().getActivePermanents(filter, controller.getId(), source, game)); - toExile.add(targetPermanent); - controller.moveCards(toExile, Zone.EXILED, source, game); - return true; + Set set = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_PERMANENT_TOKEN, + source.getControllerId(), source, game + ) + .stream() + .filter(permanent -> permanent.sharesName(targetPermanent, game) + && permanent.isControlledBy(targetPermanent.getControllerId())) + .collect(Collectors.toSet()); + set.add(targetPermanent); + return controller.moveCards(set, Zone.EXILED, source, game); } } diff --git a/Mage.Sets/src/mage/cards/m/MaskOfTheMimic.java b/Mage.Sets/src/mage/cards/m/MaskOfTheMimic.java index 438b6efae01b..f982aaa33769 100644 --- a/Mage.Sets/src/mage/cards/m/MaskOfTheMimic.java +++ b/Mage.Sets/src/mage/cards/m/MaskOfTheMimic.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.effects.OneShotEffect; @@ -12,27 +10,19 @@ import mage.constants.Outcome; import mage.filter.FilterCard; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.TokenPredicate; +import mage.filter.predicate.mageobject.SharesNamePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInLibrary; -import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class MaskOfTheMimic extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); - - static { - filter.add(TokenPredicate.FALSE); - } - public MaskOfTheMimic(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); @@ -41,7 +31,7 @@ public MaskOfTheMimic(UUID ownerId, CardSetInfo setInfo) { // Search your library for a card with the same name as target nontoken creature and put that card onto the battlefield. Then shuffle your library. this.getSpellAbility().addEffect(new MaskOfTheMimicEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_CREATURE_NON_TOKEN)); } private MaskOfTheMimic(final MaskOfTheMimic card) { @@ -58,7 +48,7 @@ class MaskOfTheMimicEffect extends OneShotEffect { MaskOfTheMimicEffect() { super(Outcome.Benefit); - this.staticText = "Search your library for a card with the same name as target nontoken creature," + this.staticText = "search your library for a card with the same name as target nontoken creature," + " put that card onto the battlefield, then shuffle."; } @@ -73,12 +63,12 @@ public MaskOfTheMimicEffect copy() { @Override public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(source.getFirstTarget()); + Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); if (creature == null) { return false; } - FilterCard filter = new FilterCard("a card named " + creature.getName()); - filter.add(new NamePredicate(creature.getName())); + FilterCard filter = new FilterCard("a card with the same name"); + filter.add(new SharesNamePredicate(creature)); return new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter)).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/m/Mimeofacture.java b/Mage.Sets/src/mage/cards/m/Mimeofacture.java index 64323528df47..a70a34d609b1 100644 --- a/Mage.Sets/src/mage/cards/m/Mimeofacture.java +++ b/Mage.Sets/src/mage/cards/m/Mimeofacture.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.ReplicateAbility; @@ -13,15 +11,16 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.StaticFilters; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.mageobject.SharesNamePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class Mimeofacture extends CardImpl { @@ -68,7 +67,7 @@ public MimeofactureEffect copy() { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent permanent = game.getPermanent(source.getFirstTarget()); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (controller == null || permanent == null) { return false; } @@ -76,8 +75,8 @@ public boolean apply(Game game, Ability source) { if (opponent == null) { return false; } - FilterCard filter = new FilterCard("card named " + permanent.getName()); - filter.add(new NamePredicate(permanent.getName())); + FilterCard filter = new FilterCard("card with the same name"); + filter.add(new SharesNamePredicate(permanent)); TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); if (controller.searchLibrary(target, source, game, opponent.getId())) { Card card = opponent.getLibrary().getCard(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/cards/m/MishraArtificerProdigy.java b/Mage.Sets/src/mage/cards/m/MishraArtificerProdigy.java index 0632a31c0ea0..e798d91ee6b1 100644 --- a/Mage.Sets/src/mage/cards/m/MishraArtificerProdigy.java +++ b/Mage.Sets/src/mage/cards/m/MishraArtificerProdigy.java @@ -1,37 +1,32 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.SharesNamePredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author emerald000 */ public final class MishraArtificerProdigy extends CardImpl { public MishraArtificerProdigy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}{R}"); this.supertype.add(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ARTIFICER); @@ -39,7 +34,9 @@ public MishraArtificerProdigy(UUID ownerId, CardSetInfo setInfo) { this.toughness = new MageInt(4); // Whenever you cast an artifact spell, you may search your graveyard, hand, and/or library for a card with the same name as that spell and put it onto the battlefield. If you search your library this way, shuffle it. - this.addAbility(new MishraArtificerProdigyTriggeredAbility()); + this.addAbility(new SpellCastControllerTriggeredAbility( + new MishraArtificerProdigyEffect(), StaticFilters.FILTER_SPELL_AN_ARTIFACT, true + )); } private MishraArtificerProdigy(final MishraArtificerProdigy card) { @@ -52,56 +49,16 @@ public MishraArtificerProdigy copy() { } } -class MishraArtificerProdigyTriggeredAbility extends TriggeredAbilityImpl { - - MishraArtificerProdigyTriggeredAbility() { - super(Zone.BATTLEFIELD, new MishraArtificerProdigyEffect(), true); - } - - private MishraArtificerProdigyTriggeredAbility(final MishraArtificerProdigyTriggeredAbility ability) { - super(ability); - } - - @Override - public MishraArtificerProdigyTriggeredAbility copy() { - return new MishraArtificerProdigyTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.SPELL_CAST; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (event.getPlayerId().equals(this.getControllerId())) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && spell.isArtifact(game)) { - ((MishraArtificerProdigyEffect) this.getEffects().get(0)).setName(spell.getName()); - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "Whenever you cast an artifact spell, you may search your graveyard, hand, and/or library for a card with the same name as that spell and put it onto the battlefield. If you search your library this way, shuffle."; - } -} - class MishraArtificerProdigyEffect extends OneShotEffect { - private String cardName; - MishraArtificerProdigyEffect() { super(Outcome.PutCardInPlay); - this.staticText = "Search your graveyard, hand, and/or library for a card named " + cardName + " and put it onto the battlefield. If you search your library this way, shuffle."; + this.staticText = "search your graveyard, hand, and/or library for a card with the same name as " + + "that spell and put it onto the battlefield. If you search your library this way, shuffle"; } private MishraArtificerProdigyEffect(final MishraArtificerProdigyEffect effect) { super(effect); - this.cardName = effect.cardName; } @Override @@ -112,43 +69,40 @@ public MishraArtificerProdigyEffect copy() { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - FilterCard filter = new FilterCard("card named " + this.cardName); - filter.add(new NamePredicate(cardName)); - Card card = null; - // Graveyard - if (controller.chooseUse(Outcome.Neutral, "Search your graveyard?", source, game)) { - // You can't fail to find the card in your graveyard because it's not hidden - TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(1, 1, filter); - if (controller.choose(Outcome.PutCardInPlay, controller.getGraveyard(), target, source, game)) { - card = game.getCard(target.getFirstTarget()); - } - } - // Hand - if (card == null && controller.chooseUse(Outcome.Neutral, "Search your hand?", source, game)) { - TargetCardInHand target = new TargetCardInHand(0, 1, filter); - if (controller.choose(Outcome.PutCardInPlay, controller.getHand(), target, source, game)) { - card = game.getCard(target.getFirstTarget()); - } + Spell spell = (Spell) getValue("spellCast"); + if (controller == null || spell == null) { + return false; + } + FilterCard filter = new FilterCard("card with the same name"); + filter.add(new SharesNamePredicate(spell)); + Card card = null; + // Graveyard + if (controller.chooseUse(Outcome.Neutral, "Search your graveyard?", source, game)) { + // You can't fail to find the card in your graveyard because it's not hidden + TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(1, 1, filter); + if (controller.choose(Outcome.PutCardInPlay, controller.getGraveyard(), target, source, game)) { + card = game.getCard(target.getFirstTarget()); } - // Library - if (card == null && controller.chooseUse(Outcome.Neutral, "Search your library?", source, game)) { - TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); - if (controller.searchLibrary(target, source, game)) { - card = game.getCard(target.getFirstTarget()); - } - controller.shuffleLibrary(source, game); + } + // Hand + if (card == null && controller.chooseUse(Outcome.Neutral, "Search your hand?", source, game)) { + TargetCardInHand target = new TargetCardInHand(0, 1, filter); + if (controller.choose(Outcome.PutCardInPlay, controller.getHand(), target, source, game)) { + card = game.getCard(target.getFirstTarget()); } - // Put on battlefield - if (card != null) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } + // Library + if (card == null && controller.chooseUse(Outcome.Neutral, "Search your library?", source, game)) { + TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); + if (controller.searchLibrary(target, source, game)) { + card = game.getCard(target.getFirstTarget()); } - return true; + controller.shuffleLibrary(source, game); } - return false; - } - - public void setName(String cardName) { - this.cardName = cardName; + // Put on battlefield + if (card != null) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/m/MitoticManipulation.java b/Mage.Sets/src/mage/cards/m/MitoticManipulation.java index 703f83cac6ec..6cb1097e04bc 100644 --- a/Mage.Sets/src/mage/cards/m/MitoticManipulation.java +++ b/Mage.Sets/src/mage/cards/m/MitoticManipulation.java @@ -1,36 +1,38 @@ package mage.cards.m; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; -import mage.MageObject; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.PutCards; import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.StaticFilters; +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.TargetCard; + +import java.util.UUID; /** - * * @author North */ public final class MitoticManipulation extends CardImpl { + private static final FilterCard filter = new FilterCard("a card with the same name as a permanent"); + + static { + filter.add(MitoticManipulationPredicate.instance); + } + public MitoticManipulation(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}{U}"); - this.getSpellAbility().addEffect(new MitoticManipulationEffect()); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + 7, 1, filter, PutCards.BATTLEFIELD, PutCards.BOTTOM_ANY + ).setText("look at the top seven cards of your library. You may put one of those cards onto the battlefield " + + "if it has the same name as a permanent. Put the rest on the bottom of your library in any order")); } private MitoticManipulation(final MitoticManipulation card) { @@ -43,57 +45,18 @@ public MitoticManipulation copy() { } } -class MitoticManipulationEffect extends OneShotEffect { - - MitoticManipulationEffect() { - super(Outcome.PutCardInPlay); - this.staticText = "Look at the top seven cards of your library. You may put one of those cards onto the battlefield if it has the same name as a permanent. Put the rest on the bottom of your library in any order"; - } - - private MitoticManipulationEffect(final MitoticManipulationEffect effect) { - super(effect); - } +enum MitoticManipulationPredicate implements ObjectSourcePlayerPredicate { + instance; @Override - public MitoticManipulationEffect copy() { - return new MitoticManipulationEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - Set permanentNames = new HashSet<>(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - permanentNames.add(permanent.getName()); - } - - Cards cardsFromTop = new CardsImpl(); - cardsFromTop.addAllCards(controller.getLibrary().getTopCards(game, 7)); - controller.lookAtCards(sourceObject.getIdName(), cardsFromTop, game); - FilterCard filter = new FilterCard("card to put onto the battlefield"); - List namePredicates = new ArrayList<>(); - for (String name : permanentNames) { - namePredicates.add(new NamePredicate(name)); - } - if (!namePredicates.isEmpty() && !cardsFromTop.isEmpty()) { - filter.add(Predicates.or(namePredicates)); - TargetCard target = new TargetCard(Zone.LIBRARY, filter); - if (cardsFromTop.count(filter, source.getControllerId(), source, game) > 0 - && controller.chooseUse(Outcome.PutCardInPlay, "Put a card on the battlefield?", source, game)) { - if (controller.choose(Outcome.PutCardInPlay, cardsFromTop, target, source, game)) { - Card card = cardsFromTop.get(target.getFirstTarget(), game); - if (card != null) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - cardsFromTop.remove(card); - } - } - } - } - controller.putCardsOnBottomOfLibrary(cardsFromTop, game, source, true); - return true; - } - return false; + public boolean apply(ObjectSourcePlayer input, Game game) { + return game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_PERMANENT, + input.getPlayerId(), input.getSource(), game + ) + .stream() + .anyMatch(permanent -> permanent.sharesName(input.getObject(), game)); } } diff --git a/Mage.Sets/src/mage/cards/m/MoratoriumStone.java b/Mage.Sets/src/mage/cards/m/MoratoriumStone.java index 30e6cc743081..4c6b5fc336cd 100644 --- a/Mage.Sets/src/mage/cards/m/MoratoriumStone.java +++ b/Mage.Sets/src/mage/cards/m/MoratoriumStone.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -9,23 +7,27 @@ import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ExileAllEffect; -import mage.abilities.effects.common.ExileGraveyardAllPlayersEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; +import mage.players.Player; import mage.target.common.TargetCardInGraveyard; +import java.util.Collection; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + /** - * * @author TheElk801 */ public final class MoratoriumStone extends CardImpl { @@ -81,15 +83,31 @@ public MoratoriumStoneEffect copy() { @Override public boolean apply(Game game, Ability source) { - Card card = game.getCard(source.getFirstTarget()); - if (card == null) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (player == null || card == null) { return false; } - String cardName = card.getName(); - FilterCard filter1 = new FilterCard(); - filter1.add(new NamePredicate(cardName)); - FilterPermanent filter2 = new FilterPermanent(); - filter2.add(new NamePredicate(cardName)); - return new ExileGraveyardAllPlayersEffect(filter1).apply(game, source) && new ExileAllEffect(filter2).apply(game, source); + Set cards = game + .getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getGraveyard) + .map(g -> g.getCards(game)) + .flatMap(Collection::stream) + .filter(c -> c.sharesName(card, game)) + .collect(Collectors.toSet()); + cards.add(card); + game.getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_PERMANENT, + source.getControllerId(), source, game + ) + .stream() + .filter(permanent -> permanent.sharesName(card, game)) + .forEach(cards::add); + return player.moveCards(card, Zone.EXILED, source, game); } } diff --git a/Mage.Sets/src/mage/cards/n/NantukoShrine.java b/Mage.Sets/src/mage/cards/n/NantukoShrine.java index dd2a51c3329d..0dfdb44cdd03 100644 --- a/Mage.Sets/src/mage/cards/n/NantukoShrine.java +++ b/Mage.Sets/src/mage/cards/n/NantukoShrine.java @@ -1,7 +1,5 @@ - package mage.cards.n; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SpellCastAllTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -10,17 +8,18 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SetTargetPointer; -import mage.filter.FilterCard; import mage.filter.StaticFilters; -import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; import mage.game.permanent.token.SquirrelToken; import mage.game.stack.Spell; import mage.players.Player; +import java.util.Collection; +import java.util.Objects; +import java.util.UUID; + /** - * - * @author LevelX2 + * @author TheElk801 */ public final class NantukoShrine extends CardImpl { @@ -28,7 +27,9 @@ public NantukoShrine(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}{G}"); // Whenever a player casts a spell, that player puts X 1/1 green Squirrel creature tokens onto the battlefield, where X is the number of cards in all graveyards with the same name as that spell. - this.addAbility(new SpellCastAllTriggeredAbility(new NantukoShrineEffect(), StaticFilters.FILTER_SPELL, false, SetTargetPointer.SPELL)); + this.addAbility(new SpellCastAllTriggeredAbility( + new NantukoShrineEffect(), StaticFilters.FILTER_SPELL, false, SetTargetPointer.PLAYER + )); } private NantukoShrine(final NantukoShrine card) { @@ -59,26 +60,23 @@ public NantukoShrineEffect copy() { @Override public boolean apply(Game game, Ability source) { - Spell spell = game.getStack().getSpell(getTargetPointer().getFirst(game, source)); - if (spell != null) { - Player controller = game.getPlayer(spell.getControllerId()); - if (controller != null) { - int count = 0; - String name = spell.getName(); - FilterCard filterCardName = new FilterCard(); - filterCardName.add(new NamePredicate(name)); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - count += player.getGraveyard().count(filterCardName, game); - } - } - if (count > 0) { - new SquirrelToken().putOntoBattlefield(count, game, source, spell.getControllerId()); - } - return true; - } + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + Spell spell = (Spell) getValue("spellCast"); + if (player == null || spell == null) { + return false; } - return false; + int count = game + .getState() + .getPlayersInRange(source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .map(Player::getGraveyard) + .map(g -> g.getCards(game)) + .flatMap(Collection::stream) + .filter(c -> c.sharesName(spell, game)) + .mapToInt(x -> 1) + .sum(); + return count > 0 && new SquirrelToken().putOntoBattlefield(count, game, source, player.getId()); } } diff --git a/Mage.Sets/src/mage/cards/p/PackHunt.java b/Mage.Sets/src/mage/cards/p/PackHunt.java index f4622fc58ee6..af169c5d66c9 100644 --- a/Mage.Sets/src/mage/cards/p/PackHunt.java +++ b/Mage.Sets/src/mage/cards/p/PackHunt.java @@ -1,4 +1,3 @@ - package mage.cards.p; import mage.abilities.Ability; @@ -9,8 +8,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.FilterCard; -import mage.filter.common.FilterPermanentCard; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.mageobject.SharesNamePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInLibrary; @@ -19,7 +17,6 @@ import java.util.UUID; /** - * * @author ciaccona007 */ public final class PackHunt extends CardImpl { @@ -41,11 +38,13 @@ public PackHunt copy() { return new PackHunt(this); } } + class PackHuntEffect extends OneShotEffect { PackHuntEffect() { super(Outcome.Benefit); - this.staticText = "Search your library for up to three cards with the same name as target creature, reveal them, and put them into your hand. Then shuffle"; + this.staticText = "search your library for up to three cards with the same name as " + + "target creature, reveal them, and put them into your hand. Then shuffle"; } private PackHuntEffect(final PackHuntEffect effect) { @@ -59,9 +58,14 @@ public PackHuntEffect copy() { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - FilterCard filter = new FilterPermanentCard(); - filter.add(new NamePredicate(permanent.getName())); - return new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0,3, filter), true).apply(game, source); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent == null) { + return false; + } + FilterCard filter = new FilterCard(); + filter.add(new SharesNamePredicate(permanent)); + return new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(0, 3, filter), true + ).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/r/Remembrance.java b/Mage.Sets/src/mage/cards/r/Remembrance.java index 347bf2c4b583..b2db20db7093 100644 --- a/Mage.Sets/src/mage/cards/r/Remembrance.java +++ b/Mage.Sets/src/mage/cards/r/Remembrance.java @@ -1,21 +1,19 @@ - package mage.cards.r; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; +import mage.constants.Outcome; import mage.filter.FilterCard; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.TokenPredicate; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.SharesNamePredicate; import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.common.TargetCardInLibrary; import java.util.UUID; @@ -29,7 +27,9 @@ public Remembrance(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); // Whenever a nontoken creature you control dies, you may search your library for a card with the same name as that creature, reveal it, and put it into your hand. If you do, shuffle your library. - this.addAbility(new RemembranceTriggeredAbility()); + this.addAbility(new DiesCreatureTriggeredAbility( + new RemembranceEffect(), true, StaticFilters.FILTER_CONTROLLED_CREATURE_NON_TOKEN + )); } private Remembrance(final Remembrance card) { @@ -42,54 +42,32 @@ public Remembrance copy() { } } -class RemembranceTriggeredAbility extends TriggeredAbilityImpl { - - private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); - - static { - filter.add(TokenPredicate.FALSE); - } +class RemembranceEffect extends OneShotEffect { - RemembranceTriggeredAbility() { - super(Zone.BATTLEFIELD, null, true); + RemembranceEffect() { + super(Outcome.Benefit); + staticText = "search your library for a card with the same name as that creature, " + + "reveal it, and put it into your hand. If you do, shuffle your library"; } - private RemembranceTriggeredAbility(final RemembranceTriggeredAbility ability) { - super(ability); + private RemembranceEffect(final RemembranceEffect effect) { + super(effect); } @Override - public RemembranceTriggeredAbility copy() { - return new RemembranceTriggeredAbility(this); + public RemembranceEffect copy() { + return new RemembranceEffect(this); } @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (!((ZoneChangeEvent) event).isDiesEvent()) { + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = (Permanent) getValue("creatureDied"); + if (player == null || permanent == null) { return false; } - Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); - if (permanent != null && filter.match(permanent, game)) { - FilterCard filterCard = new FilterCard("card named " + permanent.getName()); - filterCard.add(new NamePredicate(permanent.getName())); - this.getEffects().clear(); - this.addEffect(new SearchLibraryPutInHandEffect( - new TargetCardInLibrary(filterCard), true - )); - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever a nontoken creature you control dies, " + - "you may search your library for a card with the same name as that creature, " + - "reveal it, put it into your hand, then shuffle."; + FilterCard filter = new FilterCard("card with the same name"); + filter.add(new SharesNamePredicate(permanent)); + return new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/s/SecretSalvage.java b/Mage.Sets/src/mage/cards/s/SecretSalvage.java index cdd25f0677a3..c300cf8991a0 100644 --- a/Mage.Sets/src/mage/cards/s/SecretSalvage.java +++ b/Mage.Sets/src/mage/cards/s/SecretSalvage.java @@ -11,12 +11,11 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterNonlandCard; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.mageobject.SharesNamePredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInYourGraveyard; -import mage.util.CardUtil; import java.util.UUID; @@ -72,9 +71,8 @@ public boolean apply(Game game, Ability source) { return false; } controller.moveCards(targetCard, Zone.EXILED, source, game); - String nameToSearch = CardUtil.getCardNameForSameNameSearch(targetCard); - FilterCard nameFilter = new FilterCard("card named " + nameToSearch); - nameFilter.add(new NamePredicate(nameToSearch)); + FilterCard nameFilter = new FilterCard("card with the same name"); + nameFilter.add(new SharesNamePredicate(targetCard)); return new SearchLibraryPutInHandEffect(new TargetCardInLibrary( 0, Integer.MAX_VALUE, nameFilter ), true).apply(game, source); diff --git a/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java b/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java index 1bdb1a4c288e..0273c14f3e2d 100644 --- a/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java +++ b/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java @@ -4,21 +4,21 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlashbackAbility; +import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; -import mage.util.CardUtil; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author North @@ -28,10 +28,10 @@ public final class SeverTheBloodline extends CardImpl { public SeverTheBloodline(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); - // Exile target creature and all other creatures with the same name as that creature. this.getSpellAbility().addEffect(new SeverTheBloodlineEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + // Flashback {5}{B}{B} this.addAbility(new FlashbackAbility(this, new ManaCostsImpl<>("{5}{B}{B}"))); } @@ -64,20 +64,21 @@ public SeverTheBloodlineEffect copy() { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(source.getControllerId()); Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (controller != null && targetPermanent != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (CardUtil.haveEmptyName(targetPermanent)) { - filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected - } else { - filter.add(new NamePredicate(targetPermanent.getName())); - } - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game)) { - controller.moveCardToExileWithInfo(permanent, null, "", source, game, Zone.BATTLEFIELD, true); - } - return true; + if (player == null || targetPermanent == null) { + return false; } - return false; + Set set = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, + source.getControllerId(), source, game + ) + .stream() + .filter(permanent -> permanent.sharesName(targetPermanent, game)) + .collect(Collectors.toSet()); + set.add(targetPermanent); + return player.moveCards(set, Zone.EXILED, source, game); } } diff --git a/Mage.Sets/src/mage/cards/s/StrataScythe.java b/Mage.Sets/src/mage/cards/s/StrataScythe.java index 6dd075e6d015..d753a38cd19b 100644 --- a/Mage.Sets/src/mage/cards/s/StrataScythe.java +++ b/Mage.Sets/src/mage/cards/s/StrataScythe.java @@ -1,11 +1,8 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -14,17 +11,21 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterLandCard; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.constants.AbilityWord; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.ExileZone; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.Set; +import java.util.UUID; /** - * * @author Loki */ public final class StrataScythe extends CardImpl { @@ -37,10 +38,12 @@ public StrataScythe(UUID ownerId, CardSetInfo setInfo) { this.addAbility(new EntersBattlefieldTriggeredAbility(new StrataScytheImprintEffect()).setAbilityWord(AbilityWord.IMPRINT)); // Equipped creature gets +1/+1 for each land on the battlefield with the same name as the exiled card. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(SameNameAsExiledCountValue.getInstance(), SameNameAsExiledCountValue.getInstance()))); + this.addAbility(new SimpleStaticAbility(new BoostEquippedEffect( + StrataScytheValue.instance, StrataScytheValue.instance + ))); // Equip {3} - this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(3), false)); + this.addAbility(new EquipAbility(3, false)); } private StrataScythe(final StrataScythe card) { @@ -71,19 +74,15 @@ public boolean apply(Game game, Ability source) { if (player == null) { return false; } - TargetCardInLibrary target = new TargetCardInLibrary(new FilterLandCard()); - if (player.searchLibrary(target, source, game)) { - if (!target.getTargets().isEmpty()) { - UUID cardId = target.getTargets().get(0); - Card card = player.getLibrary().remove(cardId, game); - if (card != null) { - card.moveToExile(source.getSourceId(), "Strata Scythe", source, game); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - permanent.imprint(card.getId(), game); - } - } - } + TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_LAND_A); + player.searchLibrary(target, source, game); + Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null) { + player.moveCardsToExile( + card, source, game, true, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); } player.shuffleLibrary(source, game); return true; @@ -96,31 +95,32 @@ public StrataScytheImprintEffect copy() { } -class SameNameAsExiledCountValue implements DynamicValue { - - private static final SameNameAsExiledCountValue instance = new SameNameAsExiledCountValue(); - - public static SameNameAsExiledCountValue getInstance() { - return instance; - } - - private SameNameAsExiledCountValue() { - } +enum StrataScytheValue implements DynamicValue { + instance; @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - int value = 0; - Permanent permanent = game.getPermanent(sourceAbility.getSourceId()); - if (permanent != null && !permanent.getImprinted().isEmpty()) { - FilterPermanent filterPermanent = new FilterPermanent(); - filterPermanent.add(new NamePredicate(game.getCard(permanent.getImprinted().get(0)).getName())); - value = game.getBattlefield().count(filterPermanent, sourceAbility.getControllerId(), sourceAbility, game); + public int calculate(Game game, Ability source, Effect effect) { + ExileZone exileZone = game + .getExile() + .getExileZone(CardUtil.getExileZoneId( + game, source.getSourceId(), + game.getState().getZoneChangeCounter(source.getSourceId()) + )); + if (exileZone == null || exileZone.isEmpty()) { + return 0; } - return value; + Set cards = exileZone.getCards(game); + return game + .getBattlefield() + .getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source, game) + .stream() + .filter(permanent -> cards.stream().anyMatch(card -> card.sharesName(permanent, game))) + .mapToInt(x -> 1) + .sum(); } @Override - public DynamicValue copy() { + public StrataScytheValue copy() { return instance; } diff --git a/Mage.Sets/src/mage/cards/t/TheApprenticesFolly.java b/Mage.Sets/src/mage/cards/t/TheApprenticesFolly.java index d5c884bddb4e..0c7239c54358 100644 --- a/Mage.Sets/src/mage/cards/t/TheApprenticesFolly.java +++ b/Mage.Sets/src/mage/cards/t/TheApprenticesFolly.java @@ -9,14 +9,14 @@ import mage.constants.SagaChapter; import mage.constants.SubType; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; import mage.target.common.TargetControlledCreaturePermanent; import java.util.UUID; @@ -77,15 +77,14 @@ enum TheApprenticesFollyPredicate implements ObjectSourcePlayerPredicate input, Game game) { - String name = input.getObject().getName(); - if (name == null || name.isEmpty()) { - return true; - } - - FilterControlledPermanent filter = new FilterControlledPermanent(); - filter.add(new NamePredicate(name)); - filter.add(TokenPredicate.TRUE); - // This works due to the non-token clause on the target. There should be no controlled token with that name. - return game.getBattlefield().count(filter, input.getPlayerId(), input.getSource(), game) == 0; + return game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT, + input.getPlayerId(), input.getSource(), game + ) + .stream() + .filter(PermanentToken.class::isInstance) + .noneMatch(permanent -> permanent.sharesName(input.getObject(), game)); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/v/VerdantSuccession.java b/Mage.Sets/src/mage/cards/v/VerdantSuccession.java index b435f3b8a62d..cbccf48b3eb1 100644 --- a/Mage.Sets/src/mage/cards/v/VerdantSuccession.java +++ b/Mage.Sets/src/mage/cards/v/VerdantSuccession.java @@ -1,12 +1,8 @@ - package mage.cards.v; -import java.util.*; - -import mage.MageObject; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; @@ -15,106 +11,57 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; -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.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * - * @author jeffwadsworth, jimga150 + * @author TheElk801 */ public final class VerdantSuccession extends CardImpl { - public VerdantSuccession(UUID ownerId, CardSetInfo setInfo) { - super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}"); - - // Whenever a green nontoken creature dies, that creature's controller may search their library for a card - // with the same name as that creature and put it onto the battlefield. If that player does, they shuffle their library. - this.addAbility(new VerdantSuccessionTriggeredAbility()); - - } - - private VerdantSuccession(final VerdantSuccession card) { - super(card); - } - - @Override - public VerdantSuccession copy() { - return new VerdantSuccession(this); - } -} - -class VerdantSuccessionTriggeredAbility extends TriggeredAbilityImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("green nontoken creature"); + private static final FilterPermanent filter = new FilterCreaturePermanent("a green nontoken creature"); static { filter.add(new ColorPredicate(ObjectColor.GREEN)); filter.add(TokenPredicate.FALSE); } - VerdantSuccessionTriggeredAbility() { - super(Zone.BATTLEFIELD, null, true); - } - - private VerdantSuccessionTriggeredAbility(final VerdantSuccessionTriggeredAbility ability) { - super(ability); - } - - @Override - public VerdantSuccessionTriggeredAbility copy() { - return new VerdantSuccessionTriggeredAbility(this); - } + public VerdantSuccession(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}"); - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; + // Whenever a green nontoken creature dies, that creature's controller may search their library for a card with the same name as that creature and put it onto the battlefield. If that player does, they shuffle their library. + this.addAbility(new DiesCreatureTriggeredAbility(new VerdantSuccessionEffect(), false, filter)); } - @Override - public boolean checkTrigger(GameEvent event, Game game) { - ZoneChangeEvent zoneChangeEvent = (ZoneChangeEvent) event; - if (zoneChangeEvent.isDiesEvent()) { - Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - MageObject mageObject = game.getObject(sourceId); - if (permanent != null && mageObject != null - && filter.match(permanent, game)) { - this.getEffects().clear(); - this.addEffect(new VerdantSuccessionEffect(permanent.getName(), permanent.getControllerId())); - return true; - } - } - return false; + private VerdantSuccession(final VerdantSuccession card) { + super(card); } @Override - public String getRule() { - return "Whenever a green nontoken creature dies, that creature's controller may search their library for a card with the same name as that creature, put it onto the battlefield, then shuffle."; + public VerdantSuccession copy() { + return new VerdantSuccession(this); } } class VerdantSuccessionEffect extends OneShotEffect { - private final String creatureName; - private final UUID controllerId; - - VerdantSuccessionEffect(String creatureName, UUID controllerId) { - super(Outcome.PutCardInPlay); - this.creatureName = creatureName; - this.controllerId = controllerId; + VerdantSuccessionEffect() { + super(Outcome.Benefit); + staticText = "that creature's controller may search their library for a card " + + "with the same name as that creature, put it onto the battlefield, then shuffle."; } private VerdantSuccessionEffect(final VerdantSuccessionEffect effect) { super(effect); - this.creatureName = effect.creatureName; - this.controllerId = effect.controllerId; } @Override @@ -124,26 +71,25 @@ public VerdantSuccessionEffect copy() { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(controllerId); - if (controller == null) { - return false; - } - MageObject mageObject = game.getObject(source); - if (mageObject == null) { + Permanent permanent = (Permanent) getValue("creatureDied"); + if (permanent == null) { return false; } - FilterCard filterCard = new FilterCard("Card named " + creatureName); - filterCard.add(new NamePredicate(creatureName)); - TargetCardInLibrary target = new TargetCardInLibrary(filterCard); - controller.searchLibrary(target, source, game); - if (target.getTargets().isEmpty()) { + Player player = game.getPlayer(permanent.getControllerId()); + if (player == null || !player.chooseUse( + Outcome.PutCreatureInPlay, "Search for a card with the same name?", source, game + )) { return false; } - Card card = game.getCard(target.getFirstTarget()); - if (card != null - && controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { - controller.shuffleLibrary(source, game); + FilterCard filter = new FilterCard("card with the same name"); + filter.add(new SharesNamePredicate(permanent)); + TargetCardInLibrary target = new TargetCardInLibrary(filter); + player.searchLibrary(target, source, game); + Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null) { + player.moveCards(card, Zone.BATTLEFIELD, source, game); } + player.shuffleLibrary(source, game); return true; } } diff --git a/Mage.Sets/src/mage/cards/w/Winnow.java b/Mage.Sets/src/mage/cards/w/Winnow.java index da5c469da6dc..2353f3a43dde 100644 --- a/Mage.Sets/src/mage/cards/w/Winnow.java +++ b/Mage.Sets/src/mage/cards/w/Winnow.java @@ -1,32 +1,30 @@ - package mage.cards.w; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetNonlandPermanent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class Winnow extends CardImpl { public Winnow(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Destroy target nonland permanent if another permanent with the same name is on the battlefield. this.getSpellAbility().addEffect(new WinnowEffect()); this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } @@ -59,15 +57,16 @@ public WinnowEffect copy() { @Override public boolean apply(Game game, Ability source) { - Permanent target = game.getPermanent(source.getFirstTarget()); - if(target != null) { - FilterPermanent filter = new FilterPermanent(); - filter.add(new NamePredicate(target.getName())); - if(new PermanentsOnBattlefieldCount(filter).calculate(game, source, this) > 1) { - super.apply(game, source); - } - return true; + Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (target == null) { + return false; } - return false; + return game + .getBattlefield() + .getActivePermanents(StaticFilters.FILTER_PERMANENT, source.getControllerId(), source, game) + .stream() + .filter(p -> p.sharesName(target, game)) + .anyMatch(p -> !p.getId().equals(target.getId())) + && target.destroy(source, game); } } From 3307eb31a56351fe8f9e9f7e847c7d56542f7e3a Mon Sep 17 00:00:00 2001 From: theelk801 Date: Fri, 27 Sep 2024 16:27:12 -0400 Subject: [PATCH 08/16] refactor cards that search for multiple matching names --- .../src/mage/cards/c/ClarionUltimatum.java | 82 +++-------------- Mage.Sets/src/mage/cards/d/Dichotomancy.java | 46 ++++++---- Mage.Sets/src/mage/cards/d/DoublingChant.java | 87 ++++--------------- .../TargetCardWithSameNameAsPermanents.java | 76 ++++++++++++++++ 4 files changed, 135 insertions(+), 156 deletions(-) create mode 100644 Mage/src/main/java/mage/target/common/TargetCardWithSameNameAsPermanents.java diff --git a/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java b/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java index 8519f8cbd6a0..136ae91f1758 100644 --- a/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java +++ b/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java @@ -1,25 +1,23 @@ package mage.cards.c; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.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.game.Game; import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardWithSameNameAsPermanents; import mage.target.common.TargetControlledPermanent; -import mage.util.CardUtil; -import java.util.*; -import java.util.stream.Collectors; +import java.util.UUID; /** * @author North @@ -74,68 +72,14 @@ public boolean apply(Game game, Ability source) { TargetPermanent targetPermanent = new TargetControlledPermanent(Math.max(permCount, 5)); targetPermanent.withNotTarget(true); player.choose(outcome, targetPermanent, source, game); - Set names = targetPermanent - .getTargets() - .stream() - .map(game::getCard) - .filter(Objects::nonNull) - .map(MageObject::getName) - .collect(Collectors.toSet()); - TargetCardInLibrary targetCardInLibrary = new ClarionUltimatumTarget(names); - player.searchLibrary(targetCardInLibrary, source, game); - Cards cards = new CardsImpl(targetCardInLibrary.getTargets()); - player.moveCards(cards.getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); + TargetCardInLibrary target = new TargetCardWithSameNameAsPermanents(targetPermanent.getTargets()); + player.searchLibrary(target, source, game); + Cards cards = new CardsImpl(target.getTargets()); + player.moveCards( + cards.getCards(game), Zone.BATTLEFIELD, source, game, + true, false, false, null + ); player.shuffleLibrary(source, game); return true; } } - -class ClarionUltimatumTarget extends TargetCardInLibrary { - - private final Map nameMap = new HashMap<>(); - - ClarionUltimatumTarget(Set names) { - super(0, names.size(), makeFilter(names)); - this.populateNameMap(names); - } - - private ClarionUltimatumTarget(final ClarionUltimatumTarget target) { - super(target); - this.nameMap.putAll(target.nameMap); - } - - @Override - public ClarionUltimatumTarget copy() { - return new ClarionUltimatumTarget(this); - } - - private static FilterCard makeFilter(Set names) { - FilterCard filter = new FilterCard(); - filter.add(Predicates.or(names.stream().map(name -> new NamePredicate(name)).collect(Collectors.toSet()))); - return filter; - } - - private void populateNameMap(Set names) { - names.stream().forEach(name -> this.nameMap.compute(name, CardUtil::setOrIncrementValue)); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { - if (!super.canTarget(playerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - if (card == null) { - return false; - } - Map alreadyChosen = new HashMap<>(); - this.getTargets() - .stream() - .map(game::getCard) - .filter(Objects::nonNull) - .map(MageObject::getName) - .forEach(name -> alreadyChosen.compute(name, CardUtil::setOrIncrementValue)); - return nameMap.getOrDefault(card.getName(), 0) - > alreadyChosen.getOrDefault(card.getName(), 0); - } -} diff --git a/Mage.Sets/src/mage/cards/d/Dichotomancy.java b/Mage.Sets/src/mage/cards/d/Dichotomancy.java index 4f492ff0b173..831bd9ffe838 100644 --- a/Mage.Sets/src/mage/cards/d/Dichotomancy.java +++ b/Mage.Sets/src/mage/cards/d/Dichotomancy.java @@ -1,25 +1,29 @@ package mage.cards.d; +import mage.MageItem; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.SuspendAbility; 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.TargetController; import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.common.FilterNonlandPermanent; -import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardWithSameNameAsPermanents; import mage.target.common.TargetOpponent; +import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; /** * @author noahg @@ -29,7 +33,6 @@ public final class Dichotomancy extends CardImpl { public Dichotomancy(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{7}{U}{U}"); - // For each tapped nonland permanent target opponent controls, search that player’s library for a card with the same name as that permanent and put it onto the battlefield under your control. Then that player shuffles their library. this.getSpellAbility().addEffect(new DichotomancyEffect()); this.getSpellAbility().addTarget(new TargetOpponent()); @@ -53,6 +56,7 @@ class DichotomancyEffect extends OneShotEffect { private static final FilterNonlandPermanent filter = new FilterNonlandPermanent(); static { + filter.add(TargetController.YOU.getControllerPredicate()); filter.add(TappedPredicate.TAPPED); } @@ -69,26 +73,30 @@ private DichotomancyEffect(DichotomancyEffect effect) { @Override public boolean apply(Game game, Ability source) { - Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && opponent != null) { - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, opponent.getId(), game)) { - String name = permanent.getName(); - FilterCard filterCard = new FilterCard("card named \"" + name + '"'); - filterCard.add(new NamePredicate(name)); - TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filterCard); - if (controller.searchLibrary(target, source, game, opponent.getId())) { - controller.moveCards(opponent.getLibrary().getCard(target.getFirstTarget(), game), Zone.BATTLEFIELD, source, game); - } - } - opponent.shuffleLibrary(source, game); - return true; + Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || opponent == null) { + return false; } - return false; + Set set = game + .getBattlefield() + .getActivePermanents(filter, opponent.getId(), source, game) + .stream() + .map(MageItem::getId) + .collect(Collectors.toSet()); + TargetCardInLibrary target = new TargetCardWithSameNameAsPermanents(set); + controller.searchLibrary(target, source, game, opponent.getId()); + Cards cards = new CardsImpl(); + for (UUID targetId : target.getTargets()) { + cards.add(opponent.getLibrary().getCard(targetId, game)); + } + controller.moveCards(cards, Zone.BATTLEFIELD, source, game); + opponent.shuffleLibrary(source, game); + return true; } @Override public DichotomancyEffect copy() { return new DichotomancyEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/d/DoublingChant.java b/Mage.Sets/src/mage/cards/d/DoublingChant.java index d5c1da4dac16..74bd4132e8aa 100644 --- a/Mage.Sets/src/mage/cards/d/DoublingChant.java +++ b/Mage.Sets/src/mage/cards/d/DoublingChant.java @@ -1,23 +1,23 @@ package mage.cards.d; -import mage.MageObject; +import mage.MageItem; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.StaticFilters; -import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; -import mage.util.CardUtil; +import mage.target.common.TargetCardWithSameNameAsPermanents; -import java.util.*; +import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; /** @@ -67,69 +67,20 @@ public boolean apply(Game game, Ability source) { if (player == null) { return false; } - Set names = game.getBattlefield().getActivePermanents( - StaticFilters.FILTER_CONTROLLED_CREATURE, - source.getControllerId(), source, game - ) + Set set = game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getControllerId(), source, game + ) .stream() - .filter(Objects::nonNull) - .map(MageObject::getName) + .map(MageItem::getId) .collect(Collectors.toSet()); - TargetCardInLibrary targetCardInLibrary = new DoublingChantTarget(names); - player.searchLibrary(targetCardInLibrary, source, game); - Cards cards = new CardsImpl(targetCardInLibrary.getTargets()); - player.moveCards(cards, Zone.BATTLEFIELD, source, game); + TargetCardInLibrary target = new TargetCardWithSameNameAsPermanents(set); + player.searchLibrary(target, source, game); + Cards cards = new CardsImpl(target.getTargets()); + player.moveCards(cards.getCards(game), Zone.BATTLEFIELD, source, game); player.shuffleLibrary(source, game); return true; } } - -class DoublingChantTarget extends TargetCardInLibrary { - - private final Map nameMap = new HashMap<>(); - - DoublingChantTarget(Set names) { - super(0, names.size(), makeFilter(names)); - this.populateNameMap(names); - } - - private DoublingChantTarget(final DoublingChantTarget target) { - super(target); - this.nameMap.putAll(target.nameMap); - } - - @Override - public DoublingChantTarget copy() { - return new DoublingChantTarget(this); - } - - private static FilterCard makeFilter(Set names) { - FilterCard filter = new FilterCreatureCard(); - filter.add(Predicates.or(names.stream().map(name -> new NamePredicate(name)).collect(Collectors.toSet()))); - return filter; - } - - private void populateNameMap(Set names) { - names.stream().forEach(name -> this.nameMap.compute(name, CardUtil::setOrIncrementValue)); - } - - @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { - if (!super.canTarget(playerId, id, source, game)) { - return false; - } - Card card = game.getCard(id); - if (card == null) { - return false; - } - Map alreadyChosen = new HashMap<>(); - this.getTargets() - .stream() - .map(game::getCard) - .filter(Objects::nonNull) - .map(MageObject::getName) - .forEach(name -> alreadyChosen.compute(name, CardUtil::setOrIncrementValue)); - return nameMap.getOrDefault(card.getName(), 0) - > alreadyChosen.getOrDefault(card.getName(), 0); - } -} diff --git a/Mage/src/main/java/mage/target/common/TargetCardWithSameNameAsPermanents.java b/Mage/src/main/java/mage/target/common/TargetCardWithSameNameAsPermanents.java new file mode 100644 index 000000000000..411b60794dc7 --- /dev/null +++ b/Mage/src/main/java/mage/target/common/TargetCardWithSameNameAsPermanents.java @@ -0,0 +1,76 @@ +package mage.target.common; + +import mage.MageItem; +import mage.abilities.Ability; +import mage.abilities.assignment.RoleAssignment; +import mage.cards.Card; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.filter.FilterCard; +import mage.game.Game; + +import java.util.Collection; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author TheElk801 + */ +public class TargetCardWithSameNameAsPermanents extends TargetCardInLibrary { + + private static final class SameNameAsPermanentAssignment extends RoleAssignment { + + public SameNameAsPermanentAssignment(UUID... uuids) { + super(uuids); + } + + @Override + protected Set makeSet(Card card, Game game) { + return attributes + .stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .filter(permanent -> permanent.sharesName(card, game)) + .map(MageItem::getId) + .collect(Collectors.toSet()); + } + } + + private final SameNameAsPermanentAssignment assigner; + private static final FilterCard defaultFilter = new FilterCard("cards with the same name"); + + public TargetCardWithSameNameAsPermanents(Collection uuids) { + this(uuids, defaultFilter); + } + + public TargetCardWithSameNameAsPermanents(Collection uuids, FilterCard filter) { + super(0, uuids.size(), filter); + this.assigner = new SameNameAsPermanentAssignment(uuids.toArray(new UUID[]{})); + } + + private TargetCardWithSameNameAsPermanents(final TargetCardWithSameNameAsPermanents target) { + super(target); + this.assigner = target.assigner; + } + + @Override + public TargetCardWithSameNameAsPermanents copy() { + return new TargetCardWithSameNameAsPermanents(this); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { + return false; + } + Card card = game.getCard(id); + if (card == null) { + return false; + } + Cards cards = new CardsImpl(this.getTargets()); + cards.add(card); + return assigner.getRoleCount(cards, game) >= cards.size(); + } +} From d69bc200d46896b426da1e206aefa4c1b8e50773 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Sat, 28 Sep 2024 15:20:07 -0400 Subject: [PATCH 09/16] more refactoring --- Mage.Sets/src/mage/cards/d/DualNature.java | 12 +- Mage.Sets/src/mage/cards/e/EndlessAtlas.java | 33 +++-- .../src/mage/cards/e/EscapedShapeshifter.java | 8 +- .../src/mage/cards/e/ExtraplanarLens.java | 15 +- .../src/mage/cards/e/EyeOfSingularity.java | 136 ++++++------------ .../src/mage/cards/f/FrostpyreArcanist.java | 4 +- .../src/mage/cards/g/GoblinArtisans.java | 2 +- Mage.Sets/src/mage/cards/g/Godsend.java | 6 +- .../mage/cards/g/GollumObsessedStalker.java | 85 ++++------- .../src/mage/cards/h/HintOfInsanity.java | 31 ++-- Mage.Sets/src/mage/cards/h/HourOfGlory.java | 44 +++--- .../src/mage/cards/j/JourneyForTheElixir.java | 11 +- .../mage/cards/k/KotoseTheSilentSpider.java | 4 +- Mage.Sets/src/mage/cards/l/LegionsEnd.java | 20 ++- .../src/mage/cards/l/LocketOfYesterdays.java | 50 ++++--- .../src/mage/cards/l/LutriTheSpellchaser.java | 17 +-- .../mage/cards/m/MechanizedProduction.java | 87 ++++++----- .../src/mage/cards/m/MedomaisProphecy.java | 2 +- .../src/mage/cards/m/MirrorMadPhantasm.java | 12 +- .../src/mage/cards/p/PatternMatcher.java | 70 +++------ Mage.Sets/src/mage/cards/r/ReapIntellect.java | 135 +++++++---------- .../mage/cards/s/SasayaOrochiAscendant.java | 26 ++-- .../src/mage/cards/s/SphinxOfTheChimes.java | 7 +- .../mage/cards/y/YidaroWanderingMonster.java | 2 +- Mage/src/main/java/mage/game/GameImpl.java | 4 +- Mage/src/main/java/mage/util/CardUtil.java | 22 ++- 26 files changed, 337 insertions(+), 508 deletions(-) diff --git a/Mage.Sets/src/mage/cards/d/DualNature.java b/Mage.Sets/src/mage/cards/d/DualNature.java index f4bebc486490..5a74d6767fd5 100644 --- a/Mage.Sets/src/mage/cards/d/DualNature.java +++ b/Mage.Sets/src/mage/cards/d/DualNature.java @@ -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.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 @@ public boolean apply(Game game, Ability source) { 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; } diff --git a/Mage.Sets/src/mage/cards/e/EndlessAtlas.java b/Mage.Sets/src/mage/cards/e/EndlessAtlas.java index 913fad076868..e11a38ba077f 100644 --- a/Mage.Sets/src/mage/cards/e/EndlessAtlas.java +++ b/Mage.Sets/src/mage/cards/e/EndlessAtlas.java @@ -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.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 EndlessAtlas(UUID ownerId, CardSetInfo setInfo) { Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new GenericManaCost(2), - new EndlessAtlasCondition() + EndlessAtlasCondition.instance ); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -47,21 +46,27 @@ public EndlessAtlas copy() { } } -class EndlessAtlasCondition implements Condition { +enum EndlessAtlasCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { - Map landMap = new HashMap<>(); - for (Permanent land : game.getBattlefield().getActivePermanents( + Set 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; diff --git a/Mage.Sets/src/mage/cards/e/EscapedShapeshifter.java b/Mage.Sets/src/mage/cards/e/EscapedShapeshifter.java index e8b277845564..02e92f52e140 100644 --- a/Mage.Sets/src/mage/cards/e/EscapedShapeshifter.java +++ b/Mage.Sets/src/mage/cards/e/EscapedShapeshifter.java @@ -65,16 +65,16 @@ public boolean apply(Game game, Ability source) { 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 @@ private static boolean checkAbility(Ability ability) { public EscapedShapeshifterEffect copy() { return new EscapedShapeshifterEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/e/ExtraplanarLens.java b/Mage.Sets/src/mage/cards/e/ExtraplanarLens.java index 57b52b8beeba..c12f80f17ab4 100644 --- a/Mage.Sets/src/mage/cards/e/ExtraplanarLens.java +++ b/Mage.Sets/src/mage/cards/e/ExtraplanarLens.java @@ -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.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.targetpointer.FixedTarget; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class ExtraplanarLens extends CardImpl { @@ -123,8 +118,8 @@ public boolean checkTrigger(GameEvent event, Game game) { 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()); diff --git a/Mage.Sets/src/mage/cards/e/EyeOfSingularity.java b/Mage.Sets/src/mage/cards/e/EyeOfSingularity.java index 57fa01e7785a..06aec1a059e3 100644 --- a/Mage.Sets/src/mage/cards/e/EyeOfSingularity.java +++ b/Mage.Sets/src/mage/cards/e/EyeOfSingularity.java @@ -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.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 EyeOfSingularity(UUID ownerId, CardSetInfo setInfo) { 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 @@ public EyeOfSingularityETBEffect copy() { @Override public boolean apply(Game game, Ability source) { - Map cardNames = new HashMap<>(); - Map toDestroy = new HashMap<>(); - - 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); - } - } - 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; - } + Set permanents = CardUtil.streamAllPairwiseMatches( + game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game), + (p1, p2) -> p1.sharesName(p2, game) + ).collect(Collectors.toSet()); - if (permanent != null && !permanent.isBasic(game)) { - getEffects().get(0).setTargetPointer(new FixedTarget(event.getTargetId())); - return true; + for (Permanent permanent : permanents) { + permanent.destroy(source, game, 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."; + return true; } } 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 can’t be regenerated"; } private EyeOfSingularityTriggeredEffect(final EyeOfSingularityTriggeredEffect effect) { @@ -157,28 +109,20 @@ private EyeOfSingularityTriggeredEffect(final EyeOfSingularityTriggeredEffect ef @Override public boolean apply(Game game, Ability source) { - Map 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 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; } diff --git a/Mage.Sets/src/mage/cards/f/FrostpyreArcanist.java b/Mage.Sets/src/mage/cards/f/FrostpyreArcanist.java index 0c40a3f676ab..569c8185fd8f 100644 --- a/Mage.Sets/src/mage/cards/f/FrostpyreArcanist.java +++ b/Mage.Sets/src/mage/cards/f/FrostpyreArcanist.java @@ -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 @@ public boolean apply(ObjectSourcePlayer input, Game game) { .getGraveyard() .getCards(game) .stream() - .map(MageObject::getName) - .anyMatch(input.getObject().getName()::equals); + .anyMatch(card -> card.sharesName(input.getObject(), game)); } } diff --git a/Mage.Sets/src/mage/cards/g/GoblinArtisans.java b/Mage.Sets/src/mage/cards/g/GoblinArtisans.java index e9f7d247e3aa..ebbfcfe6210d 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinArtisans.java +++ b/Mage.Sets/src/mage/cards/g/GoblinArtisans.java @@ -98,7 +98,7 @@ public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) if (permanent != null && !sourceRef.refersTo(permanent, game) && permanent.isCreature(game) - && "Goblin Artisans".equals(permanent.getName()) + && permanent.hasName("Goblin Artisans", game) && stackObject .getStackAbility() .getTargets() diff --git a/Mage.Sets/src/mage/cards/g/Godsend.java b/Mage.Sets/src/mage/cards/g/Godsend.java index a14a99938972..7e520d69d168 100644 --- a/Mage.Sets/src/mage/cards/g/Godsend.java +++ b/Mage.Sets/src/mage/cards/g/Godsend.java @@ -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.FixedTarget; import mage.util.CardUtil; +import java.util.*; + /** - * * @author LevelX2 */ public final class Godsend extends CardImpl { @@ -201,7 +201,7 @@ public boolean applies(GameEvent event, Ability source, Game game) { 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; } } diff --git a/Mage.Sets/src/mage/cards/g/GollumObsessedStalker.java b/Mage.Sets/src/mage/cards/g/GollumObsessedStalker.java index b6cdbf3809e3..ba33067057b4 100644 --- a/Mage.Sets/src/mage/cards/g/GollumObsessedStalker.java +++ b/Mage.Sets/src/mage/cards/g/GollumObsessedStalker.java @@ -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 GollumObsessedStalker(UUID ownerId, CardSetInfo setInfo) { 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 GollumObsessedStalker copy() { class GollumObsessedStalkerWatcher extends Watcher { - // For each creature name, the players damaged by them during combat. - private final Map> playersPerName = new HashMap<>(); + // Players damaged by creatures named Gollum, Obsessed Stalker during combat. + private final Set players = new HashSet<>(); public GollumObsessedStalkerWatcher() { super(WatcherScope.GAME); @@ -78,22 +73,14 @@ public void watch(GameEvent event, Game game) { 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 getPlayersDamagedByNamed(String name) { - return playersPerName.getOrDefault(name, new HashSet<>()); + public Set 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 @@ public GollumObsessedStalkerEffect copy() { 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 playersDamaged = damageWatcher.getPlayersDamagedByNamed(name); + Set playersDamaged = damageWatcher.getPlayersDamagedByNamed(); if (amount == 0 || playersDamaged.isEmpty()) { return true; @@ -135,12 +120,10 @@ public boolean apply(Game game, Ability source) { 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 namesOfPlayersDealtDamage = - watcher.getPlayersDamagedByNamed(name) - .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: [" + List 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 Gollum, Obsessed Stalker this game: [" + String.join(", ", namesOfPlayersDealtDamage) + "]"; } diff --git a/Mage.Sets/src/mage/cards/h/HintOfInsanity.java b/Mage.Sets/src/mage/cards/h/HintOfInsanity.java index 5d8af4de02fc..bfd0eccc3ca8 100644 --- a/Mage.Sets/src/mage/cards/h/HintOfInsanity.java +++ b/Mage.Sets/src/mage/cards/h/HintOfInsanity.java @@ -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.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 @@ public HintOfInsanityEffect copy() { @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 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 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(); } } diff --git a/Mage.Sets/src/mage/cards/h/HourOfGlory.java b/Mage.Sets/src/mage/cards/h/HourOfGlory.java index c74c9482dd1f..0f0162d68da5 100644 --- a/Mage.Sets/src/mage/cards/h/HourOfGlory.java +++ b/Mage.Sets/src/mage/cards/h/HourOfGlory.java @@ -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.UUID; /** - * * @author LevelX2 */ public final class HourOfGlory extends CardImpl { @@ -63,28 +60,27 @@ public HourOfGloryEffect copy() { @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 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 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; } } diff --git a/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java b/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java index e78ed4ef421c..3751f7d69105 100644 --- a/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java +++ b/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java @@ -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 @@ public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { .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 @@ public Set possibleTargets(UUID sourceControllerId, Ability source, Game g .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; } diff --git a/Mage.Sets/src/mage/cards/k/KotoseTheSilentSpider.java b/Mage.Sets/src/mage/cards/k/KotoseTheSilentSpider.java index b02bc89141e4..0e5b200b4da4 100644 --- a/Mage.Sets/src/mage/cards/k/KotoseTheSilentSpider.java +++ b/Mage.Sets/src/mage/cards/k/KotoseTheSilentSpider.java @@ -10,7 +10,7 @@ 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 @@ public boolean apply(Game game, Ability source) { 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); diff --git a/Mage.Sets/src/mage/cards/l/LegionsEnd.java b/Mage.Sets/src/mage/cards/l/LegionsEnd.java index 6041696698de..49bf3c978794 100644 --- a/Mage.Sets/src/mage/cards/l/LegionsEnd.java +++ b/Mage.Sets/src/mage/cards/l/LegionsEnd.java @@ -71,7 +71,7 @@ public LegionsEndEffect copy() { @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 @@ public boolean apply(Game game, Ability source) { 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); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/l/LocketOfYesterdays.java b/Mage.Sets/src/mage/cards/l/LocketOfYesterdays.java index 24662243bc5a..b5dacc835e95 100644 --- a/Mage.Sets/src/mage/cards/l/LocketOfYesterdays.java +++ b/Mage.Sets/src/mage/cards/l/LocketOfYesterdays.java @@ -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 LocketOfYesterdays(UUID ownerId, CardSetInfo setInfo) { 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 @@ private LocketOfYesterdaysCostReductionEffect(final LocketOfYesterdaysCostReduct @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); } - } diff --git a/Mage.Sets/src/mage/cards/l/LutriTheSpellchaser.java b/Mage.Sets/src/mage/cards/l/LutriTheSpellchaser.java index 818845b3be40..ee82afe44b80 100644 --- a/Mage.Sets/src/mage/cards/l/LutriTheSpellchaser.java +++ b/Mage.Sets/src/mage/cards/l/LutriTheSpellchaser.java @@ -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.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 @@ public String getRule() { @Override public boolean isLegal(Set deck, int minimumDeckSize) { - Map cardMap = new HashMap<>(); - deck.stream() + Set 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); } } diff --git a/Mage.Sets/src/mage/cards/m/MechanizedProduction.java b/Mage.Sets/src/mage/cards/m/MechanizedProduction.java index a0adaa6e8260..866bacda07ef 100644 --- a/Mage.Sets/src/mage/cards/m/MechanizedProduction.java +++ b/Mage.Sets/src/mage/cards/m/MechanizedProduction.java @@ -2,8 +2,12 @@ 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.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 MechanizedProduction(UUID ownerId, CardSetInfo setInfo) { 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 @@ public MechanizedProductionEffect copy() { @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 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 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 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; } diff --git a/Mage.Sets/src/mage/cards/m/MedomaisProphecy.java b/Mage.Sets/src/mage/cards/m/MedomaisProphecy.java index 1b68bfba3fa3..4575175b1273 100644 --- a/Mage.Sets/src/mage/cards/m/MedomaisProphecy.java +++ b/Mage.Sets/src/mage/cards/m/MedomaisProphecy.java @@ -108,7 +108,7 @@ public boolean checkTrigger(GameEvent event, Game game) { return false; } Spell spell = game.getStack().getSpell(event.getTargetId()); - return spell != null && spellName.equals(spell.getName()); + return spell != null && spell.hasName(spellName, game); } @Override diff --git a/Mage.Sets/src/mage/cards/m/MirrorMadPhantasm.java b/Mage.Sets/src/mage/cards/m/MirrorMadPhantasm.java index a70b07a6856a..6fc68e80e4d8 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorMadPhantasm.java +++ b/Mage.Sets/src/mage/cards/m/MirrorMadPhantasm.java @@ -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.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author BetaSteward */ public final class MirrorMadPhantasm extends CardImpl { @@ -74,7 +70,7 @@ public boolean apply(Game game, Ability source) { 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; } diff --git a/Mage.Sets/src/mage/cards/p/PatternMatcher.java b/Mage.Sets/src/mage/cards/p/PatternMatcher.java index f5ec6f0019b4..de788f71e54d 100644 --- a/Mage.Sets/src/mage/cards/p/PatternMatcher.java +++ b/Mage.Sets/src/mage/cards/p/PatternMatcher.java @@ -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 PatternMatcher(UUID ownerId, CardSetInfo setInfo) { 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 PatternMatcher copy() { } } -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); - } - - @Override - public RegularExpression copy() { - return new RegularExpression(this); - } +enum RegularExpression implements ObjectSourcePlayerPredicate { + instance; @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - List predicates = game + public boolean apply(ObjectSourcePlayer 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)); } } diff --git a/Mage.Sets/src/mage/cards/r/ReapIntellect.java b/Mage.Sets/src/mage/cards/r/ReapIntellect.java index 1e9f975dbfc4..24e10525b577 100644 --- a/Mage.Sets/src/mage/cards/r/ReapIntellect.java +++ b/Mage.Sets/src/mage/cards/r/ReapIntellect.java @@ -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 ReapIntellect(UUID ownerId, CardSetInfo setInfo) { // 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 ReapIntellect copy() { 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 @@ private ReapIntellectEffect(final ReapIntellectEffect effect) { @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 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 diff --git a/Mage.Sets/src/mage/cards/s/SasayaOrochiAscendant.java b/Mage.Sets/src/mage/cards/s/SasayaOrochiAscendant.java index fa0f4be0b4f6..612f6ce348f4 100644 --- a/Mage.Sets/src/mage/cards/s/SasayaOrochiAscendant.java +++ b/Mage.Sets/src/mage/cards/s/SasayaOrochiAscendant.java @@ -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 @@ public List getNetMana(Game game, Ability source) { 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 @@ public List getNetMana(Game game, Ability source) { } if (producedMana.getColorless() > 0) { netMana.add(Mana.ColorlessMana(count)); - } + } } } return netMana; @@ -174,12 +174,12 @@ public List getNetMana(Game game, Ability source) { * RULINGS 6/1/2005 If Sasaya’s Essence’s controller has four Forests and * taps one of them for Green, the Essence will add GreenGreenGreen to that * player’s mana pool for a total of GreenGreenGreenGreen. - * + *

* 6/1/2005 If Sasaya’s Essence’s 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 player’s mana pool. - * + *

* 6/1/2005 If Sasaya’s Essence’s controller has two Brushlands and taps one * of them for White, Sasaya’s Essence adds another White to that player’s * mana pool. It won’t produce Green or Colorless unless the land was tapped @@ -197,7 +197,7 @@ public Mana produceMana(Game game, Ability source) { 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); diff --git a/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java b/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java index 3faa7800b31a..dee6b632e2a6 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java +++ b/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java @@ -18,9 +18,7 @@ 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 @@ public Set possibleTargets(UUID sourceControllerId, Ability source, Game g break; } Set set = CardUtil - .streamPairsWithMap( + .streamAllPairwiseMatches( possibleTargets, (u1, u2) -> game.getCard(u1).sharesName(game.getCard(u2), game) - ? Stream.of(u1, u2) - : Stream.empty() ) - .flatMap(Function.identity()) .collect(Collectors.toSet()); possibleTargets.clear(); possibleTargets.addAll(set); diff --git a/Mage.Sets/src/mage/cards/y/YidaroWanderingMonster.java b/Mage.Sets/src/mage/cards/y/YidaroWanderingMonster.java index 6706653e9a46..bec26df1d2ed 100644 --- a/Mage.Sets/src/mage/cards/y/YidaroWanderingMonster.java +++ b/Mage.Sets/src/mage/cards/y/YidaroWanderingMonster.java @@ -155,7 +155,7 @@ public void watch(GameEvent event, Game game) { 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); } } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index 8c122146d71a..92a1f4d5093d 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -37,7 +37,7 @@ 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 @@ protected boolean checkStateBasedActions() { 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)) { diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 829ef95a1ec9..bc67863096f0 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -58,6 +58,7 @@ 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 static Stream castStream(Stream stream, Class clazz) { return stream.filter(clazz::isInstance).map(clazz::cast).filter(Objects::nonNull); } + public static boolean checkAnyPairs(Collection collection, BiPredicate predicate) { + return streamPairsWithMap(collection, (t1, t2) -> predicate.test(t1, t2)).anyMatch(x -> x); + } + + public static Stream streamAllPairwiseMatches(Collection collection, BiPredicate predicate) { + return streamPairsWithMap( + collection, + (t1, t2) -> predicate.test(t1, t2) + ? Stream.of(t1, t2) + : Stream.empty() + ).flatMap(Function.identity()).distinct(); + } + private static class IntPairIterator implements Iterator> { private final int amount; private int firstCounter = 0; @@ -2201,13 +2215,7 @@ public int getMax() { } } - public static boolean checkAnyPairs(Collection collection, BiPredicate predicate) { - return streamPairsWithMap(collection, (t1, t2) -> predicate.test(t1, t2)).anyMatch(x -> x); - } - - public static Stream streamPairsWithMap( - Collection collection, - BiFunction function) { + public static Stream streamPairsWithMap(Collection collection, BiFunction function) { if (collection.size() < 2) { return Stream.empty(); } From e0f031801ddc849aa9e4a6e68a2d10029b590fe8 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Thu, 3 Oct 2024 12:59:14 -0400 Subject: [PATCH 10/16] more refactors --- Mage.Sets/src/mage/cards/b/BlazingEffigy.java | 20 +-- .../src/mage/cards/b/BondersOrnament.java | 24 ++-- Mage.Sets/src/mage/cards/b/BoobyTrap.java | 4 +- Mage.Sets/src/mage/cards/g/GrimReminder.java | 87 ++++--------- .../src/mage/cards/i/InvaderParasite.java | 119 ++++++------------ Mage.Sets/src/mage/cards/m/MineWorker.java | 83 +++++------- .../src/mage/cards/n/Nebuchadnezzar.java | 2 +- Mage.Sets/src/mage/cards/n/NullChamber.java | 4 +- .../src/mage/cards/p/PowerPlantWorker.java | 88 ++++++------- Mage.Sets/src/mage/cards/p/PsychicBattle.java | 2 +- Mage.Sets/src/mage/cards/r/RetracedImage.java | 41 +++--- Mage.Sets/src/mage/cards/s/Scalpelexis.java | 36 ++---- .../src/mage/cards/s/ScepterOfEmpires.java | 71 +++++------ .../src/mage/cards/s/SiftThroughSands.java | 68 +++++----- .../src/mage/cards/s/SkophosMazeWarden.java | 2 +- .../src/mage/cards/s/SphinxAmbassador.java | 69 ++++------ Mage.Sets/src/mage/cards/s/StompingSlabs.java | 22 ++-- Mage.Sets/src/mage/cards/t/TaintedPact.java | 48 ++++--- .../src/mage/cards/t/ThroneOfEmpires.java | 74 +++++------ Mage.Sets/src/mage/cards/t/TowerWorker.java | 39 +++--- 20 files changed, 348 insertions(+), 555 deletions(-) diff --git a/Mage.Sets/src/mage/cards/b/BlazingEffigy.java b/Mage.Sets/src/mage/cards/b/BlazingEffigy.java index c64d4e9826f4..8aa1dd384750 100644 --- a/Mage.Sets/src/mage/cards/b/BlazingEffigy.java +++ b/Mage.Sets/src/mage/cards/b/BlazingEffigy.java @@ -1,9 +1,5 @@ - package mage.cards.b; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -11,10 +7,10 @@ import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.GameEvent; @@ -22,8 +18,11 @@ import mage.util.CardUtil; import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** - * * @author TheElk801 & L_J */ public final class BlazingEffigy extends CardImpl { @@ -89,14 +88,15 @@ public BlazingEffigyWatcher() { @Override public void watch(GameEvent event, Game game) { - if (event.getType() != GameEvent.EventType.DAMAGED_PERMANENT) { return; } - - if (event.getSourceId().equals(event.getTargetId())) { return; } + if (event.getType() != GameEvent.EventType.DAMAGED_PERMANENT + || event.getSourceId().equals(event.getTargetId())) { + return; + } // TODO: Should damageSourceRef be used for anything? MageObjectReference damageSourceRef = new MageObjectReference(event.getSourceId(), game); MageObjectReference damageTargetRef = new MageObjectReference(event.getTargetId(), game); - if (game.getPermanentOrLKIBattlefield(event.getSourceId()) != null && game.getPermanentOrLKIBattlefield(event.getSourceId()).getName().equals("Blazing Effigy")) { + if (game.getPermanentOrLKIBattlefield(event.getSourceId()) != null && game.getPermanentOrLKIBattlefield(event.getSourceId()).hasName("Blazing Effigy", game)) { damagedObjects.putIfAbsent(damageTargetRef, 0); damagedObjects.compute(damageTargetRef, (k, damage) -> damage + event.getAmount()); } diff --git a/Mage.Sets/src/mage/cards/b/BondersOrnament.java b/Mage.Sets/src/mage/cards/b/BondersOrnament.java index 8e36188ee81e..f69c2d4e27af 100644 --- a/Mage.Sets/src/mage/cards/b/BondersOrnament.java +++ b/Mage.Sets/src/mage/cards/b/BondersOrnament.java @@ -1,6 +1,5 @@ package mage.cards.b; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -11,6 +10,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; import mage.players.Player; @@ -45,6 +47,12 @@ public BondersOrnament copy() { class BondersOrnamentEffect extends OneShotEffect { + private static final FilterPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(new NamePredicate("Bonder's Ornament")); + } + BondersOrnamentEffect() { super(Outcome.Benefit); staticText = "Each player who controls a permanent named Bonder's Ornament draws a card."; @@ -63,18 +71,10 @@ public BondersOrnamentEffect copy() { public boolean apply(Game game, Ability source) { for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); - if (player == null) { - continue; + if (player != null && game.getBattlefield().contains(filter, playerId, source, game, 1)) { + player.drawCards(1, source, game); } - if (game.getBattlefield() - .getAllActivePermanents(playerId) - .stream() - .map(MageObject::getName) - .noneMatch("Bonder's Ornament"::equals)) { - continue; - } - player.drawCards(1, source, game); } return true; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/b/BoobyTrap.java b/Mage.Sets/src/mage/cards/b/BoobyTrap.java index f8fd5f929071..566d4d8730a3 100644 --- a/Mage.Sets/src/mage/cards/b/BoobyTrap.java +++ b/Mage.Sets/src/mage/cards/b/BoobyTrap.java @@ -74,7 +74,7 @@ public boolean checkTrigger(GameEvent event, Game game) { Card drawn = game.getCard(event.getTargetId()); if (drawn != null) { controller.revealCards(this, new CardsImpl(drawn), game); - if (drawn.getName().equals(game.getState().getValue(getSourceId().toString() + ChooseACardNameEffect.INFO_KEY))) { + if (drawn.hasName((String) game.getState().getValue(getSourceId().toString() + ChooseACardNameEffect.INFO_KEY), game)) { //Set target this.getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); return true; @@ -94,4 +94,4 @@ public String getRule() { return "The chosen player reveals each card they draw.\n" + "When the chosen player draws the named card, sacrifice {this}. If you do, {this} deals 10 damage to that player."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/g/GrimReminder.java b/Mage.Sets/src/mage/cards/g/GrimReminder.java index 3da95e7a63e1..e45bcda64efe 100644 --- a/Mage.Sets/src/mage/cards/g/GrimReminder.java +++ b/Mage.Sets/src/mage/cards/g/GrimReminder.java @@ -1,38 +1,28 @@ - package mage.cards.g; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.condition.common.IsStepCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; -import mage.abilities.effects.common.ReturnToHandSourceEffect; 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; import mage.constants.PhaseStep; -import mage.constants.WatcherScope; import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent; import mage.players.Player; import mage.target.common.TargetCardInLibrary; -import mage.watchers.Watcher; +import mage.watchers.common.SpellsCastWatcher; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class GrimReminder extends CardImpl { @@ -42,7 +32,7 @@ public GrimReminder(UUID ownerId, CardSetInfo setInfo) { // Search your library for a nonland card and reveal it. Each opponent who cast a card this turn with the same name as that card loses 6 life. Then shuffle your library. this.getSpellAbility().addEffect(new GrimReminderEffect()); - this.getSpellAbility().addWatcher(new GrimReminderWatcher()); + this.getSpellAbility().addWatcher(new SpellsCastWatcher()); // {B}{B}: Return Grim Reminder from your graveyard to your hand. Activate this ability only during your upkeep. this.addAbility(new ConditionalActivatedAbility( @@ -85,60 +75,29 @@ public GrimReminderEffect copy() { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_NON_LAND); - if (controller.searchLibrary(target, source, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - Cards cardsToReveal = new CardsImpl(card); - controller.revealCards(sourceObject.getIdName(), cardsToReveal, game); - String cardName = card.getName(); - GrimReminderWatcher watcher = game.getState().getWatcher(GrimReminderWatcher.class); - if (watcher != null) { - for (UUID playerId : watcher.getPlayersCastSpell(cardName)) { - Player player = game.getPlayer(playerId); - if (player != null) { - player.loseLife(6, game, source, false); - } - } - } - } - } + if (controller == null) { + return false; + } + TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_NON_LAND); + controller.searchLibrary(target, source, game); + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + if (card == null) { controller.shuffleLibrary(source, game); return true; } - return false; - } -} - -class GrimReminderWatcher extends Watcher { - - private final Map> playersCastSpell = new HashMap<>(); - - public GrimReminderWatcher() { - super(WatcherScope.GAME); - } - - @Override - public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST) { - MageObject spell = game.getObject(event.getTargetId()); - UUID playerId = event.getPlayerId(); - if (playerId != null && spell != null) { - playersCastSpell.putIfAbsent(spell.getName(), new HashSet<>()); - playersCastSpell.get(spell.getName()).add(playerId); + controller.revealCards(source, new CardsImpl(card), game); + String cardName = card.getName(); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); + for (UUID playerId : game.getOpponents(source.getControllerId())) { + Player player = game.getPlayer(playerId); + if (player != null && watcher + .getSpellsCastThisTurn(playerId) + .stream() + .anyMatch(spell -> spell.sharesName(card, game))) { + player.loseLife(6, game, source, false); } } + controller.shuffleLibrary(source, game); + return true; } - - @Override - public void reset() { - playersCastSpell.clear(); - } - - public Set getPlayersCastSpell(String spellName) { - return playersCastSpell.getOrDefault(spellName, new HashSet<>()); - } - } diff --git a/Mage.Sets/src/mage/cards/i/InvaderParasite.java b/Mage.Sets/src/mage/cards/i/InvaderParasite.java index 16bf0109e77f..c64405eec476 100644 --- a/Mage.Sets/src/mage/cards/i/InvaderParasite.java +++ b/Mage.Sets/src/mage/cards/i/InvaderParasite.java @@ -1,29 +1,40 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; -import mage.cards.Card; +import mage.abilities.effects.common.ExileTargetForSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.target.common.TargetLandPermanent; -import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.Collection; +import java.util.Optional; +import java.util.UUID; /** - * @author Loki + * @author TheElk801 */ public final class InvaderParasite extends CardImpl { + private static final FilterPermanent filter + = new FilterLandPermanent("a land an opponent controls with the same name as the exiled card"); + + static { + filter.add(TargetController.OPPONENT.getControllerPredicate()); + filter.add(InvaderParasitePredicate.instance); + } + public InvaderParasite(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); this.subtype.add(SubType.PHYREXIAN); @@ -33,12 +44,15 @@ public InvaderParasite(UUID ownerId, CardSetInfo setInfo) { this.toughness = new MageInt(2); // Imprint - When Invader Parasite enters the battlefield, exile target land. - Ability ability = new EntersBattlefieldTriggeredAbility(new InvaderParasiteImprintEffect(), false); + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect()); ability.addTarget(new TargetLandPermanent()); - this.addAbility(ability); + this.addAbility(ability.setAbilityWord(AbilityWord.IMPRINT)); // Whenever a land with the same name as the exiled card enters the battlefield under an opponent's control, Invader Parasite deals 2 damage to that player. - this.addAbility(new InvaderParasiteTriggeredAbility().setAbilityWord(AbilityWord.IMPRINT)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new DamageTargetEffect(2, true, "that player"), + filter, false, SetTargetPointer.PLAYER + )); } private InvaderParasite(final InvaderParasite card) { @@ -51,76 +65,19 @@ public InvaderParasite copy() { } } -class InvaderParasiteImprintEffect extends OneShotEffect { - - InvaderParasiteImprintEffect() { - super(Outcome.Exile); - staticText = "exile target land"; - } - - private InvaderParasiteImprintEffect(final InvaderParasiteImprintEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (sourcePermanent != null && targetPermanent != null) { - targetPermanent.moveToExile(getId(), "Invader Parasite (Imprint)", source, game); - sourcePermanent.imprint(targetPermanent.getId(), game); - } - return true; - } - - @Override - public InvaderParasiteImprintEffect copy() { - return new InvaderParasiteImprintEffect(this); - } -} - -class InvaderParasiteTriggeredAbility extends TriggeredAbilityImpl { - - InvaderParasiteTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(2)); - } - - private InvaderParasiteTriggeredAbility(final InvaderParasiteTriggeredAbility ability) { - super(ability); - } - - @Override - public InvaderParasiteTriggeredAbility copy() { - return new InvaderParasiteTriggeredAbility(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) { - if (game.getOpponents(this.controllerId).contains(event.getPlayerId())) { - Permanent targetPermanent = game.getPermanent(event.getTargetId()); - Permanent sourcePermanent = game.getPermanent(getSourceId()); - if (targetPermanent != null && sourcePermanent != null) { - if (!sourcePermanent.getImprinted().isEmpty()) { - Card imprintedCard = game.getCard(sourcePermanent.getImprinted().get(0)); - if (imprintedCard != null && targetPermanent.getName().equals(imprintedCard.getName())) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - } - return true; - } - } - } - } - return false; - } +enum InvaderParasitePredicate implements ObjectSourcePlayerPredicate { + instance; @Override - public String getRule() { - return "Whenever a land with the same name as the exiled card enters the battlefield under an opponent's control, {this} deals 2 damage to that player."; + public boolean apply(ObjectSourcePlayer input, Game game) { + return Optional + .ofNullable(game) + .map(Game::getExile) + .map(e -> e.getExileZone(CardUtil.getExileZoneId(game, input.getSource()))) + .filter(e -> !e.isEmpty()) + .map(e -> e.getCards(game)) + .map(Collection::stream) + .map(s -> s.anyMatch(card -> card.sharesName(input.getObject(), game))) + .orElse(false); } } diff --git a/Mage.Sets/src/mage/cards/m/MineWorker.java b/Mage.Sets/src/mage/cards/m/MineWorker.java index 250d61d12711..edb2b9c6a1a8 100644 --- a/Mage.Sets/src/mage/cards/m/MineWorker.java +++ b/Mage.Sets/src/mage/cards/m/MineWorker.java @@ -1,27 +1,41 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.OneShotEffect; -import mage.constants.Outcome; -import mage.constants.SubType; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.NamePredicate; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class MineWorker extends CardImpl { + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterPermanent filter2 = new FilterControlledCreaturePermanent(); + + static { + filter.add(new NamePredicate("Power Plant Worker")); + filter2.add(new NamePredicate("Tower Worker")); + } + + private static final Condition condition = new CompoundCondition( + new PermanentsOnTheBattlefieldCondition(filter), + new PermanentsOnTheBattlefieldCondition(filter2) + ); + public MineWorker(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); @@ -30,7 +44,10 @@ public MineWorker(UUID ownerId, CardSetInfo setInfo) { this.toughness = new MageInt(1); // {T}: You gain 1 life. If you control creatures named Power Plant Worker and Tower Worker, you gain 3 life instead. - this.addAbility(new SimpleActivatedAbility(new MineWorkerEffect(), new TapSourceCost())); + this.addAbility(new SimpleActivatedAbility(new ConditionalOneShotEffect( + new GainLifeEffect(3), new GainLifeEffect(1), condition, "you gain 1 life. " + + "If you control creatures named Power Plant Worker and Tower Worker, you gain 3 life instead" + ), new TapSourceCost())); } private MineWorker(final MineWorker card) { @@ -42,47 +59,3 @@ public MineWorker copy() { return new MineWorker(this); } } - -class MineWorkerEffect extends OneShotEffect { - - MineWorkerEffect() { - super(Outcome.GainLife); - this.staticText = "You gain 1 life. If you control creatures named Power Plant Worker and Tower Worker, you gain 3 life instead."; - } - - private MineWorkerEffect(final MineWorkerEffect effect) { - super(effect); - } - - @Override - public MineWorkerEffect copy() { - return new MineWorkerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - String powerPlantName = "Power Plant Worker"; - String towerName = "Tower Worker"; - boolean powerPlant = false; - boolean tower = false; - int life = 1; - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game)) { - String name = permanent.getName(); - if (!powerPlant && powerPlantName.equals(name)) { - powerPlant = true; - } else if (!tower && towerName.equals(name)) { - tower = true; - } - if (powerPlant && tower) { - life = 3; - break; - } - } - controller.gainLife(life, game, source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/n/Nebuchadnezzar.java b/Mage.Sets/src/mage/cards/n/Nebuchadnezzar.java index 20048051a127..e70c66b9d78d 100644 --- a/Mage.Sets/src/mage/cards/n/Nebuchadnezzar.java +++ b/Mage.Sets/src/mage/cards/n/Nebuchadnezzar.java @@ -86,7 +86,7 @@ public boolean apply(Game game, Ability source) { } } opponent.revealCards(sourceObject.getIdName(), cards, game); - cards.removeIf(uuid -> !cardName.equals(game.getCard(uuid).getName())); + cards.removeIf(uuid -> !game.getCard(uuid).hasName(cardName, game)); opponent.discard(cards, false, source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/n/NullChamber.java b/Mage.Sets/src/mage/cards/n/NullChamber.java index 8aff04eb4b21..86b7a945827b 100644 --- a/Mage.Sets/src/mage/cards/n/NullChamber.java +++ b/Mage.Sets/src/mage/cards/n/NullChamber.java @@ -134,8 +134,8 @@ public boolean checksEventType(GameEvent event, Game game) { public boolean applies(GameEvent event, Ability source, Game game) { MageObject object = game.getObject(event.getSourceId()); if (object != null) { - return object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NullChamberChooseEffect.INFO_KEY_CONTROLLER)) - || object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NullChamberChooseEffect.INFO_KEY_OPPONENT)); + return object.hasName((String) game.getState().getValue(source.getSourceId().toString() + NullChamberChooseEffect.INFO_KEY_CONTROLLER), game) + || object.hasName((String) game.getState().getValue(source.getSourceId().toString() + NullChamberChooseEffect.INFO_KEY_OPPONENT), game); } return false; } diff --git a/Mage.Sets/src/mage/cards/p/PowerPlantWorker.java b/Mage.Sets/src/mage/cards/p/PowerPlantWorker.java index ff650468a451..a7a43449baf8 100644 --- a/Mage.Sets/src/mage/cards/p/PowerPlantWorker.java +++ b/Mage.Sets/src/mage/cards/p/PowerPlantWorker.java @@ -1,26 +1,46 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.AddContinuousEffectToGame; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.constants.*; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.NamePredicate; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class PowerPlantWorker extends CardImpl { + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterPermanent filter2 = new FilterControlledCreaturePermanent(); + + static { + filter.add(new NamePredicate("Mine Worker")); + filter2.add(new NamePredicate("Tower Worker")); + } + + private static final Condition condition = new CompoundCondition( + new PermanentsOnTheBattlefieldCondition(filter), + new PermanentsOnTheBattlefieldCondition(filter2) + ); + public PowerPlantWorker(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}"); @@ -29,7 +49,15 @@ public PowerPlantWorker(UUID ownerId, CardSetInfo setInfo) { this.toughness = new MageInt(4); // {3}: Power Plant Worker gets +2/+2 until end of turn. If you control creatures named Mine Worker and Tower Worker, put two +1/+1 counters on Power Plant Worker instead. Activate only once each turn. - this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new PowerPlantWorkerEffect(), new GenericManaCost(3))); + this.addAbility(new LimitedTimesPerTurnActivatedAbility( + Zone.BATTLEFIELD, + new ConditionalOneShotEffect( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), + new AddContinuousEffectToGame(new BoostSourceEffect(2, 2, Duration.EndOfTurn)), + condition, "{this} gets +2/+2 until end of turn. If you control creatures " + + "named Mine Worker and Tower Worker, put two +1/+1 counters on {this} instead" + ), new GenericManaCost(3) + )); } private PowerPlantWorker(final PowerPlantWorker card) { @@ -41,45 +69,3 @@ public PowerPlantWorker copy() { return new PowerPlantWorker(this); } } - -class PowerPlantWorkerEffect extends OneShotEffect { - - PowerPlantWorkerEffect() { - super(Outcome.BoostCreature); - this.staticText = "{this} gets +2/+2 until end of turn. If you control creatures named Mine Worker and Tower Worker, put two +1/+1 counters on {this} instead."; - } - - private PowerPlantWorkerEffect(final PowerPlantWorkerEffect effect) { - super(effect); - } - - @Override - public PowerPlantWorkerEffect copy() { - return new PowerPlantWorkerEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); - if (sourcePermanent == null) { - return false; - } - String mineName = "Mine Worker"; - String towerName = "Tower Worker"; - boolean mine = false; - boolean tower = false; - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game)) { - String name = permanent.getName(); - if (!mine && mineName.equals(name)) { - mine = true; - } else if (!tower && towerName.equals(name)) { - tower = true; - } - if (mine && tower) { - return sourcePermanent.addCounters(CounterType.P1P1.createInstance(2), source, game); - } - } - game.addEffect(new BoostSourceEffect(2, 2, Duration.EndOfTurn), source); - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/p/PsychicBattle.java b/Mage.Sets/src/mage/cards/p/PsychicBattle.java index e0e760bc84a8..8d17aac1dde6 100644 --- a/Mage.Sets/src/mage/cards/p/PsychicBattle.java +++ b/Mage.Sets/src/mage/cards/p/PsychicBattle.java @@ -69,7 +69,7 @@ public boolean checkEventType(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) { StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); if (stackObject != null) { - if (!stackObject.isTargetChanged() && !stackObject.getName().equals("Psychic Battle")) { + if (!stackObject.isTargetChanged() && !stackObject.hasName("Psychic Battle", game)) { this.getEffects().get(0).setTargetPointer(new FixedTarget(event.getSourceId())); stackObject.setTargetChanged(false); // resets the targetChanged flag return true; diff --git a/Mage.Sets/src/mage/cards/r/RetracedImage.java b/Mage.Sets/src/mage/cards/r/RetracedImage.java index b52eaf19e3c3..45a42882f536 100644 --- a/Mage.Sets/src/mage/cards/r/RetracedImage.java +++ b/Mage.Sets/src/mage/cards/r/RetracedImage.java @@ -1,23 +1,21 @@ package mage.cards.r; -import java.util.UUID; 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; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class RetracedImage extends CardImpl { @@ -27,7 +25,6 @@ public RetracedImage(UUID ownerId, CardSetInfo setInfo) { // Reveal a card in your hand, then put that card onto the battlefield if it has the same name as a permanent. this.getSpellAbility().addEffect(new RetracedImageEffect()); - } private RetracedImage(final RetracedImage card) { @@ -59,23 +56,21 @@ public RetracedImageEffect copy() { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - TargetCardInHand target = new TargetCardInHand(); - if (target.canChoose(controller.getId(), source, game) - && controller.choose(outcome, target, source, game)) { - Card chosenCard = game.getCard(target.getFirstTarget()); - if (chosenCard != null) { - Cards cards = new CardsImpl(); - cards.add(chosenCard); - controller.revealCards(source, cards, game); - for (Permanent permanent : game.getBattlefield().getAllActivePermanents()) { - if (permanent.getName().equals(chosenCard.getName())) { - return controller.moveCards(chosenCard, Zone.BATTLEFIELD, source, game); - } - } - } - } + if (controller == null || controller.getHand().isEmpty()) { + return false; } - return false; + TargetCardInHand target = new TargetCardInHand(); + controller.choose(outcome, target, source, game); + Card chosenCard = game.getCard(target.getFirstTarget()); + return chosenCard != null + && game + .getBattlefield() + .getActivePermanents( + StaticFilters.FILTER_PERMANENT, + source.getControllerId(), source, game + ) + .stream() + .anyMatch(permanent -> permanent.sharesName(chosenCard, game)) + && controller.moveCards(chosenCard, Zone.BATTLEFIELD, source, game); } } diff --git a/Mage.Sets/src/mage/cards/s/Scalpelexis.java b/Mage.Sets/src/mage/cards/s/Scalpelexis.java index 08e42551ba5e..7c1927ab55c3 100644 --- a/Mage.Sets/src/mage/cards/s/Scalpelexis.java +++ b/Mage.Sets/src/mage/cards/s/Scalpelexis.java @@ -1,28 +1,25 @@ - package mage.cards.s; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; 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.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class Scalpelexis extends CardImpl { @@ -69,26 +66,17 @@ public ScalpelexisEffect copy() { @Override public boolean apply(Game game, Ability source) { - Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (targetPlayer == null) { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player == null) { return false; } - Set cardNames = new HashSet<>(); - boolean doubleName; - do { - doubleName = false; - Cards toExile = new CardsImpl(targetPlayer.getLibrary().getTopCards(game, 4)); - cardNames.clear(); - for (Card card : toExile.getCards(game)) { - if (cardNames.contains(card.getName())) { - doubleName = true; - break; - } else { - cardNames.add(card.getName()); - } + while (player.getLibrary().hasCards()) { + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 4)); + player.moveCards(cards, Zone.EXILED, source, game); + if (!CardUtil.checkAnyPairs(cards.getCards(game), (c1, c2) -> c1.sharesName(c2, game))) { + break; } - targetPlayer.moveCards(toExile, Zone.EXILED, source, game); - } while (doubleName); + } return true; } } diff --git a/Mage.Sets/src/mage/cards/s/ScepterOfEmpires.java b/Mage.Sets/src/mage/cards/s/ScepterOfEmpires.java index 821d119473ad..8ae2b42c7c08 100644 --- a/Mage.Sets/src/mage/cards/s/ScepterOfEmpires.java +++ b/Mage.Sets/src/mage/cards/s/ScepterOfEmpires.java @@ -1,30 +1,50 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.predicate.mageobject.NamePredicate; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** * @author nantuko */ public final class ScepterOfEmpires extends CardImpl { + private static final FilterPermanent filter = new FilterControlledArtifactPermanent(); + private static final FilterPermanent filter2 = new FilterControlledArtifactPermanent(); + + static { + filter.add(new NamePredicate("Crown of Empires")); + filter2.add(new NamePredicate("Throne of Empires")); + } + + private static final Condition condition = new CompoundCondition( + new PermanentsOnTheBattlefieldCondition(filter), + new PermanentsOnTheBattlefieldCondition(filter2) + ); + public ScepterOfEmpires(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // {tap}: Scepter of Empires deals 1 damage to target player. It deals 3 damage to that player instead if you control artifacts named Crown of Empires and Throne of Empires. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScepterOfEmpiresEffect(), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new ConditionalOneShotEffect( + new DamageTargetEffect(3), new DamageTargetEffect(1), condition, "{this} deals " + + "1 damage to target player. It deals 3 damage to that player instead if " + + "you control artifacts named Crown of Empires and Throne of Empires" + ), new TapSourceCost()); ability.addTarget(new TargetPlayerOrPlaneswalker()); this.addAbility(ability); } @@ -38,38 +58,3 @@ public ScepterOfEmpires copy() { return new ScepterOfEmpires(this); } } - -class ScepterOfEmpiresEffect extends OneShotEffect { - - ScepterOfEmpiresEffect() { - super(Outcome.PutCreatureInPlay); - staticText = "Scepter of Empires deals 1 damage to target player or planeswalker. It deals 3 damage instead if you control artifacts named Crown of Empires and Throne of Empires"; - } - - private ScepterOfEmpiresEffect(final ScepterOfEmpiresEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - boolean throne = false; - boolean crown = false; - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { - if (permanent.getName().equals("Throne of Empires")) { - throne = true; - } else if (permanent.getName().equals("Crown of Empires")) { - crown = true; - } - if (throne && crown) { - break; - } - } - int amount = throne && crown ? 3 : 1; - return game.damagePlayerOrPermanent(source.getFirstTarget(), amount, source.getSourceId(), source, game, false, true) > 0; - } - - @Override - public ScepterOfEmpiresEffect copy() { - return new ScepterOfEmpiresEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SiftThroughSands.java b/Mage.Sets/src/mage/cards/s/SiftThroughSands.java index ee2bdd883554..edf490e59535 100644 --- a/Mage.Sets/src/mage/cards/s/SiftThroughSands.java +++ b/Mage.Sets/src/mage/cards/s/SiftThroughSands.java @@ -1,12 +1,9 @@ - package mage.cards.s; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalOneShotEffect; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -21,15 +18,15 @@ import mage.target.common.TargetCardInLibrary; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; /** - * * @author LevelX2 */ public final class SiftThroughSands extends CardImpl { - private static final String rule = "
If you've cast a spell named Peer Through Depths and a spell named Reach Through Mists this turn, you may search your library for a card named The Unspeakable, put it onto the battlefield, then shuffle"; private static final FilterCreatureCard filter = new FilterCreatureCard("a card named The Unspeakable"); static { @@ -37,17 +34,19 @@ public final class SiftThroughSands extends CardImpl { } public SiftThroughSands(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{U}"); this.subtype.add(SubType.ARCANE); // Draw two cards, then discard a card. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); - Effect effect = new DiscardControllerEffect(1); - effect.setText(", then discard a card"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new DrawDiscardControllerEffect(2, 1)); // If you've cast a spell named Peer Through Depths and a spell named Reach Through Mists this turn, you may search your library for a card named The Unspeakable, put it onto the battlefield, then shuffle your library. - this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), false), new SiftThroughSandsCondition(), rule)); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), false), + SiftThroughSandsCondition.instance, "
If you've cast a spell named " + + "Peer Through Depths and a spell named Reach Through Mists this turn, you may search your library " + + "for a card named The Unspeakable, put it onto the battlefield, then shuffle" + )); this.getSpellAbility().addWatcher(new SiftThroughSandsWatcher()); } @@ -61,48 +60,51 @@ public SiftThroughSands copy() { } } -class SiftThroughSandsCondition implements Condition { +enum SiftThroughSandsCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { - SiftThroughSandsWatcher watcher = game.getState().getWatcher(SiftThroughSandsWatcher.class, source.getControllerId()); - if (watcher != null) { - return watcher.conditionMet(); - } - return false; + return SiftThroughSandsWatcher.checkPlayer(source.getControllerId(), game); } } class SiftThroughSandsWatcher extends Watcher { - boolean castPeerThroughDepths = false; - boolean castReachThroughMists = false; + Set castPeerThroughDepths = new HashSet<>(); + Set castReachThroughMists = new HashSet<>(); public SiftThroughSandsWatcher() { - super(WatcherScope.PLAYER); + super(WatcherScope.GAME); } @Override public void watch(GameEvent event, Game game) { - if (condition) { //no need to check - condition has already occured + if (event.getType() != GameEvent.EventType.SPELL_CAST) { return; } - if (event.getType() == GameEvent.EventType.SPELL_CAST - && controllerId.equals(event.getPlayerId())) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell.getCard().getName().equals("Peer Through Depths")) { - castPeerThroughDepths = true; - } else if (spell.getCard().getName().equals("Reach Through Mists")) { - castReachThroughMists = true; - } - condition = castPeerThroughDepths && castReachThroughMists; + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell.hasName("Peer Through Depths", game)) { + castPeerThroughDepths.add(spell.getControllerId()); + } + if (spell.hasName("Reach Through Mists", game)) { + castReachThroughMists.add(spell.getControllerId()); } } @Override public void reset() { super.reset(); - this.castPeerThroughDepths = false; - this.castReachThroughMists = false; + this.castPeerThroughDepths.clear(); + this.castReachThroughMists.clear(); + } + + static boolean checkPlayer(UUID playerId, Game game) { + return game.getState().getWatcher(SiftThroughSandsWatcher.class).check(playerId); + } + + private boolean check(UUID playerId) { + return castPeerThroughDepths.contains(playerId) + && castReachThroughMists.contains(playerId); } } diff --git a/Mage.Sets/src/mage/cards/s/SkophosMazeWarden.java b/Mage.Sets/src/mage/cards/s/SkophosMazeWarden.java index e76024a55468..12519208f07d 100644 --- a/Mage.Sets/src/mage/cards/s/SkophosMazeWarden.java +++ b/Mage.Sets/src/mage/cards/s/SkophosMazeWarden.java @@ -82,7 +82,7 @@ public boolean checkTrigger(GameEvent event, Game game) { if (permanent == null || !permanent.isControlledBy(getControllerId()) || !permanent.isLand(game) - || !permanent.getName().equals("Labyrinth of Skophos")) { + || !permanent.hasName("Labyrinth of Skophos", game)) { return false; } Permanent creature = game.getPermanent(event.getTargetId()); diff --git a/Mage.Sets/src/mage/cards/s/SphinxAmbassador.java b/Mage.Sets/src/mage/cards/s/SphinxAmbassador.java index cd61086ebd69..4a4295687f8b 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxAmbassador.java +++ b/Mage.Sets/src/mage/cards/s/SphinxAmbassador.java @@ -1,31 +1,25 @@ - package mage.cards.s; -import java.util.Collection; -import java.util.TreeSet; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseACardNameEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.choices.Choice; -import mage.choices.ChoiceHintType; -import mage.choices.ChoiceImpl; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author North */ public final class SphinxAmbassador extends CardImpl { @@ -38,8 +32,11 @@ public SphinxAmbassador(UUID ownerId, CardSetInfo setInfo) { this.toughness = new MageInt(5); this.addAbility(FlyingAbility.getInstance()); + // Whenever Sphinx Ambassador deals combat damage to a player, search that player's library for a card, then that player names a card. If you searched for a creature card that isn't the named card, you may put it onto the battlefield under your control. Then that player shuffles their library. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new SphinxAmbassadorEffect(), false, true)); + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new SphinxAmbassadorEffect(), false, true + )); } private SphinxAmbassador(final SphinxAmbassador card) { @@ -56,7 +53,9 @@ class SphinxAmbassadorEffect extends OneShotEffect { SphinxAmbassadorEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "search that player's library for a card, then that player chooses a card name. If you searched for a creature card that doesn't have that name, you may put it onto the battlefield under your control. Then that player shuffles"; + this.staticText = "search that player's library for a card, then that player chooses a card name. " + + "If you searched for a creature card that doesn't have that name, " + + "you may put it onto the battlefield under your control. Then that player shuffles"; } private SphinxAmbassadorEffect(final SphinxAmbassadorEffect effect) { @@ -72,40 +71,20 @@ public SphinxAmbassadorEffect copy() { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (controller != null && targetPlayer != null && sourcePermanent != null) { - TargetCardInLibrary target = new TargetCardInLibrary(); - controller.searchLibrary(target, source, game, targetPlayer.getId()); - - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - TreeSet choices = new TreeSet<>(); - Collection cards = game.getCards(); - for (Card gameCard : cards) { - if (gameCard.isOwnedBy(targetPlayer.getId())) { - choices.add(gameCard.getName()); - } - } - - Choice cardChoice = new ChoiceImpl(false, ChoiceHintType.CARD); - cardChoice.setChoices(choices); - cardChoice.clearChoice(); - if (!targetPlayer.choose(Outcome.Benefit, cardChoice, game)) { - return false; - } - String cardName = cardChoice.getChoice(); - - game.informPlayers(sourcePermanent.getName() + ", named card: [" + cardName + ']'); - if (!card.getName().equals(cardName) && card.isCreature(game)) { - if (controller.chooseUse(outcome, "Put " + card.getName() + " onto the battlefield?", source, game)) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } - } - } - - targetPlayer.shuffleLibrary(source, game); - return true; + if (controller == null || targetPlayer == null) { + return false; + } + TargetCardInLibrary target = new TargetCardInLibrary(); + controller.searchLibrary(target, source, game, targetPlayer.getId()); + Card card = targetPlayer.getLibrary().getCard(target.getFirstTarget(), game); + String name = ChooseACardNameEffect.TypeOfName.ALL.getChoice(targetPlayer, game, source, false); + if (card != null + && card.isCreature(game) + && !card.hasName(name, game) + && controller.chooseUse(outcome, "Put " + card.getName() + " onto the battlefield?", source, game)) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); } - return false; + targetPlayer.shuffleLibrary(source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/s/StompingSlabs.java b/Mage.Sets/src/mage/cards/s/StompingSlabs.java index bcf260595b5a..8b62303944d6 100644 --- a/Mage.Sets/src/mage/cards/s/StompingSlabs.java +++ b/Mage.Sets/src/mage/cards/s/StompingSlabs.java @@ -1,16 +1,11 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; -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.game.Game; @@ -18,14 +13,15 @@ import mage.target.common.TargetAnyTarget; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author emerald000 */ public final class StompingSlabs extends CardImpl { public StompingSlabs(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); // Reveal the top seven cards of your library, then put those cards on the bottom of your library in any order. If a card named Stomping Slabs was revealed this way, Stomping Slabs deals 7 damage to any target. this.getSpellAbility().addEffect(new StompingSlabsEffect()); @@ -43,21 +39,21 @@ public StompingSlabs copy() { } class StompingSlabsEffect extends OneShotEffect { - + StompingSlabsEffect() { super(Outcome.Damage); this.staticText = "Reveal the top seven cards of your library, then put those cards on the bottom of your library in any order. If a card named Stomping Slabs was revealed this way, {this} deals 7 damage to any target"; } - + private StompingSlabsEffect(final StompingSlabsEffect effect) { super(effect); } - + @Override public StompingSlabsEffect copy() { return new StompingSlabsEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -68,7 +64,7 @@ public boolean apply(Game game, Ability source) { boolean stompingSlabsFound = false; for (UUID cardId : cards) { Card card = game.getCard(cardId); - if (card != null && card.getName().equals("Stomping Slabs")) { + if (card != null && card.hasName("Stomping Slabs", game)) { stompingSlabsFound = true; break; } diff --git a/Mage.Sets/src/mage/cards/t/TaintedPact.java b/Mage.Sets/src/mage/cards/t/TaintedPact.java index 73c3327775ba..c1499d136286 100644 --- a/Mage.Sets/src/mage/cards/t/TaintedPact.java +++ b/Mage.Sets/src/mage/cards/t/TaintedPact.java @@ -1,21 +1,17 @@ package mage.cards.t; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author cbt33, Ad Nauseum (North), Izzet Staticaster (LevelX2), Bane Alley * Broker (LevelX2) */ @@ -56,30 +52,28 @@ public TaintedPactEffect copy() { @Override public boolean apply(Game game, Ability source) { - Card sourceCard = game.getCard(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); - if (controller == null - || sourceCard == null) { + if (controller == null) { return false; } - Set names = new HashSet<>(); - while (controller.canRespond() - && controller.getLibrary().hasCards()) { + Cards cards = new CardsImpl(); + while (controller.canRespond() && controller.getLibrary().hasCards()) { Card card = controller.getLibrary().getFromTop(game); - if (card != null) { - // the card move is sequential, not all at once. - controller.moveCards(card, Zone.EXILED, source, game); - game.processAction(); // Laelia, the Blade Reforged - // Checks if there was already exiled a card with the same name - if (names.contains(card.getName())) { - break; - } - names.add(card.getName()); - if (controller.chooseUse(outcome, "Put " + card.getName() + " into your hand?", source, game)) { - //Adds the current card to hand if it is chosen. - controller.moveCards(card, Zone.HAND, source, game); - break; - } + if (card == null) { + continue; + } + // the card move is sequential, not all at once. + controller.moveCards(card, Zone.EXILED, source, game); + game.processAction(); // Laelia, the Blade Reforged + // Checks if there was already exiled a card with the same name + if (cards.getCards(game).stream().anyMatch(c -> c.sharesName(card, game))) { + break; + } + cards.add(card); + if (controller.chooseUse(outcome, "Put " + card.getName() + " into your hand?", source, game)) { + //Adds the current card to hand if it is chosen. + controller.moveCards(card, Zone.HAND, source, game); + break; } } return true; diff --git a/Mage.Sets/src/mage/cards/t/ThroneOfEmpires.java b/Mage.Sets/src/mage/cards/t/ThroneOfEmpires.java index 103cc7baa9d5..4f14310efcc9 100644 --- a/Mage.Sets/src/mage/cards/t/ThroneOfEmpires.java +++ b/Mage.Sets/src/mage/cards/t/ThroneOfEmpires.java @@ -1,32 +1,51 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.CompoundCondition; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.predicate.mageobject.NamePredicate; import mage.game.permanent.token.SoldierToken; -import mage.game.permanent.token.Token; + +import java.util.UUID; /** * @author nantuko */ public final class ThroneOfEmpires extends CardImpl { + private static final FilterPermanent filter = new FilterControlledArtifactPermanent(); + private static final FilterPermanent filter2 = new FilterControlledArtifactPermanent(); + + static { + filter.add(new NamePredicate("Crown of Empires")); + filter2.add(new NamePredicate("Scepter of Empires")); + } + + private static final Condition condition = new CompoundCondition( + new PermanentsOnTheBattlefieldCondition(filter), + new PermanentsOnTheBattlefieldCondition(filter2) + ); + public ThroneOfEmpires(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {1}, {tap}: Create a 1/1 white Soldier creature token. Create five of those tokens instead if you control artifacts named Crown of Empires and Scepter of Empires. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ThroneOfEmpiresEffect(), new GenericManaCost(1)); + Ability ability = new SimpleActivatedAbility(new ConditionalOneShotEffect( + new CreateTokenEffect(new SoldierToken(), 5), new CreateTokenEffect(new SoldierToken()), + condition, "create a 1/1 white Soldier creature token. Create five of those tokens " + + "instead if you control artifacts named Crown of Empires and Scepter of Empires" + ), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } @@ -40,38 +59,3 @@ public ThroneOfEmpires copy() { return new ThroneOfEmpires(this); } } - -class ThroneOfEmpiresEffect extends OneShotEffect { - - ThroneOfEmpiresEffect() { - super(Outcome.PutCreatureInPlay); - staticText = "Create a 1/1 white Soldier creature token. Create five of those tokens instead if you control artifacts named Crown of Empires and Scepter of Empires"; - } - - private ThroneOfEmpiresEffect(final ThroneOfEmpiresEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - boolean scepter = false; - boolean crown = false; - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { - if (permanent.getName().equals("Scepter of Empires")) { - scepter = true; - } else if (permanent.getName().equals("Crown of Empires")) { - crown = true; - } - if (scepter && crown) break; - } - Token soldier = new SoldierToken(); - int count = scepter && crown ? 5 : 1; - soldier.putOntoBattlefield(count, game, source, source.getControllerId()); - return false; - } - - @Override - public ThroneOfEmpiresEffect copy() { - return new ThroneOfEmpiresEffect(this); - } -} diff --git a/Mage.Sets/src/mage/cards/t/TowerWorker.java b/Mage.Sets/src/mage/cards/t/TowerWorker.java index 96e6150f8701..eb37b9e682e0 100644 --- a/Mage.Sets/src/mage/cards/t/TowerWorker.java +++ b/Mage.Sets/src/mage/cards/t/TowerWorker.java @@ -1,23 +1,24 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.Mana; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; -import mage.abilities.mana.DynamicManaAbility; -import mage.constants.SubType; import mage.abilities.keyword.ReachAbility; +import mage.abilities.mana.DynamicManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.NamePredicate; import mage.game.Game; -import mage.game.permanent.Permanent; + +import java.util.UUID; /** - * * @author weirddan455 */ public final class TowerWorker extends CardImpl { @@ -51,25 +52,19 @@ public TowerWorker copy() { enum TowerWorkerValue implements DynamicValue { instance; + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterPermanent filter2 = new FilterControlledCreaturePermanent(); + + static { + filter.add(new NamePredicate("Mine Worker")); + filter2.add(new NamePredicate("Power Plant Worker")); + } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - String mineName = "Mine Worker"; - String powerPlantName = "Power Plant Worker"; - boolean mine = false; - boolean powerPlant = false; - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceAbility.getControllerId(), game)) { - String name = permanent.getName(); - if (!mine && mineName.equals(name)) { - mine = true; - } else if (!powerPlant && powerPlantName.equals(name)) { - powerPlant = true; - } - if (mine && powerPlant) { - return 3; - } - } - return 1; + return game.getBattlefield().contains(filter, sourceAbility, game, 1) + && game.getBattlefield().contains(filter2, sourceAbility, game, 1) + ? 3 : 1; } @Override From a9ef69885eaca5ab899788cfbce6a0d733096c27 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Tue, 8 Oct 2024 11:18:49 -0400 Subject: [PATCH 11/16] more refactoring --- Mage.Sets/src/mage/cards/d/DeadlyCoverUp.java | 17 +- Mage.Sets/src/mage/cards/d/Deicide.java | 15 +- .../src/mage/cards/i/InvasiveSurgery.java | 35 +-- .../src/mage/cards/m/MinamosMeddling.java | 2 +- .../src/mage/cards/n/NissasEncouragement.java | 204 +++++++++++------- Mage.Sets/src/mage/cards/p/PickTheBrain.java | 38 ++-- .../src/mage/cards/p/PompousGadabout.java | 4 +- .../mage/cards/s/SceptreOfEternalGlory.java | 42 ++-- .../src/mage/cards/s/SpellweaverHelix.java | 162 ++++++-------- .../abilities/enters/ProteanHydraTest.java | 3 +- .../abilities/keywords/DisguiseTest.java | 6 +- .../cards/abilities/keywords/DisturbTest.java | 42 ++-- .../cards/abilities/keywords/HauntTest.java | 24 +-- .../abilities/keywords/ManifestTest.java | 23 +- .../cards/abilities/keywords/MorphTest.java | 10 +- .../abilities/keywords/OffspringTest.java | 2 +- .../abilities/keywords/PoisonousTest.java | 4 +- .../abilities/keywords/PrototypeTest.java | 52 +++-- .../oneshot/library/PutToLibraryTest.java | 8 +- Mage/src/main/java/mage/MageObject.java | 4 + .../assignment/common/NameAssignment.java | 23 ++ .../ExileTargetCardCopyAndCastEffect.java | 6 +- ...dHandLibraryForCardNameAndExileEffect.java | 109 +++++----- 23 files changed, 431 insertions(+), 404 deletions(-) create mode 100644 Mage/src/main/java/mage/abilities/assignment/common/NameAssignment.java diff --git a/Mage.Sets/src/mage/cards/d/DeadlyCoverUp.java b/Mage.Sets/src/mage/cards/d/DeadlyCoverUp.java index 4f04e8b6dbe3..0a9ed83e0ae5 100644 --- a/Mage.Sets/src/mage/cards/d/DeadlyCoverUp.java +++ b/Mage.Sets/src/mage/cards/d/DeadlyCoverUp.java @@ -27,7 +27,6 @@ public final class DeadlyCoverUp extends CardImpl { public DeadlyCoverUp(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); - // As an additional cost to cast this spell, you may collect evidence 6. this.addAbility(new CollectEvidenceAbility(6)); @@ -70,16 +69,18 @@ public DeadlyCoverUpEffect copy() { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return true; + } TargetCardInOpponentsGraveyard target = new TargetCardInOpponentsGraveyard(StaticFilters.FILTER_CARD); target.withNotTarget(true); - if (player != null && player.chooseTarget(Outcome.Exile, target, source, game)) { - Card cardToExile = game.getCard(target.getFirstTarget()); - if (cardToExile == null) { - return false; - } - player.moveCards(cardToExile, Zone.EXILED, source, game); - this.applySearchAndExile(game, source, cardToExile.getName(), cardToExile.getOwnerId()); + player.chooseTarget(Outcome.Exile, target, source, game); + Card cardToExile = game.getCard(target.getFirstTarget()); + if (cardToExile == null) { + return false; } + player.moveCards(cardToExile, Zone.EXILED, source, game); + this.applySearchAndExile(game, source, cardToExile, cardToExile.getOwnerId()); return true; } } diff --git a/Mage.Sets/src/mage/cards/d/Deicide.java b/Mage.Sets/src/mage/cards/d/Deicide.java index 366d1076f0e9..bb24d8bdf2d1 100644 --- a/Mage.Sets/src/mage/cards/d/Deicide.java +++ b/Mage.Sets/src/mage/cards/d/Deicide.java @@ -1,7 +1,6 @@ package mage.cards.d; import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; import mage.cards.Card; import mage.cards.CardImpl; @@ -53,12 +52,8 @@ private DeicideExileEffect(final DeicideExileEffect effect) { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Card sourceCard = game.getCard(source.getSourceId()); - if (controller == null || sourceCard == null) { - return false; - } Permanent targetEnchantment = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (targetEnchantment == null) { + if (controller == null || targetEnchantment == null) { return false; } controller.moveCards(targetEnchantment, Zone.EXILED, source, game); @@ -69,11 +64,11 @@ public boolean apply(Game game, Ability source) { // if it is a God. For each of the Gods in the Theros block, it won't matter what your // devotion to its color(s) was. The card is a God card when not on the battlefield. Card cardInExile = game.getExile().getCard(targetEnchantment.getId(), game); - if (cardInExile != null && cardInExile.hasSubtype(SubType.GOD, game)) { - Player enchantmentController = game.getPlayer(targetEnchantment.getControllerId()); - return enchantmentController != null && super.applySearchAndExile(game, source, cardInExile.getName(), enchantmentController.getId()); + if (cardInExile == null || !cardInExile.hasSubtype(SubType.GOD, game)) { + return false; } - return false; + Player enchantmentController = game.getPlayer(targetEnchantment.getControllerId()); + return enchantmentController != null && super.applySearchAndExile(game, source, cardInExile, enchantmentController.getId()); } @Override diff --git a/Mage.Sets/src/mage/cards/i/InvasiveSurgery.java b/Mage.Sets/src/mage/cards/i/InvasiveSurgery.java index 21190f5ffb24..e8ab8d9c654b 100644 --- a/Mage.Sets/src/mage/cards/i/InvasiveSurgery.java +++ b/Mage.Sets/src/mage/cards/i/InvasiveSurgery.java @@ -1,23 +1,20 @@ package mage.cards.i; -import java.util.UUID; - -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; import mage.abilities.hint.common.CardTypesInGraveyardHint; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.FilterSpell; import mage.game.Game; -import mage.game.stack.StackObject; +import mage.game.stack.Spell; import mage.players.Player; import mage.target.TargetSpell; +import java.util.UUID; + /** * @author LevelX2 */ @@ -71,28 +68,12 @@ public InvasiveSurgeryEffect copy() { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { + Spell spell = game.getSpell(getTargetPointer().getFirst(game, source)); + if (controller == null || spell == null) { return false; } - String cardName = ""; - UUID spellController = null; - if (source.getTargets().get(0) instanceof TargetSpell) { - UUID objectId = source.getFirstTarget(); - StackObject stackObject = game.getStack().getStackObject(objectId); - if (stackObject != null) { - MageObject targetObject = game.getObject(stackObject.getSourceId()); - if (targetObject instanceof Card) { - cardName = targetObject.getName(); - } - spellController = stackObject.getControllerId(); - game.getStack().counter(objectId, source, game); - } - } - - // Check the Delirium condition - if (!DeliriumCondition.instance.apply(game, source)) { - return true; - } - return this.applySearchAndExile(game, source, cardName, spellController); + game.getStack().counter(spell.getId(), source, game); + return !DeliriumCondition.instance.apply(game, source) + || this.applySearchAndExile(game, source, spell, spell.getControllerId()); } } diff --git a/Mage.Sets/src/mage/cards/m/MinamosMeddling.java b/Mage.Sets/src/mage/cards/m/MinamosMeddling.java index 1a0ae290801f..5427ef81e3cb 100644 --- a/Mage.Sets/src/mage/cards/m/MinamosMeddling.java +++ b/Mage.Sets/src/mage/cards/m/MinamosMeddling.java @@ -75,7 +75,7 @@ public boolean apply(Game game, Ability source) { for (SpellAbility spellAbility : spell.getSpellAbilities()) { if (spellAbility.getSpellAbilityType() == SpellAbilityType.SPLICE) { for (Card card : spellController.getHand().getCards(game)) { - if (card.getName().equals(spellAbility.getCardName())) { + if (card.hasName(spellAbility.getCardName(), game)) { cardsToDiscard.add(card); } } diff --git a/Mage.Sets/src/mage/cards/n/NissasEncouragement.java b/Mage.Sets/src/mage/cards/n/NissasEncouragement.java index 62083b226ff3..79d639a4bd29 100644 --- a/Mage.Sets/src/mage/cards/n/NissasEncouragement.java +++ b/Mage.Sets/src/mage/cards/n/NissasEncouragement.java @@ -1,6 +1,7 @@ package mage.cards.n; import mage.abilities.Ability; +import mage.abilities.assignment.common.NameAssignment; import mage.abilities.effects.OneShotEffect; import mage.cards.*; import mage.constants.CardType; @@ -13,9 +14,9 @@ import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCardInYourGraveyard; -import java.util.HashMap; -import java.util.Map; +import java.util.Set; import java.util.UUID; /** @@ -28,7 +29,6 @@ public NissasEncouragement(UUID ownerId, CardSetInfo setInfo) { // Search your library and graveyard for a card named Forest, a card named Brambleweft Behemoth, and a card named Nissa, Genesis Mage. Reveal those cards, put them into your hand, then shuffle your library. this.getSpellAbility().addEffect(new NissasEncouragementEffect()); - } private NissasEncouragement(final NissasEncouragement card) { @@ -43,16 +43,11 @@ public NissasEncouragement copy() { class NissasEncouragementEffect extends OneShotEffect { - private static final FilterCard filter = new FilterCard("card named Forest, a card named Brambleweft Behemoth, and a card named Nissa, Genesis Mage"); - private static final FilterCard filterGY = new FilterCard(); - - static { - filter.add(Predicates.or(new NamePredicate("Forest"), new NamePredicate("Brambleweft Behemoth"), new NamePredicate("Nissa, Genesis Mage"))); - } - public NissasEncouragementEffect() { super(Outcome.DrawCard); - this.staticText = "Search your library and graveyard for a card named Forest, a card named Brambleweft Behemoth, and a card named Nissa, Genesis Mage. Reveal those cards, put them into your hand, then shuffle."; + this.staticText = "Search your library and graveyard for a card named Forest, " + + "a card named Brambleweft Behemoth, and a card named Nissa, Genesis Mage. " + + "Reveal those cards, put them into your hand, then shuffle."; } private NissasEncouragementEffect(final NissasEncouragementEffect effect) { @@ -67,95 +62,140 @@ public NissasEncouragementEffect copy() { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Card sourceCard = game.getCard(source.getSourceId()); - if (player == null || sourceCard == null) { + if (player == null) { return false; } - - NissasEncouragementTarget target = new NissasEncouragementTarget(filter); - if (player.searchLibrary(target, source, game)) { - boolean searchGY = false; - - if (target.getTargets().size() < 3) { - searchGY = true; - } - - Map foundCards = new HashMap<>(); - foundCards.put("Forest", 0); - foundCards.put("Brambleweft Behemoth", 0); - foundCards.put("Nissa, Genesis Mage", 0); - Cards cards = new CardsImpl(); - - if (!target.getTargets().isEmpty()) { - for (UUID cardId : target.getTargets()) { - Card card = player.getLibrary().remove(cardId, game); - - if (card != null) { - cards.add(card); - foundCards.put(card.getName(), 1); - } - } - } - - if (searchGY) { - for (String name : foundCards.keySet()) { - if (foundCards.get(name) == 1) { - continue; - } - // Look in graveyard for any with this name - FilterCard namedFilterGY = filterGY.copy(); // never change static objects so copy the object here before - namedFilterGY.add(new NamePredicate(name)); - if (player.getGraveyard().count(namedFilterGY, game) > 0) { - TargetCard targetGY = new TargetCard(0, 1, Zone.GRAVEYARD, namedFilterGY); - if (player.choose(Outcome.ReturnToHand, player.getGraveyard(), targetGY, source, game)) { - for (UUID cardIdGY : targetGY.getTargets()) { - Card cardGY = player.getGraveyard().get(cardIdGY, game); - cards.add(cardGY); - } - } - } - } - } - - if (!cards.isEmpty()) { - player.revealCards(sourceCard.getIdName(), cards, game); - player.moveCards(cards, Zone.HAND, source, game); - player.shuffleLibrary(source, game); - return true; - } + TargetCardInLibrary target = new NissasEncouragementLibraryTarget(); + player.searchLibrary(target, source, game); + Cards cards = new CardsImpl(); + for (UUID targetId : target.getTargets()) { + cards.add(player.getLibrary().getCard(targetId, game)); + } + if (cards.size() < 3) { + TargetCard graveyardTarget = new NissasEncouragementGraveyardTarget(cards); + player.choose(outcome, target, source, game); + cards.addAll(graveyardTarget.getTargets()); + } + if (!cards.isEmpty()) { + player.revealCards(source, cards, game); + player.moveCards(cards, Zone.HAND, source, game); } player.shuffleLibrary(source, game); - return false; + return true; } } -class NissasEncouragementTarget extends TargetCardInLibrary { +class NissasEncouragementLibraryTarget extends TargetCardInLibrary { + + private static final FilterCard filter + = new FilterCard("card named Forest, a card named Brambleweft Behemoth, and a card named Nissa, Genesis Mage"); + + static { + filter.add(Predicates.or( + new NamePredicate("Forest"), + new NamePredicate("Brambleweft Behemoth"), + new NamePredicate("Nissa, Genesis Mage") + )); + } + + private static final NameAssignment nameAssigner = new NameAssignment( + "Forest", "Brambleweft Behemoth", "Nissa, Genesis Mage" + ); - public NissasEncouragementTarget(FilterCard filter) { + public NissasEncouragementLibraryTarget() { super(0, 3, filter); } - private NissasEncouragementTarget(final NissasEncouragementTarget target) { + private NissasEncouragementLibraryTarget(final NissasEncouragementLibraryTarget target) { + super(target); + } + + @Override + public NissasEncouragementLibraryTarget copy() { + return new NissasEncouragementLibraryTarget(this); + } + + @Override + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { + return false; + } + Card card = game.getCard(id); + if (card == null) { + return false; + } + if (this.getTargets().isEmpty()) { + return true; + } + Cards cards = new CardsImpl(this.getTargets()); + cards.add(card); + return nameAssigner.getRoleCount(cards, game) >= cards.size(); + } +} + +class NissasEncouragementGraveyardTarget extends TargetCardInYourGraveyard { + + private static final FilterCard filter + = new FilterCard("card named Forest, a card named Brambleweft Behemoth, and a card named Nissa, Genesis Mage"); + + static { + filter.add(Predicates.or( + new NamePredicate("Forest"), + new NamePredicate("Brambleweft Behemoth"), + new NamePredicate("Nissa, Genesis Mage") + )); + } + + private final Cards cardsAlreadyFound = new CardsImpl(); + private static final NameAssignment nameAssigner = new NameAssignment( + "Forest", "Brambleweft Behemoth", "Nissa, Genesis Mage" + ); + + public NissasEncouragementGraveyardTarget(Cards cardsAlreadyFound) { + super(0, 3, filter, true); + this.cardsAlreadyFound.addAll(cardsAlreadyFound); + } + + private NissasEncouragementGraveyardTarget(final NissasEncouragementGraveyardTarget target) { super(target); + this.cardsAlreadyFound.addAll(target.cardsAlreadyFound); + } + + @Override + public NissasEncouragementGraveyardTarget copy() { + return new NissasEncouragementGraveyardTarget(this); } @Override - public NissasEncouragementTarget copy() { - return new NissasEncouragementTarget(this); + public boolean canTarget(UUID playerId, UUID id, Ability source, Game game) { + if (!super.canTarget(playerId, id, source, game)) { + return false; + } + Card card = game.getCard(id); + if (card == null) { + return false; + } + if (this.getTargets().isEmpty()) { + return true; + } + Cards cards = new CardsImpl(this.getTargets()); + cards.addAll(this.cardsAlreadyFound); + cards.add(card); + return nameAssigner.getRoleCount(cards, game) >= cards.size(); } @Override - public boolean canTarget(UUID playerId, UUID id, Ability source, Cards cards, Game game) { - Card card = cards.get(id, game); - if (card != null) { - for (UUID targetId : this.getTargets()) { - Card iCard = game.getCard(targetId); - if (iCard != null && iCard.getName().equals(card.getName())) { - return false; - } - } - return filter.match(card, playerId, game); + public Set possibleTargets(UUID sourceControllerId, Ability source, Game game) { + Set possibleTargets = super.possibleTargets(sourceControllerId, source, game); + if (this.getTargets().isEmpty()) { + return possibleTargets; } - return false; + possibleTargets.removeIf(uuid -> { + Cards cards = new CardsImpl(this.getTargets()); + cards.addAll(this.cardsAlreadyFound); + cards.add(game.getCard(uuid)); + return nameAssigner.getRoleCount(cards, game) < cards.size(); + }); + return possibleTargets; } } diff --git a/Mage.Sets/src/mage/cards/p/PickTheBrain.java b/Mage.Sets/src/mage/cards/p/PickTheBrain.java index 73b8dd0c9e74..e7fe9e7044fd 100644 --- a/Mage.Sets/src/mage/cards/p/PickTheBrain.java +++ b/Mage.Sets/src/mage/cards/p/PickTheBrain.java @@ -1,9 +1,6 @@ package mage.cards.p; -import java.util.UUID; - import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; import mage.abilities.hint.common.CardTypesInGraveyardHint; @@ -19,6 +16,8 @@ import mage.target.TargetCard; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ @@ -65,26 +64,21 @@ public PickTheBrainEffect copy() { @Override public boolean apply(Game game, Ability source) { - Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - if (opponent != null && controller != null) { - if (!opponent.getHand().isEmpty()) { - opponent.revealCards("Exile " + StaticFilters.FILTER_CARD_A_NON_LAND.getMessage(), opponent.getHand(), game); - TargetCard target = new TargetCard(Zone.HAND, StaticFilters.FILTER_CARD_A_NON_LAND); - if (controller.choose(Outcome.Exile, opponent.getHand(), target, source, game)) { - Card card = opponent.getHand().get(target.getFirstTarget(), game); - if (card != null) { - controller.moveCardToExileWithInfo(card, null, "", source, game, Zone.HAND, true); - - // Check the Delirium condition - if (!DeliriumCondition.instance.apply(game, source)) { - return true; - } - return this.applySearchAndExile(game, source, card.getName(), opponent.getId()); - } - } - } + Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (controller == null || opponent == null || opponent.getHand().isEmpty()) { + return false; + } + opponent.revealCards("Exile " + StaticFilters.FILTER_CARD_A_NON_LAND.getMessage(), opponent.getHand(), game); + TargetCard target = new TargetCard(Zone.HAND, StaticFilters.FILTER_CARD_A_NON_LAND); + controller.choose(Outcome.Exile, opponent.getHand(), target, source, game); + Card card = opponent.getHand().get(target.getFirstTarget(), game); + if (card == null) { + return false; } - return false; + controller.moveCards(card, Zone.EXILED, source, game); + // Check the Delirium condition + return !DeliriumCondition.instance.apply(game, source) + || this.applySearchAndExile(game, source, card, opponent.getId()); } } diff --git a/Mage.Sets/src/mage/cards/p/PompousGadabout.java b/Mage.Sets/src/mage/cards/p/PompousGadabout.java index fbb62bc92198..4c836e00be0f 100644 --- a/Mage.Sets/src/mage/cards/p/PompousGadabout.java +++ b/Mage.Sets/src/mage/cards/p/PompousGadabout.java @@ -65,6 +65,6 @@ enum PompousGadaboutPredicate implements Predicate { @Override public boolean apply(Permanent input, Game game) { - return input.getName() == null || input.getName().isEmpty(); + return input.hasNoName(game); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/SceptreOfEternalGlory.java b/Mage.Sets/src/mage/cards/s/SceptreOfEternalGlory.java index 7260eeb87151..3ec04dafb7c1 100644 --- a/Mage.Sets/src/mage/cards/s/SceptreOfEternalGlory.java +++ b/Mage.Sets/src/mage/cards/s/SceptreOfEternalGlory.java @@ -1,7 +1,5 @@ package mage.cards.s; -import com.google.common.base.Functions; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.condition.Condition; import mage.abilities.costs.common.TapSourceCost; @@ -15,9 +13,12 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.RandomUtil; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; /** * @author TheElk801 @@ -54,22 +55,25 @@ enum SceptreOfEternalGloryCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - return game - .getBattlefield() - .getActivePermanents( - StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, - source.getControllerId(), source, game - ) - .stream() - .map(MageObject::getName) - .filter(s -> !s.isEmpty()) - .collect(Collectors.toMap( - Functions.identity(), - x -> 1, Integer::sum - )) - .values() - .stream() - .anyMatch(x -> x >= 3); + Set lands = new HashSet<>(game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, + 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; + } + } + } + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java b/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java index af8ef841e101..cfbf00940519 100644 --- a/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java +++ b/Mage.Sets/src/mage/cards/s/SpellweaverHelix.java @@ -1,29 +1,32 @@ package mage.cards.s; +import mage.MageItem; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; +import mage.abilities.effects.common.ExileTargetCardCopyAndCastEffect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.cards.*; import mage.constants.AbilityWord; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.Player; +import mage.target.TargetCard; import mage.target.common.TargetCardInASingleGraveyard; +import mage.target.common.TargetCardInExile; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; -import java.util.UUID; -import mage.ApprovingObject; +import java.util.*; +import java.util.stream.Collectors; /** * @author emerald000 @@ -40,7 +43,7 @@ public SpellweaverHelix(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // Imprint - When Spellweaver Helix enters the battlefield, you may exile two target sorcery cards from a single graveyard. - Ability ability = new EntersBattlefieldTriggeredAbility(new SpellweaverHelixImprintEffect(), true); + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect(), true); ability.addTarget(new TargetCardInASingleGraveyard(2, 2, filter)); ability.setAbilityWord(AbilityWord.IMPRINT); this.addAbility(ability); @@ -59,42 +62,6 @@ public SpellweaverHelix copy() { } } -class SpellweaverHelixImprintEffect extends OneShotEffect { - - SpellweaverHelixImprintEffect() { - super(Outcome.Exile); - this.staticText = "you may exile two target sorcery cards from a single graveyard"; - } - - private SpellweaverHelixImprintEffect(final SpellweaverHelixImprintEffect effect) { - super(effect); - } - - @Override - public SpellweaverHelixImprintEffect copy() { - return new SpellweaverHelixImprintEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { - Card card = game.getCard(targetId); - if (card != null) { - controller.moveCardsToExile(card, source, game, true, CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()), source.getSourceObject(game).getIdName()); - if (sourcePermanent != null) { - sourcePermanent.imprint(targetId, game); - } - } - } - return true; - } - return false; - } -} - class SpellweaverHelixTriggeredAbility extends TriggeredAbilityImpl { SpellweaverHelixTriggeredAbility() { @@ -118,44 +85,41 @@ public boolean checkEventType(GameEvent event, Game game) { @Override public boolean checkTrigger(GameEvent event, Game game) { Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && spell.getCard() != null && !spell.getCard().isCopy()) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(spell.getId())); - } - return true; + if (spell == null || spell.getCard() == null || spell.getCard().isCopy()) { + return false; } - return false; + this.getEffects().setValue("spellCast", spell); + return true; } @Override public boolean checkInterveningIfClause(Game game) { - Spell spell = game.getStack().getSpell(this.getEffects().get(0).getTargetPointer().getFirst(game, this)); - if (spell != null) { - String spellName = spell.getName(); - Permanent sourcePermanent = game.getPermanent(this.getSourceId()); - if (sourcePermanent != null) { - for (UUID imprintId : sourcePermanent.getImprinted()) { - Card card = game.getCard(imprintId); - if (card != null && card.getName().equals(spellName)) { - ((SpellweaverHelixCastEffect) this.getEffects().get(0)).setSpellName(spellName); - return true; - } - } - } - } - return false; + Spell spell = this + .getEffects() + .stream() + .map(effect -> (Spell) effect.getValue("spellCast")) + .findFirst() + .orElse(null); + return spell != null + && Optional.ofNullable(game) + .map(Game::getExile) + .map(exile -> exile.getExileZone(CardUtil.getExileZoneId(game, this))) + .filter(Objects::nonNull) + .map(e -> e.getCards(game)) + .map(Collection::stream) + .map(s -> s.anyMatch(card -> card.sharesName(spell, game))) + .orElse(false); } @Override public String getRule() { - return "Whenever a player casts a card, if it has the same name as one of the cards exiled with Spellweaver Helix, you may copy the other. If you do, you may cast the copy without paying its mana cost."; + return "Whenever a player casts a card, if it has the same name as one of the cards exiled with {this}, " + + "you may copy the other. If you do, you may cast the copy without paying its mana cost."; } } class SpellweaverHelixCastEffect extends OneShotEffect { - private String spellName = ""; - SpellweaverHelixCastEffect() { super(Outcome.Benefit); this.staticText = "you may copy the other. If you do, you may cast the copy without paying its mana cost"; @@ -163,7 +127,6 @@ class SpellweaverHelixCastEffect extends OneShotEffect { private SpellweaverHelixCastEffect(final SpellweaverHelixCastEffect effect) { super(effect); - this.spellName = effect.spellName; } @Override @@ -171,38 +134,39 @@ public SpellweaverHelixCastEffect copy() { return new SpellweaverHelixCastEffect(this); } - public void setSpellName(String spellName) { - this.spellName = spellName; - } - @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (sourcePermanent != null) { - boolean foundSpellWithSameName = false; - for (UUID imprintId : sourcePermanent.getImprinted()) { - Card card = game.getCard(imprintId); - if (card != null) { - if (!foundSpellWithSameName && card.getName().equals(spellName)) { - foundSpellWithSameName = true; - } else { - if (controller.chooseUse(Outcome.Copy, "Copy " + card.getIdName(), source, game)) { - Card copy = game.copyCard(card, source, source.getControllerId()); - if (controller.chooseUse(Outcome.PlayForFree, "Cast " + copy.getIdName() + " without paying its mana cost?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + copy.getId(), Boolean.TRUE); - controller.cast(controller.chooseAbilityForCast(copy, game, true), - game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + copy.getId(), null); - } - } - } - } - } - } - return true; + Player player = game.getPlayer(source.getControllerId()); + Spell spell = (Spell) getValue("spellCast"); + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + if (player == null || spell == null || exileZone == null || exileZone.isEmpty()) { + return false; + } + Cards cards = new CardsImpl(exileZone); + Set matching = exileZone + .getCards(game) + .stream() + .filter(card -> card.sharesName(spell, game)) + .map(MageItem::getId) + .collect(Collectors.toSet()); + if (matching.size() < 2) { // If two or more cards match then all cards are valid choices + cards.removeAll(matching); + } + Card card; + switch (cards.size()) { + case 0: + return false; + case 1: + card = cards.getRandom(game); + break; + default: + TargetCard target = new TargetCardInExile(0, 1, StaticFilters.FILTER_CARD); + player.choose(outcome, cards, target, source, game); + card = cards.get(target.getFirstTarget(), game); } - return false; + return card != null + && new ExileTargetCardCopyAndCastEffect(true, true) + .setTargetPointer(new FixedTarget(card, game)) + .apply(game, source); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ProteanHydraTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ProteanHydraTest.java index 17a56f1223a0..16cf5dd2c914 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ProteanHydraTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/ProteanHydraTest.java @@ -8,7 +8,6 @@ import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author noxx */ public class ProteanHydraTest extends CardTestPlayerBase { @@ -31,7 +30,7 @@ public void testEnteringWithCounters() { assertLife(playerB, 20); for (Permanent permanent : currentGame.getBattlefield().getAllPermanents()) { - if (permanent.getName().equals("Forest")) { + if (permanent.hasName("Forest", currentGame)) { // check all mana was spent Assert.assertTrue(permanent.isTapped()); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DisguiseTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DisguiseTest.java index 5a168aaca667..cf4e984f4b05 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DisguiseTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DisguiseTest.java @@ -76,7 +76,7 @@ public void test_NormalPlay_ClientData_CostRulesVisible() { .findFirst() .orElse(null); Assert.assertNotNull("server side: can't find disguised permanent", permanent); - Assert.assertEquals("server side: wrong name", EmptyNames.FACE_DOWN_CREATURE.toString(), permanent.getName()); + Assert.assertTrue("server side: wrong name", permanent.hasNoName(currentGame)); Assert.assertEquals("server side: wrong color", "", permanent.getColor(currentGame).toString()); Assert.assertEquals("server side: wrong power", "2", permanent.getPower().toString()); Assert.assertEquals("server side: wrong toughness", "2", permanent.getToughness().toString()); @@ -150,11 +150,11 @@ public void test_NormalPlay_ClientData_CostRulesVisible() { runCode("after face up", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> { Permanent permanent = currentGame.getBattlefield().getAllPermanents() .stream() - .filter(p -> p.getName().equals("Dog Walker")) + .filter(p -> p.hasName("Dog Walker", game)) .findFirst() .orElse(null); Assert.assertNotNull("server side: can't find normal permanent", permanent); - Assert.assertEquals("server side: wrong name", "Dog Walker", permanent.getName()); + Assert.assertTrue("server side: wrong name", permanent.hasName("Dog Walker", currentGame)); Assert.assertEquals("server side: wrong color", "WR", permanent.getColor(currentGame).toString()); Assert.assertEquals("server side: wrong power", "3", permanent.getPower().toString()); Assert.assertEquals("server side: wrong toughness", "1", permanent.getToughness().toString()); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DisturbTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DisturbTest.java index 31c9ba2e1041..da3479bc4a35 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DisturbTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/DisturbTest.java @@ -17,10 +17,10 @@ public class DisturbTest extends CardTestPlayerBase { /** * Relevant ruling: - * - When you cast a spell using a card's disturb ability, the card is put onto the stack with its - * back face up. The resulting spell has all the characteristics of that face. - * - The mana value of a spell cast using disturb is determined by the mana cost on the - * front face of the card, no matter what the total cost to cast the spell was. + * - When you cast a spell using a card's disturb ability, the card is put onto the stack with its + * back face up. The resulting spell has all the characteristics of that face. + * - The mana value of a spell cast using disturb is determined by the mana cost on the + * front face of the card, no matter what the total cost to cast the spell was. */ @Test public void test_SpellAttributesOnStack() { @@ -41,7 +41,7 @@ public void test_SpellAttributesOnStack() { runCode("check stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { // Stack must contain another card side, so spell/card characteristics must be diff from main side (only mana value is same) Spell spell = (Spell) game.getStack().getFirst(); - Assert.assertEquals("Hook-Haunt Drifter", spell.getName()); + Assert.assertTrue(spell.hasName("Hook-Haunt Drifter", currentGame)); Assert.assertEquals(1, spell.getCardType(game).size()); Assert.assertEquals(CardType.CREATURE, spell.getCardType(game).get(0)); Assert.assertEquals(1, spell.getSubtype(game).size()); @@ -92,7 +92,7 @@ public void test_SpellAttributesOnStack2() { runCode("check stack", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { // Stack must contain another card side, so spell/card characteristics must be diff from main side (only mana value is same) Spell spell = (Spell) game.getStack().getFirst(); - Assert.assertEquals("Waildrifter", spell.getName()); + Assert.assertTrue(spell.hasName("Waildrifter", currentGame)); Assert.assertEquals(1, spell.getCardType(game).size()); Assert.assertEquals(CardType.CREATURE, spell.getCardType(game).get(0)); Assert.assertEquals(2, spell.getSubtype(game).size()); @@ -122,7 +122,7 @@ public void test_SpellAttributesOnStack2() { setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); execute(); - assertTappedCount("Volcanic Island",true,6); //5+1 + assertTappedCount("Volcanic Island", true, 6); //5+1 } @Test @@ -133,7 +133,7 @@ public void test_SpellAttributesTrigger() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 7); addCard(Zone.BATTLEFIELD, playerA, "Firebrand Archer", 1); // - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Sinner's Judgment using Disturb",playerB); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Sinner's Judgment using Disturb", playerB); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -163,12 +163,12 @@ public void test_SpellAttributesIndirectTrigger() { /** * Relevant ruling: - * To determine the total cost of a spell, start with the mana cost or alternative cost - * (such as a disturb cost) you're paying, add any cost increases, then apply any cost - * reductions. The mana value of a spell cast using disturb is determined by the mana cost on - * the front face of the card, no matter what the total cost to cast the spell was. (This is - * a special rule that applies only to transforming double faced-cards, including ones with - * disturb.) + * To determine the total cost of a spell, start with the mana cost or alternative cost + * (such as a disturb cost) you're paying, add any cost increases, then apply any cost + * reductions. The mana value of a spell cast using disturb is determined by the mana cost on + * the front face of the card, no matter what the total cost to cast the spell was. (This is + * a special rule that applies only to transforming double faced-cards, including ones with + * disturb.) */ @Test public void test_CostModification_CanPlay() { @@ -230,7 +230,7 @@ public void test_ConditionalCostModifications() { //net -2 // - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Sinner's Judgment using Disturb",playerB); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Sinner's Judgment using Disturb", playerB); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); @@ -262,8 +262,8 @@ public void test_SpellAttributesIndirectCostModifications() { /** * Relevant rule: - * If you copy a permanent spell cast this way (perhaps with a card like Double Major), the copy becomes - * a token that's a copy of the card's back face, even though it isn't itself a double-faced card. + * If you copy a permanent spell cast this way (perhaps with a card like Double Major), the copy becomes + * a token that's a copy of the card's back face, even though it isn't itself a double-faced card. */ @Test public void test_CopySpell() { @@ -297,10 +297,10 @@ public void test_CopySpell() { /** * Relevant ruling: - * The back face of each card with disturb has an ability that instructs its controller to exile - * if it would be put into a graveyard from anywhere. This includes going to the graveyard from the - * stack, so if the spell is countered after you cast it using the disturb ability, it will - * be put into exile. + * The back face of each card with disturb has an ability that instructs its controller to exile + * if it would be put into a graveyard from anywhere. This includes going to the graveyard from the + * stack, so if the spell is countered after you cast it using the disturb ability, it will + * be put into exile. */ @Test public void test_Counter() { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/HauntTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/HauntTest.java index 3da1ca040ff4..2eb05c17fc6d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/HauntTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/HauntTest.java @@ -9,7 +9,6 @@ import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author BetaSteward */ public class HauntTest extends CardTestPlayerBase { @@ -21,13 +20,12 @@ public class HauntTest extends CardTestPlayerBase { * Flying * Haunt (When this creature dies, exile it haunting target creature.) * When Blind Hunter enters the battlefield or the creature it haunts dies, target player loses 2 life and you gain 2 life. - * */ - + // test that Haunting and Haunted by rules are added to cards @Test public void testAddHaunt() { - + addCard(Zone.BATTLEFIELD, playerA, "Blind Hunter", 1); addCard(Zone.BATTLEFIELD, playerA, "Goblin Roughrider"); addCard(Zone.HAND, playerA, "Lightning Bolt", 1); @@ -40,12 +38,12 @@ public void testAddHaunt() { assertGraveyardCount(playerA, "Lightning Bolt", 1); assertExileCount("Blind Hunter", 1); - + boolean found = false; for (Card card : currentGame.getExile().getAllCards(currentGame)) { - if (card.getName().equals("Blind Hunter")) { + if (card.hasName("Blind Hunter", currentGame)) { for (String rule : card.getRules(currentGame)) { - if (rule.startsWith("Haunting") && rule.contains("Goblin Roughrider")) { + if (rule.startsWith("Haunting") && rule.contains("Goblin Roughrider")) { found = true; break; } @@ -56,7 +54,7 @@ public void testAddHaunt() { found = false; for (Card card : currentGame.getBattlefield().getAllActivePermanents()) { - if (card.getName().equals("Goblin Roughrider")) { + if (card.hasName("Goblin Roughrider", currentGame)) { for (String rule : card.getRules(currentGame)) { if (rule.startsWith("Haunted by") && rule.contains("Blind Hunter")) { found = true; @@ -66,13 +64,13 @@ public void testAddHaunt() { } } Assert.assertTrue("Couldn't find Haunted by rule text displayed for the card", found); - + } // test that Haunted by rule is removed from cards (it is only added to permanent) @Test public void testRemoveHaunt() { - + addCard(Zone.BATTLEFIELD, playerA, "Blind Hunter", 1); addCard(Zone.BATTLEFIELD, playerA, "Goblin Roughrider"); addCard(Zone.HAND, playerA, "Lightning Bolt", 2); @@ -91,7 +89,7 @@ public void testRemoveHaunt() { boolean found = false; for (Card card : currentGame.getPlayer(playerA.getId()).getGraveyard().getCards(currentGame)) { - if (card.getName().equals("Goblin Roughrider")) { + if (card.hasName("Goblin Roughrider", currentGame)) { for (String rule : card.getRules(currentGame)) { if (rule.startsWith("Haunted by") && rule.contains("Blind Hunter")) { found = true; @@ -101,7 +99,7 @@ public void testRemoveHaunt() { } } Assert.assertFalse("Found Haunted by rule text displayed for the card", found); - + } @Test @@ -122,5 +120,5 @@ public void testHauntToken() { assertExileCount("Blind Hunter", 1); assertLife(playerA, 22); } - + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java index b3acdef25d59..58609af216e8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java @@ -1,6 +1,5 @@ package org.mage.test.cards.abilities.keywords; -import mage.MageObject; import mage.cards.Card; import mage.cards.repository.TokenRepository; import mage.constants.EmptyNames; @@ -149,14 +148,14 @@ private void runManifestThenBlink(String cardToManifest, String cardAfterBlink) Assert.assertEquals("after blink card must keep in exile", 1, currentGame.getExile().getAllCardsByRange(currentGame, playerA.getId()).size()); } else { - String realPermanentName = currentGame.getBattlefield().getAllPermanents() + Permanent realPermanent = currentGame + .getBattlefield() + .getAllPermanents() .stream() - .map(MageObject::getName) - .filter(name -> name.equals(cardAfterBlink)) + .filter(permanent -> permanent.hasName(cardAfterBlink, currentGame)) .findFirst() .orElse(null); - Assert.assertEquals("after blink card must go to battlefield", - cardAfterBlink, realPermanentName); + Assert.assertNotNull("after blink card must go to battlefield", realPermanent); } }); @@ -428,8 +427,8 @@ public void testCardGetsExiledFaceUp() { assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); for (Card card : currentGame.getExile().getAllCards(currentGame)) { - if (card.getName().equals("Gore Swine")) { - Assert.assertTrue("Gore Swine may not be face down in exile", !card.isFaceDown(currentGame)); + if (card.hasName("Gore Swine", currentGame)) { + Assert.assertFalse("Gore Swine may not be face down in exile", card.isFaceDown(currentGame)); } } @@ -731,7 +730,7 @@ private PermanentView findFaceDownPermanent(Game game, TestPlayer viewFromPlayer .stream() .filter(permanent -> permanent.isFaceDown(game)) .filter(permanent -> { - Assert.assertEquals("face down permanent must have not name", "", permanent.getName()); + Assert.assertTrue("face down permanent must have not name", permanent.hasNoName(currentGame)); // TODO: buggy, manifested card must have some rules //Assert.assertTrue("face down permanent must have abilities", permanent.getAbilities().size() > 0); return true; @@ -739,7 +738,7 @@ private PermanentView findFaceDownPermanent(Game game, TestPlayer viewFromPlayer .findFirst() .orElse(null); Assert.assertNotNull(perm); - Assert.assertEquals("server side face down permanent must have empty name", EmptyNames.FACE_DOWN_CREATURE.toString(), perm.getName()); + Assert.assertTrue("server side face down permanent must have empty name", perm.hasNoName(currentGame)); GameView gameView = new GameView(game.getState(), game, viewFromPlayer.getId(), null); PlayerView playerView = gameView.getPlayers() .stream() @@ -836,8 +835,8 @@ public void testJeskaiInfiltrator() { attack(1, playerA, infiltrator, playerB); - checkPlayableAbility("missionary manifest",1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{1}{W}: Turn ", true); - checkPlayableAbility("infiltrator manifest",1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}{U}: Turn ", true); + checkPlayableAbility("missionary manifest", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{1}{W}: Turn ", true); + checkPlayableAbility("infiltrator manifest", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}{U}: Turn ", true); setStrictChooseMode(true); setStopAt(1, PhaseStep.END_TURN); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java index 40327de77d7c..80ecdce4f928 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java @@ -422,7 +422,7 @@ public void testExileFaceDownCreature() { assertExileCount("Birchlore Rangers", 1); for (Card card : currentGame.getExile().getAllCards(currentGame)) { - if (card.getName().equals("Birchlore Rangers")) { + if (card.hasName("Birchlore Rangers", currentGame)) { Assert.assertFalse("Birchlore Rangers has to be face up in exile", card.isFaceDown(currentGame)); break; } @@ -461,7 +461,7 @@ public void testDiesTriggeredDoesNotTriggerIfFaceDown() { assertGraveyardCount(playerA, "Ashcloud Phoenix", 1); for (Card card : playerA.getGraveyard().getCards(currentGame)) { - if (card.getName().equals("Ashcloud Phoenix")) { + if (card.hasName("Ashcloud Phoenix", currentGame)) { Assert.assertFalse("Ashcloud Phoenix has to be face up in graveyard", card.isFaceDown(currentGame)); break; } @@ -497,7 +497,7 @@ public void testDiesTriggeredDoesNotTriggerInCombatIfFaceDown() { assertGraveyardCount(playerA, "Ashcloud Phoenix", 1); for (Card card : playerA.getGraveyard().getCards(currentGame)) { - if (card.getName().equals("Ashcloud Phoenix")) { + if (card.hasName("Ashcloud Phoenix", currentGame)) { Assert.assertFalse("Ashcloud Phoenix has to be face up in graveyard", card.isFaceDown(currentGame)); break; } @@ -1236,7 +1236,7 @@ private void assertMorphedFaceDownColor(String info, String needColor) { .findFirst() .orElse(null); Assert.assertNotNull(info + ", server side: can't find morphed permanent", permanent); - Assert.assertEquals(info + ", server side: wrong name", EmptyNames.FACE_DOWN_CREATURE.toString(), permanent.getName()); + Assert.assertTrue(info + ", server side: wrong name", permanent.hasNoName(currentGame)); Assert.assertEquals(info + ", server side: wrong color", needColor, permanent.getColor(currentGame).toString()); // client side - controller @@ -1299,7 +1299,7 @@ public void test_Morph_MustGetColor() { public void test_Morph_HoodedHydra() { // Morph {2} addCard(Zone.HAND, playerA, "Hooded Hydra"); - addCard(Zone.BATTLEFIELD, playerA, "Forest", 3+5); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 3 + 5); // prepare face down castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hooded Hydra using Morph"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/OffspringTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/OffspringTest.java index bb7b1fc91786..ecdb49e231ab 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/OffspringTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/OffspringTest.java @@ -17,7 +17,7 @@ public class OffspringTest extends CardTestPlayerBase { private Permanent getCreature(String name, boolean isToken) { for (Permanent permanent : currentGame.getBattlefield().getActivePermanents(playerA.getId(), currentGame)) { - if (name.equals(permanent.getName()) && (permanent instanceof PermanentToken) == isToken) { + if (permanent.hasName(name, currentGame) && (permanent instanceof PermanentToken) == isToken) { return permanent; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PoisonousTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PoisonousTest.java index 78783f10f112..7be84d6248cd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PoisonousTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PoisonousTest.java @@ -23,7 +23,7 @@ public void assertMultipleInstancesOfAbility(Player player, String cardName, Abi int permanentCount = 0; Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(player.getId())) { - if (permanent.getName().equals(cardName)) { + if (permanent.hasName(cardName, currentGame)) { found = permanent; permanentCount++; } @@ -46,8 +46,6 @@ public void assertMultipleInstancesOfAbility(Player player, String cardName, Abi } - - @Test public void testNormalCombatDamageIsDealt() { // Virulent Sliver gives all slivers Poisonous 1 diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PrototypeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PrototypeTest.java index 26edf9e5db8b..09c98d211500 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PrototypeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/PrototypeTest.java @@ -26,7 +26,7 @@ public class PrototypeTest extends CardTestPlayerBase { // Prototype {2}{R} - 3/2 private static final String automaton = "Blitz Automaton"; private static final String withPrototype = " using Prototype"; - private static final String automatonWithPrototype = automaton+withPrototype; + private static final String automatonWithPrototype = automaton + withPrototype; private static final String bolt = "Lightning Bolt"; private static final String cloudshift = "Cloudshift"; @@ -44,7 +44,7 @@ private void checkAutomaton(boolean prototyped, int count) { for (Permanent permanent : currentGame.getBattlefield().getActivePermanents( StaticFilters.FILTER_PERMANENT, playerA.getId(), currentGame )) { - if (!permanent.getName().equals(automaton)) { + if (!permanent.hasName(automaton, currentGame)) { continue; } Assert.assertTrue("Needs haste", permanent.getAbilities(currentGame).contains(HasteAbility.getInstance())); @@ -120,7 +120,7 @@ public void testLeavesBattlefield() { .getGraveyard() .getCards(currentGame) .stream() - .filter(c -> c.getName().equals(automaton)) + .filter(c -> c.hasName(automaton, currentGame)) .findFirst() .orElse(null); Assert.assertTrue("Card should be colorless", card.getColor(currentGame).isColorless()); @@ -452,9 +452,9 @@ public void testManaValueWhenCasting() { playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Taiga"); //checkPlayableAbility("cast even proto", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast Boulderbranch Golem"+withPrototype, false); - checkPlayableAbility("cast odd proto", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast Fallaji Dragon Engine"+withPrototype, true); + checkPlayableAbility("cast odd proto", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast Fallaji Dragon Engine" + withPrototype, true); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, evenRegOddProto+withPrototype); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, evenRegOddProto + withPrototype); setStopAt(1, PhaseStep.END_TURN); setStrictChooseMode(true); @@ -462,9 +462,10 @@ public void testManaValueWhenCasting() { assertPowerToughness(playerA, evenRegOddProto, 1, 3); } + @Test public void testCopyOnStack() { - addCard(Zone.BATTLEFIELD, playerA, "Frontier Bivouac", 3+2); + addCard(Zone.BATTLEFIELD, playerA, "Frontier Bivouac", 3 + 2); addCard(Zone.HAND, playerA, automaton); addCard(Zone.HAND, playerA, "Double Major"); @@ -477,9 +478,10 @@ public void testCopyOnStack() { checkAutomaton(true, 2); } + @Test public void testHumility() { - addCard(Zone.BATTLEFIELD, playerA, "Plateau", 4+3+2); + addCard(Zone.BATTLEFIELD, playerA, "Plateau", 4 + 3 + 2); addCard(Zone.HAND, playerA, automaton); addCard(Zone.HAND, playerA, "Humility"); addCard(Zone.HAND, playerA, "Disenchant"); @@ -498,6 +500,7 @@ public void testHumility() { checkAutomaton(true); } + @Test public void testColorCostReduction() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); @@ -513,6 +516,7 @@ public void testColorCostReduction() { checkAutomaton(true); assertTappedCount("Mountain", true, 2); } + @Test public void testAbilityRemovalPre() { addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 5); @@ -528,6 +532,7 @@ public void testAbilityRemovalPre() { assertPowerToughness(playerA, automaton, 3, 2); } + @Test public void testAbilityRemovalPost() { addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 5); @@ -543,6 +548,7 @@ public void testAbilityRemovalPost() { assertPowerToughness(playerA, automaton, 3, 2); } + @Test public void testEssenceOfWild() { addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 5); @@ -559,6 +565,7 @@ public void testEssenceOfWild() { assertPermanentCount(playerA, "Essence of the Wild", 2); } + @Test public void testChainer() { addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 3); @@ -577,9 +584,10 @@ public void testChainer() { checkAutomaton(true); } + @Test public void testMetamorphCopyA() { - addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 3+9); + addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 3 + 9); addCard(Zone.HAND, playerA, automaton); addCard(Zone.HAND, playerA, "Hulking Metamorph"); @@ -596,15 +604,16 @@ public void testMetamorphCopyA() { assertPowerToughness(playerA, automaton, 3, 2); assertPowerToughness(playerA, automaton, 7, 7); } + @Test public void testMetamorphCopyB() { - addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 7+4); + addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 7 + 4); addCard(Zone.HAND, playerA, automaton); addCard(Zone.HAND, playerA, "Hulking Metamorph"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, automaton); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Hulking Metamorph"+withPrototype); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Hulking Metamorph" + withPrototype); setChoice(playerA, true); setChoice(playerA, automaton); @@ -615,9 +624,10 @@ public void testMetamorphCopyB() { assertPowerToughness(playerA, automaton, 6, 4); assertPowerToughness(playerA, automaton, 3, 3); } + @Test public void testReflectionA() { - addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 3+6+6); + addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 3 + 6 + 6); addCard(Zone.HAND, playerA, automaton); addCard(Zone.HAND, playerA, "Goring Warplow"); addCard(Zone.HAND, playerA, "Infinite Reflection"); @@ -634,9 +644,10 @@ public void testReflectionA() { checkAutomaton(true, 2); } + @Test public void testReflectionB() { - addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 7+6+2); + addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 7 + 6 + 2); addCard(Zone.HAND, playerA, automaton); addCard(Zone.HAND, playerA, "Goring Warplow"); addCard(Zone.HAND, playerA, "Infinite Reflection"); @@ -645,7 +656,7 @@ public void testReflectionB() { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, automaton); waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Infinite Reflection", automaton); - castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Goring Warplow"+withPrototype); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Goring Warplow" + withPrototype); setStopAt(1, PhaseStep.END_TURN); setStrictChooseMode(true); @@ -653,9 +664,10 @@ public void testReflectionB() { checkAutomaton(false, 2); } + @Test public void testProgenitor() { - addCard(Zone.BATTLEFIELD, playerA, "Frontier Bivouac", 3+6); + addCard(Zone.BATTLEFIELD, playerA, "Frontier Bivouac", 3 + 6); addCard(Zone.HAND, playerA, automaton); addCard(Zone.HAND, playerA, "Progenitor Mimic"); @@ -671,9 +683,10 @@ public void testProgenitor() { checkAutomaton(true, 3); } + @Test public void testInstantaneousLKI() { - addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 3+2); + addCard(Zone.BATTLEFIELD, playerA, "Volcanic Island", 3 + 2); addCard(Zone.BATTLEFIELD, playerA, "Flowstone Surge", 2); addCard(Zone.BATTLEFIELD, playerA, "Drizzt Do'Urden", 1); addCard(Zone.BATTLEFIELD, playerA, "Warstorm Surge", 1); @@ -681,7 +694,7 @@ public void testInstantaneousLKI() { addCard(Zone.HAND, playerA, "Slimebind"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Slimebind", "Drizzt Do'Urden"); - checkPT("Drizzt is shrunk",1, PhaseStep.BEGIN_COMBAT, playerA, "Drizzt Do'Urden",1, 1); + checkPT("Drizzt is shrunk", 1, PhaseStep.BEGIN_COMBAT, playerA, "Drizzt Do'Urden", 1, 1); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, automatonWithPrototype); // 5/0 setChoice(playerA, "Whenever a creature you control enters"); //Stack the trigger addTarget(playerA, playerB); @@ -692,11 +705,12 @@ public void testInstantaneousLKI() { assertPowerToughness(playerA, "Drizzt Do'Urden", 5, 5); assertGraveyardCount(playerA, automaton, 1); - assertLife(playerB, 20-5); + assertLife(playerB, 20 - 5); } + @Test public void testReanimate() { - addCard(Zone.BATTLEFIELD, playerA, "Badlands", 3+1+1); + addCard(Zone.BATTLEFIELD, playerA, "Badlands", 3 + 1 + 1); addCard(Zone.HAND, playerA, automaton); addCard(Zone.HAND, playerA, "Cut Down"); addCard(Zone.HAND, playerA, "Reanimate"); @@ -710,7 +724,7 @@ public void testReanimate() { execute(); checkAutomaton(false); - assertLife(playerA, 20-7); + assertLife(playerA, 20 - 7); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/library/PutToLibraryTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/library/PutToLibraryTest.java index 6867ebb0182b..2b2a7e813f59 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/library/PutToLibraryTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/library/PutToLibraryTest.java @@ -1,6 +1,5 @@ package org.mage.test.cards.abilities.oneshot.library; -import java.util.ArrayList; import mage.cards.Card; import mage.constants.PhaseStep; import mage.constants.Zone; @@ -8,8 +7,9 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; +import java.util.ArrayList; + /** - * * @author LevelX2 */ public class PutToLibraryTest extends CardTestPlayerBase { @@ -37,7 +37,7 @@ public void testPutSecondFromTop() { Assert.assertTrue("Library has no cards but should have", cardArray.size() > 1); Card secondCard = cardArray.get(1); Assert.assertTrue("Second card from top should be Dread Wanderer, but it isn't", - secondCard != null && secondCard.getName().equals("Dread Wanderer")); + secondCard != null && secondCard.hasName("Dread Wanderer", currentGame)); } @@ -66,7 +66,7 @@ public void testUnexpectedlyAbsent() { Assert.assertTrue("Library has no cards but should have", cardArray.size() > 3); Card fourthCard = cardArray.get(3);// get the 4th element Assert.assertTrue("Fourth card from top should be Skyrider Patrol, but it isn't", - fourthCard != null && fourthCard.getName().equals("Skyrider Patrol")); + fourthCard != null && fourthCard.hasName("Skyrider Patrol", currentGame)); assertLife(playerA, 20); assertLife(playerB, 20); diff --git a/Mage/src/main/java/mage/MageObject.java b/Mage/src/main/java/mage/MageObject.java index e3d35a3aa8ad..16af9e663bf3 100644 --- a/Mage/src/main/java/mage/MageObject.java +++ b/Mage/src/main/java/mage/MageObject.java @@ -624,6 +624,10 @@ default boolean shareCreatureTypes(Game game, MageObject otherCard) { boolean hasName(String name, Game game); + default boolean hasNoName(Game game) { + return false; + } + default boolean sharesName(MageObject mageObject, Game game) { return !mageObject.getName().isEmpty() && hasName(mageObject.getName(), game); } diff --git a/Mage/src/main/java/mage/abilities/assignment/common/NameAssignment.java b/Mage/src/main/java/mage/abilities/assignment/common/NameAssignment.java new file mode 100644 index 000000000000..50c5532559e3 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/assignment/common/NameAssignment.java @@ -0,0 +1,23 @@ +package mage.abilities.assignment.common; + +import mage.abilities.assignment.RoleAssignment; +import mage.cards.Card; +import mage.game.Game; + +import java.util.Set; +import java.util.stream.Collectors; + +public class NameAssignment extends RoleAssignment { + + public NameAssignment(String... names) { + super(names); + } + + @Override + protected Set makeSet(Card card, Game game) { + return attributes + .stream() + .filter(s -> card.hasName(s, game)) + .collect(Collectors.toSet()); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetCardCopyAndCastEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetCardCopyAndCastEffect.java index 344ac0a874b4..42f61cafd880 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetCardCopyAndCastEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetCardCopyAndCastEffect.java @@ -48,10 +48,12 @@ public boolean apply(Game game, Ability source) { if (player == null || card == null) { return false; } - player.moveCards(card, Zone.EXILED, source, game); + if (!Zone.EXILED.match(game.getState().getZone(card.getId()))) { + player.moveCards(card, Zone.EXILED, source, game); + } Card cardCopy = game.copyCard(card, source, source.getControllerId()); if (optional && !player.chooseUse(outcome, "Cast copy of " + - card.getName() + (this.noMana ? " without paying its mana cost?" : "?" ), source, game)) { + card.getName() + (this.noMana ? " without paying its mana cost?" : "?"), source, game)) { return true; } game.getState().setValue("PlayFromNotOwnHandZone" + cardCopy.getId(), Boolean.TRUE); diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java index 07a078bd1fc8..c892b1270f24 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchTargetGraveyardHandLibraryForCardNameAndExileEffect.java @@ -1,5 +1,6 @@ package mage.abilities.effects.common.search; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Cards; @@ -8,6 +9,7 @@ import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.mageobject.SharesNamePredicate; import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; @@ -40,6 +42,7 @@ protected SearchTargetGraveyardHandLibraryForCardNameAndExileEffect(boolean grav protected SearchTargetGraveyardHandLibraryForCardNameAndExileEffect(boolean graveyardExileOptional, String searchWhatText, String searchForText, boolean drawForEachHandCard) { this(graveyardExileOptional, searchWhatText, searchForText, drawForEachHandCard, Integer.MAX_VALUE); } + protected SearchTargetGraveyardHandLibraryForCardNameAndExileEffect(boolean graveyardExileOptional, String searchWhatText, String searchForText, boolean drawForEachHandCard, int maxAmount) { super(Outcome.Exile); this.searchWhatText = searchWhatText; @@ -69,59 +72,67 @@ protected SearchTargetGraveyardHandLibraryForCardNameAndExileEffect(final Search * @return */ protected boolean applySearchAndExile(Game game, Ability source, String cardName, UUID targetPlayerId) { + FilterCard filter = new FilterCard("card named \"" + cardName + "\""); + filter.add(new NamePredicate(cardName)); + return applySearchAndExile(game, source, filter, targetPlayerId); + } + + protected boolean applySearchAndExile(Game game, Ability source, MageObject mageObject, UUID targetPlayerId) { + FilterCard filter = new FilterCard("card that shares a name with " + mageObject.getName()); + filter.add(new SharesNamePredicate(mageObject)); + return applySearchAndExile(game, source, filter, targetPlayerId); + } + + private boolean applySearchAndExile(Game game, Ability source, FilterCard filter, UUID targetPlayerId) { Player controller = game.getPlayer(source.getControllerId()); - if (cardName != null && controller != null) { - Player targetPlayer = game.getPlayer(targetPlayerId); - if (targetPlayer != null) { - int handCards = 0; - int maxRemaining = maxAmount; - FilterCard filter = new FilterCard("card named \"" + cardName + "\""); - filter.add(new NamePredicate(cardName)); - - // cards in Graveyard - int cardsCount = Math.min(targetPlayer.getGraveyard().count(filter, game), maxRemaining); - if (cardsCount > 0) { - filter.setMessage("card named " + cardName + " in the graveyard of " + targetPlayer.getName()); - TargetCard target = new TargetCard((graveyardExileOptional ? 0 : cardsCount), cardsCount, Zone.GRAVEYARD, filter); - target.withNotTarget(true); - if (controller.choose(Outcome.Exile, targetPlayer.getGraveyard(), target, source, game)) { - maxRemaining -= target.getTargets().size(); - controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game); - } - } - - // cards in Hand - cardsCount = Math.min(targetPlayer.getHand().count(filter, game), maxRemaining); - filter.setMessage("card named " + cardName + " in the hand of " + targetPlayer.getName()); - TargetCard target = new TargetCard(0, cardsCount, Zone.HAND, filter); - target.withNotTarget(true); - if (controller.choose(Outcome.Exile, targetPlayer.getHand(), target, source, game)) { - maxRemaining -= target.getTargets().size(); - if (drawForEachHandCard) { - handCards = target.getTargets().size(); - } - controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game); - } - - // cards in Library - Cards cardsInLibrary = new CardsImpl(); - cardsInLibrary.addAllCards(targetPlayer.getLibrary().getCards(game)); - cardsCount = Math.min(cardsInLibrary.count(filter, game), maxRemaining); - filter.setMessage("card named " + cardName + " in the library of " + targetPlayer.getLogName()); - TargetCardInLibrary targetLib = new TargetCardInLibrary(0, cardsCount, filter); - if (controller.choose(Outcome.Exile, cardsInLibrary, targetLib, source, game)) { - controller.moveCards(new CardsImpl(targetLib.getTargets()), Zone.EXILED, source, game); - } - targetPlayer.shuffleLibrary(source, game); - - if (handCards > 0) { - targetPlayer.drawCards(handCards, source, game); - } + Player targetPlayer = game.getPlayer(targetPlayerId); + if (controller == null || targetPlayer == null) { + return false; + } + String message = filter.getMessage(); + int handCards = 0; + int maxRemaining = maxAmount; + // cards in Graveyard + int cardsCount = Math.min(targetPlayer.getGraveyard().count(filter, game), maxRemaining); + if (cardsCount > 0) { + filter.setMessage(message + " in the graveyard of " + targetPlayer.getName()); + TargetCard target = new TargetCard((graveyardExileOptional ? 0 : cardsCount), cardsCount, Zone.GRAVEYARD, filter); + target.withNotTarget(true); + if (controller.choose(Outcome.Exile, targetPlayer.getGraveyard(), target, source, game)) { + maxRemaining -= target.getTargets().size(); + controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game); } + } - return true; + // cards in Hand + cardsCount = Math.min(targetPlayer.getHand().count(filter, game), maxRemaining); + filter.setMessage(message + " in the hand of " + targetPlayer.getName()); + TargetCard target = new TargetCard(0, cardsCount, Zone.HAND, filter); + target.withNotTarget(true); + if (controller.choose(Outcome.Exile, targetPlayer.getHand(), target, source, game)) { + maxRemaining -= target.getTargets().size(); + if (drawForEachHandCard) { + handCards = target.getTargets().size(); + } + controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game); + } + + // cards in Library + Cards cardsInLibrary = new CardsImpl(); + cardsInLibrary.addAllCards(targetPlayer.getLibrary().getCards(game)); + cardsCount = Math.min(cardsInLibrary.count(filter, game), maxRemaining); + filter.setMessage(message + " in the library of " + targetPlayer.getLogName()); + TargetCardInLibrary targetLib = new TargetCardInLibrary(0, cardsCount, filter); + if (controller.choose(Outcome.Exile, cardsInLibrary, targetLib, source, game)) { + controller.moveCards(new CardsImpl(targetLib.getTargets()), Zone.EXILED, source, game); } + targetPlayer.shuffleLibrary(source, game); + + if (handCards > 0) { + targetPlayer.drawCards(handCards, source, game); + } + + return true; - return false; } } From 0c27211f1197661f3ba1b16666c0a11f284b40a9 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 16 Oct 2024 11:10:50 -0400 Subject: [PATCH 12/16] more refactoring --- .../cards/continuous/FavorableWindsTest.java | 16 ++++---- .../cards/continuous/PaintersServantTest.java | 4 +- .../test/cards/continuous/WonderTest.java | 2 +- .../test/cards/copy/ArtisanOfFormsTest.java | 4 +- .../mage/test/cards/copy/CopySpellTest.java | 4 +- .../cards/copy/EssenceOfTheWildCopyTest.java | 2 +- .../test/cards/copy/EssenceOfTheWildTest.java | 2 +- .../cards/copy/KikiJikiMirrorBreakerTest.java | 2 +- .../mage/test/cards/copy/TokenCopyTest.java | 39 +++++++++---------- .../cost/additional/CollectEvidenceTest.java | 2 +- .../ModalDoubleFacedCardsTest.java | 4 +- .../modification/CostModificationTest.java | 2 +- .../mage/test/cards/dungeons/DungeonTest.java | 2 +- .../mage/test/cards/emblems/EmblemsTest.java | 2 +- .../test/cards/emblems/TheRingEmblemTest.java | 7 ++-- .../EnchantingGraveyardCardsTest.java | 9 ++--- .../cards/facedown/BaneAlleyBrokerTest.java | 2 +- .../test/cards/facedown/SummonersEggTest.java | 6 +-- .../redirect/PalisadeGiantTest.java | 2 +- .../single/brc/RootpathPurifierTest.java | 4 +- .../single/c13/MarathWillOfTheWildTest.java | 2 +- .../cards/single/fut/DustOfMomentsTest.java | 2 +- .../cards/single/inv/TravelersCloakTest.java | 4 +- .../single/ltr/WitchKingOfAngmarTest.java | 2 +- .../single/mh2/GristTheHungerTideTest.java | 4 +- .../single/mh3/ShiftingWoodlandTest.java | 2 +- .../test/cards/single/neo/StoryweaveTest.java | 4 +- .../test/cards/single/plc/ChronozoaTest.java | 4 +- .../cards/single/roe/CastThroughTimeTest.java | 2 +- .../slx/TadeasJuniperAscendantTest.java | 2 +- .../GodEternalDiesTriggeredAbilityTest.java | 4 +- .../triggers/ReturnToHandEffectsTest.java | 6 +-- .../test/mulligan/MulliganCardSorterTest.java | 4 +- .../test/serverside/PlayableEmblemsTest.java | 6 +-- .../mage/test/serverside/TokenImagesTest.java | 4 +- .../mage/test/serverside/TokenNamesTest.java | 6 +-- .../mage/test/sets/BoosterGenerationTest.java | 19 +++++---- .../org/mage/test/testapi/AddCardApiTest.java | 4 +- ...LibraryPutInHandOrOnBattlefieldEffect.java | 2 +- 39 files changed, 100 insertions(+), 100 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/FavorableWindsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/FavorableWindsTest.java index 5b2d45b3f7bf..65737fac1b7b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/FavorableWindsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/FavorableWindsTest.java @@ -33,12 +33,12 @@ public void testBoostForFlyingCreatures() { int countSkySpirit = 0; int countMerfolkLooter = 0; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(playerA.getId())) { - if (permanent.getName().equals("Sky Spirit")) { + if (permanent.hasName("Sky Spirit", currentGame)) { countSkySpirit++; // should get +1/+1, original is 2/2 Assert.assertEquals("Power is not the same", 3, permanent.getPower().getValue()); Assert.assertEquals("Toughness is not the same", 3, permanent.getToughness().getValue()); - } else if (permanent.getName().equals("Merfolk Looter")) { + } else if (permanent.hasName("Merfolk Looter", currentGame)) { countMerfolkLooter++; // should NOT get +1/+1, original is 1/1 Assert.assertEquals("Power is not the same", 1, permanent.getPower().getValue()); @@ -51,12 +51,12 @@ public void testBoostForFlyingCreatures() { countSkySpirit = 0; countMerfolkLooter = 0; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(playerB.getId())) { - if (permanent.getName().equals("Sky Spirit")) { + if (permanent.hasName("Sky Spirit", currentGame)) { countSkySpirit++; // should NOT +1/+1, original is 2/2 Assert.assertEquals("Power is not the same", 2, permanent.getPower().getValue()); Assert.assertEquals("Toughness is not the same", 2, permanent.getToughness().getValue()); - } else if (permanent.getName().equals("Merfolk Looter")) { + } else if (permanent.hasName("Merfolk Looter", currentGame)) { countMerfolkLooter++; // should NOT get +1/+1, original is 1/1 Assert.assertEquals("Power is not the same", 1, permanent.getPower().getValue()); @@ -88,12 +88,12 @@ public void testMultiBoostForFlyingCreatures() { int countSkySpirit = 0; int countMerfolkLooter = 0; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(playerA.getId())) { - if (permanent.getName().equals("Sky Spirit")) { + if (permanent.hasName("Sky Spirit", currentGame)) { countSkySpirit++; // should get +1/+1, original is 2/2 Assert.assertEquals("Power is not the same", 5, permanent.getPower().getValue()); Assert.assertEquals("Toughness is not the same", 5, permanent.getToughness().getValue()); - } else if (permanent.getName().equals("Merfolk Looter")) { + } else if (permanent.hasName("Merfolk Looter", currentGame)) { countMerfolkLooter++; // should NOT get +1/+1, original is 1/1 Assert.assertEquals("Power is not the same", 1, permanent.getPower().getValue()); @@ -106,12 +106,12 @@ public void testMultiBoostForFlyingCreatures() { countSkySpirit = 0; countMerfolkLooter = 0; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(playerB.getId())) { - if (permanent.getName().equals("Sky Spirit")) { + if (permanent.hasName("Sky Spirit", currentGame)) { countSkySpirit++; // should NOT +1/+1, original is 2/2 Assert.assertEquals("Power is not the same", 2, permanent.getPower().getValue()); Assert.assertEquals("Toughness is not the same", 2, permanent.getToughness().getValue()); - } else if (permanent.getName().equals("Merfolk Looter")) { + } else if (permanent.hasName("Merfolk Looter", currentGame)) { countMerfolkLooter++; // should NOT get +1/+1, original is 1/1 Assert.assertEquals("Power is not the same", 1, permanent.getPower().getValue()); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/PaintersServantTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/PaintersServantTest.java index 47d083544062..217605088701 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/PaintersServantTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/PaintersServantTest.java @@ -127,13 +127,13 @@ public void testColorReset() { Assert.assertEquals(false, card.getColor(currentGame).isBlue()); } for (Card card : playerA.getGraveyard().getCards(currentGame)) { - if (card.getName().equals("Silvercoat Lion")) { + if (card.hasName("Silvercoat Lion", currentGame)) { Assert.assertEquals(true, card.getColor(currentGame).isWhite()); Assert.assertEquals(false, card.getColor(currentGame).isBlue()); } } for (Card card : playerB.getGraveyard().getCards(currentGame)) { - if (card.getName().equals("Silvercoat Lion")) { + if (card.hasName("Silvercoat Lion", currentGame)) { Assert.assertEquals(true, card.getColor(currentGame).isWhite()); Assert.assertEquals(false, card.getColor(currentGame).isBlue()); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WonderTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WonderTest.java index d4c13331a88b..098be73080e5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WonderTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WonderTest.java @@ -39,7 +39,7 @@ public void testCardWithAllConditionsMet() { // check no flying in graveyard for (Card card : playerA.getGraveyard().getCards(currentGame)) { - if (card.getName().equals("Runeclaw Bear")) { + if (card.hasName("Runeclaw Bear", currentGame)) { Assert.assertFalse(card.hasAbility(FlyingAbility.getInstance(), currentGame)); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/ArtisanOfFormsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/ArtisanOfFormsTest.java index 732a51e019c4..9f4de7eae7d4 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/ArtisanOfFormsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/ArtisanOfFormsTest.java @@ -46,7 +46,7 @@ public void testCopyTriggeredByCracklingCounterpart() { assertPermanentCount(playerA, "Silvercoat Lion", 2); for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(playerA.getId())) { - if (permanent.getName().equals("Silvercoat Lion")) { + if (permanent.hasName("Silvercoat Lion", currentGame)) { Assert.assertEquals("Creature has to have Cast + Heroic ability", 2, permanent.getAbilities().size()); } } @@ -90,7 +90,7 @@ public void testCopyTriggeredByPopulate() { assertPermanentCount(playerA, "Silvercoat Lion", 3); for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(playerA.getId())) { - if (permanent.getName().equals("Silvercoat Lion")) { + if (permanent.hasName("Silvercoat Lion", currentGame)) { Assert.assertEquals("Creature has to have Cast + Heroic ability", 2, permanent.getAbilities().size()); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java index 4c01474b53c8..81746bdabeda 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java @@ -634,12 +634,12 @@ public void test_CopiedSpellsETBCounters() { // counters checks, have to check if it's a card or a token since token copies have isCopy()=false int originalCounters = currentGame.getBattlefield().getAllActivePermanents().stream() - .filter(p -> p.getName().equals("Grenzo, Dungeon Warden")) + .filter(p -> p.hasName("Grenzo, Dungeon Warden", currentGame)) .filter(p -> p instanceof PermanentCard) .mapToInt(p -> p.getCounters(currentGame).getCount(CounterType.P1P1)) .sum(); int copyCounters = currentGame.getBattlefield().getAllActivePermanents().stream() - .filter(p -> p.getName().equals("Grenzo, Dungeon Warden")) + .filter(p -> p.hasName("Grenzo, Dungeon Warden", currentGame)) .filter(p -> p instanceof PermanentToken) .mapToInt(p -> p.getCounters(currentGame).getCount(CounterType.P1P1)) .sum(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildCopyTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildCopyTest.java index 991537379773..6b47af39e4e7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildCopyTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildCopyTest.java @@ -38,7 +38,7 @@ private Permanent findCopyPermanent(Game game, int num) { private Permanent findOriginPermanent(Game game, String permName) { for (Permanent perm : game.getBattlefield().getAllActivePermanents()) { - if (!perm.isCopy() && perm.getName().equals(permName)) { + if (!perm.isCopy() && perm.hasName(permName, currentGame)) { return perm; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildTest.java index 2d399fd4bde1..f3f93e243103 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildTest.java @@ -33,7 +33,7 @@ private Permanent findCopyPermanent(Game game, int num) { private Permanent findOriginPermanent(Game game, String permName) { for (Permanent perm : game.getBattlefield().getAllActivePermanents()) { - if (!perm.isCopy() && perm.getName().equals(permName)) { + if (!perm.isCopy() && perm.hasName(permName, currentGame)) { return perm; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java index 08b4dccde0f8..37a40c6f7e5e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/KikiJikiMirrorBreakerTest.java @@ -148,7 +148,7 @@ public void testCopyBodyDouble() { Permanent kikiCopy = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, currentGame)) { - if (permanent.getName().equals("Silvercoat Lion") && (permanent instanceof PermanentToken)) { + if (permanent.hasName("Silvercoat Lion", currentGame) && (permanent instanceof PermanentToken)) { kikiCopy = permanent; break; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/TokenCopyTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/TokenCopyTest.java index 43f7d59e50c3..57478a790f43 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/TokenCopyTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/TokenCopyTest.java @@ -23,27 +23,24 @@ private void checkProwlers(int prowlerCount, int predatorCount) { assertPermanentCount(playerA, prowler, prowlerCount); assertPermanentCount(playerA, predator, predatorCount); for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { - switch (permanent.getName()) { - case prowler: - Assert.assertEquals("Power of " + prowler + " should be 2", 2, permanent.getPower().getValue()); - Assert.assertEquals("Toughness of " + prowler + " should be 1", 1, permanent.getToughness().getValue()); - Assert.assertEquals(prowler + " should be green", ObjectColor.GREEN, permanent.getColor(currentGame)); - Assert.assertTrue(prowler + " should be a Werewolf", permanent.hasSubtype(SubType.WEREWOLF, currentGame)); - Assert.assertTrue(prowler + " should be a Horror", permanent.hasSubtype(SubType.HORROR, currentGame)); - Assert.assertFalse(prowler + " should not be an Eldrazi", permanent.hasSubtype(SubType.ELDRAZI, currentGame)); - Assert.assertEquals(prowler + " should have mana value 1", 1, permanent.getManaValue()); - Assert.assertFalse(prowler + " should not be transformed", permanent.isTransformed()); - break; - case predator: - Assert.assertEquals("Power of " + predator + " should be 4", 4, permanent.getPower().getValue()); - Assert.assertEquals("Toughness of " + predator + " should be 4", 4, permanent.getToughness().getValue()); - Assert.assertTrue(predator + " should be colorless", permanent.getColor(currentGame).isColorless()); - Assert.assertTrue(predator + " should be an Eldrazi", permanent.hasSubtype(SubType.ELDRAZI, currentGame)); - Assert.assertTrue(predator + " should be a Werewolf", permanent.hasSubtype(SubType.WEREWOLF, currentGame)); - Assert.assertFalse(predator + " should not be a Horror", permanent.hasSubtype(SubType.HORROR, currentGame)); - Assert.assertEquals(predator + " should have mana value 1", 1, permanent.getManaValue()); - Assert.assertTrue(prowler + " should be transformed", permanent.isTransformed()); - break; + if (permanent.hasName(prowler, currentGame)) { + Assert.assertEquals("Power of " + prowler + " should be 2", 2, permanent.getPower().getValue()); + Assert.assertEquals("Toughness of " + prowler + " should be 1", 1, permanent.getToughness().getValue()); + Assert.assertEquals(prowler + " should be green", ObjectColor.GREEN, permanent.getColor(currentGame)); + Assert.assertTrue(prowler + " should be a Werewolf", permanent.hasSubtype(SubType.WEREWOLF, currentGame)); + Assert.assertTrue(prowler + " should be a Horror", permanent.hasSubtype(SubType.HORROR, currentGame)); + Assert.assertFalse(prowler + " should not be an Eldrazi", permanent.hasSubtype(SubType.ELDRAZI, currentGame)); + Assert.assertEquals(prowler + " should have mana value 1", 1, permanent.getManaValue()); + Assert.assertFalse(prowler + " should not be transformed", permanent.isTransformed()); + } else if (permanent.hasName(predator, currentGame)) { + Assert.assertEquals("Power of " + predator + " should be 4", 4, permanent.getPower().getValue()); + Assert.assertEquals("Toughness of " + predator + " should be 4", 4, permanent.getToughness().getValue()); + Assert.assertTrue(predator + " should be colorless", permanent.getColor(currentGame).isColorless()); + Assert.assertTrue(predator + " should be an Eldrazi", permanent.hasSubtype(SubType.ELDRAZI, currentGame)); + Assert.assertTrue(predator + " should be a Werewolf", permanent.hasSubtype(SubType.WEREWOLF, currentGame)); + Assert.assertFalse(predator + " should not be a Horror", permanent.hasSubtype(SubType.HORROR, currentGame)); + Assert.assertEquals(predator + " should have mana value 1", 1, permanent.getManaValue()); + Assert.assertTrue(prowler + " should be transformed", permanent.isTransformed()); } } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/additional/CollectEvidenceTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/additional/CollectEvidenceTest.java index 2e608ce41301..84b554fe1b2b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/additional/CollectEvidenceTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/additional/CollectEvidenceTest.java @@ -334,7 +334,7 @@ public void testNonDirectConditionalOnStack() { // before runCode("before", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { - Card card = playerA.getHand().getCards(game).stream().filter(c -> c.getName().equals(bite)).findFirst().orElse(null); + Card card = playerA.getHand().getCards(game).stream().filter(c -> c.hasName(bite, currentGame)).findFirst().orElse(null); Assert.assertNotNull(card); Ability ability = card.getAbilities(game).stream().filter(a -> a instanceof CollectEvidenceAbility).findFirst().orElse(null); Assert.assertNotNull(ability); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java index 7fd088c4ec0d..3cde69d2f4f7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java @@ -1051,7 +1051,7 @@ public void test_Copy_TokenFromCard_MustIgnoreSecondSide() { runCode("check side 2", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { PermanentToken permanent = (PermanentToken) game.getBattlefield().getAllPermanents() .stream() - .filter(p -> p.getName().equals("Tergrid, God of Fright")) + .filter(p -> p.hasName("Tergrid, God of Fright", currentGame)) .findFirst() .orElse(null); Assert.assertNotNull(permanent); @@ -1080,7 +1080,7 @@ public void test_Copy_TokenFromCard_MustIgnoreSecondSide() { GameView gameView = getGameView(playerA); PermanentView permanentView = gameView.getMyPlayer().getBattlefield().values() .stream() - .filter(p -> p.getName().equals("Tergrid, God of Fright")) + .filter(p -> p.hasName("Tergrid, God of Fright", currentGame)) .findFirst() .orElse(null); Assert.assertNotNull(permanentView); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/CostModificationTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/CostModificationTest.java index 1f0e6467275b..36799049cf6f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/CostModificationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modification/CostModificationTest.java @@ -427,7 +427,7 @@ public void test_PlaneswalkerLoyalty_CostModification_Single() { // Huatli: check x cost changes runCode("check x cost", 3, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> { - Permanent huatli = game.getBattlefield().getAllActivePermanents().stream().filter(p -> p.getName().equals("Huatli, Warrior Poet")).findFirst().orElse(null); + Permanent huatli = game.getBattlefield().getAllActivePermanents().stream().filter(p -> p.hasName("Huatli, Warrior Poet", currentGame)).findFirst().orElse(null); Assert.assertNotNull("must have huatli on battlefield", huatli); LoyaltyAbility ability = (LoyaltyAbility) huatli.getAbilities(game).stream().filter(a -> a.getRule().startsWith("-X: ")).findFirst().orElse(null); Assert.assertNotNull("must have loyalty ability", ability); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/dungeons/DungeonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/dungeons/DungeonTest.java index 548ecea0a7c4..3ecbf5a18b85 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/dungeons/DungeonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/dungeons/DungeonTest.java @@ -69,7 +69,7 @@ private void assertDungeonRoom(TestPlayer player, String dungeonName, String roo return; } Assert.assertNotNull("Dungeon should not be null", dungeon); - Assert.assertEquals("Dungeon should be " + dungeonName, dungeonName, dungeon.getName()); + Assert.assertTrue("Dungeon should be " + dungeonName, dungeon.hasName(dungeonName, currentGame)); Assert.assertEquals( "Current room is " + roomName, roomName, dungeon.getCurrentRoom().getName() diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemsTest.java index a1587ff240e1..5542c0764ec6 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/EmblemsTest.java @@ -116,7 +116,7 @@ public void testTamiyoTheMoonSageSecondEmblem() { boolean found = false; for (Card card : playerA.getHand().getCards(currentGame)) { - if (card.getName().equals("Elite Vanguard")) { + if (card.hasName("Elite Vanguard", currentGame)) { found = true; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/TheRingEmblemTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/TheRingEmblemTest.java index 4c4afe0424ef..08625a73aff7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/emblems/TheRingEmblemTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/emblems/TheRingEmblemTest.java @@ -1,6 +1,5 @@ package org.mage.test.cards.emblems; -import mage.MageObject; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.game.command.emblems.TheRingEmblem; @@ -33,15 +32,15 @@ private void assertRing(String info, Player player, int totalGameEmblems, int ne boolean hasEmblem = ringEmblems.stream().anyMatch(e -> e.isControlledBy(player.getId())); Assert.assertEquals(info + " - ring emblem for " + player.getName(), needEmblem, hasEmblem); - String hasBearer = Optional.ofNullable(player.getRingBearer(currentGame)).map(MageObject::getName).orElse(null); - Assert.assertEquals(info + " - ring bearer for " + player.getName(), needBearer, hasBearer); + boolean hasBearer = Optional.ofNullable(player.getRingBearer(currentGame)).map(permanent -> permanent.hasName(needBearer, currentGame)).orElse(false); + Assert.assertTrue(info + " - ring bearer for " + player.getName(), hasBearer); } private void assertPermanent(String info, Player player, String needName, boolean needLegendary) { Permanent permanent = currentGame.getBattlefield().getAllActivePermanents(player.getId()) .stream() .filter(p -> p.isControlledBy(player.getId())) - .filter(p -> p.getName().equals(needName)) + .filter(p -> p.hasName(needName, currentGame)) .findFirst() .orElse(null); Assert.assertNotNull(info + " - permanent " + needName + " for player " + player.getName() + " must exist", permanent); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/EnchantingGraveyardCardsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/EnchantingGraveyardCardsTest.java index f4d4c757fd45..891ac27ed502 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/EnchantingGraveyardCardsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/EnchantingGraveyardCardsTest.java @@ -11,7 +11,6 @@ import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class EnchantingGraveyardCardsTest extends CardTestPlayerBase { @@ -50,7 +49,7 @@ public void testSpellwaeverVoluteNormal() { if (spellweaver != null) { attachedToCard = playerB.getGraveyard().get(spellweaver.getAttachedTo(), currentGame); } - Assert.assertTrue(SPELLWEAVER_VOLUTE + " has to be attached to Lightning Bolt in graveyard", attachedToCard != null && attachedToCard.getName().equals(LIGHTNING_BOLT)); + Assert.assertTrue(SPELLWEAVER_VOLUTE + " has to be attached to Lightning Bolt in graveyard", attachedToCard != null && attachedToCard.hasName(LIGHTNING_BOLT, currentGame)); } /** @@ -94,7 +93,7 @@ public void testSpellwaeverVoluteAndSorcery() { if (spellweaver != null) { attachedToCard = playerA.getGraveyard().get(spellweaver.getAttachedTo(), currentGame); } - Assert.assertTrue(SPELLWEAVER_VOLUTE + " has to be attached to Aerial Volley in graveyard", attachedToCard != null && attachedToCard.getName().equals("Aerial Volley")); + Assert.assertTrue(SPELLWEAVER_VOLUTE + " has to be attached to Aerial Volley in graveyard", attachedToCard != null && attachedToCard.hasName("Aerial Volley", currentGame)); assertHandCount(playerA, 1); @@ -139,7 +138,7 @@ public void testSpellwaeverVoluteAndSorceryWithoutNewTarget() { assertGraveyardCount(playerA, SPELLWEAVER_VOLUTE, 1); for (Card card : currentGame.getExile().getAllCards(currentGame)) { - if (card.getName().equals(LIGHTNING_BOLT)) { + if (card.hasName(LIGHTNING_BOLT, currentGame)) { Assert.assertTrue(LIGHTNING_BOLT + " may not have any attachments", card.getAttachments().isEmpty()); } @@ -183,7 +182,7 @@ public void testSpellwaeverVoluteAndReturnToHand() { assertPermanentCount(playerA, SPELLWEAVER_VOLUTE, 0); for (Card card : playerB.getGraveyard().getCards(currentGame)) { - if (card.getName().equals(LIGHTNING_BOLT)) { + if (card.hasName(LIGHTNING_BOLT, currentGame)) { Assert.assertTrue(LIGHTNING_BOLT + " may not have any attachments", card.getAttachments().isEmpty()); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/BaneAlleyBrokerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/BaneAlleyBrokerTest.java index ed4129146709..9d37121c5f55 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/BaneAlleyBrokerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/BaneAlleyBrokerTest.java @@ -41,7 +41,7 @@ public void testBaneAlleyBroker() { assertExileCount("Goblin Roughrider", 1); for (Card card : currentGame.getExile().getAllCards(currentGame)) { - if (card.getName().equals("Goblin Roughrider")) { + if (card.hasName("Goblin Roughrider", currentGame)) { Assert.assertTrue("Exiled card is not face down", card.isFaceDown(currentGame)); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/SummonersEggTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/SummonersEggTest.java index c8796b10770f..73b23a6144ac 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/SummonersEggTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/SummonersEggTest.java @@ -44,7 +44,7 @@ public void testSummonersEggImprint() { assertExileCount("Goblin Roughrider", 1); for (Card card : currentGame.getExile().getAllCards(currentGame)) { - if (card.getName().equals("Goblin Roughrider")) { + if (card.hasName("Goblin Roughrider", currentGame)) { Assert.assertTrue("Exiled card is not face down", card.isFaceDown(currentGame)); } } @@ -80,7 +80,7 @@ public void testSummonersEggDies() { assertExileCount("Goblin Roughrider", 0); assertPermanentCount(playerA, "Goblin Roughrider", 1); for (Permanent p : currentGame.getBattlefield().getAllActivePermanents()) { - if (p.getName().equals("Goblin Roughrider")) { + if (p.hasName("Goblin Roughrider", currentGame)) { Assert.assertTrue("Permanent is not face up", !p.isFaceDown(currentGame)); } } @@ -113,7 +113,7 @@ public void testSummonersEggDies2() { assertExileCount("Forest", 1); for (Card card : currentGame.getExile().getAllCards(currentGame)) { - if (card.getName().equals("Forest")) { + if (card.hasName("Forest", currentGame)) { Assert.assertTrue("Exiled card is not face up", !card.isFaceDown(currentGame)); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/PalisadeGiantTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/PalisadeGiantTest.java index d2823328918a..4d7fe0e7849e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/PalisadeGiantTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/PalisadeGiantTest.java @@ -43,7 +43,7 @@ public void testRedirectDamage() { int damage = 0; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(playerA.getId())) { - if (permanent.getName().equals("Palisade Giant")) { + if (permanent.hasName("Palisade Giant", currentGame)) { damage += permanent.getDamage(); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/brc/RootpathPurifierTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/brc/RootpathPurifierTest.java index 867e1261a1a7..e33147e21a72 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/brc/RootpathPurifierTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/brc/RootpathPurifierTest.java @@ -90,7 +90,7 @@ public void testSearchToHand() { playerA.getHand() .getCards(currentGame) .stream() - .filter(card -> tree.equals(card.getName())) + .filter(card -> card.hasName(tree, currentGame)) .noneMatch(card -> card.isBasic(currentGame)) ); } @@ -116,7 +116,7 @@ public void testRemove() { playerA.getLibrary() .getCards(currentGame) .stream() - .filter(card -> tree.equals(card.getName())) + .filter(card -> card.hasName(tree, currentGame)) .noneMatch(card -> card.isBasic(currentGame)) ); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/c13/MarathWillOfTheWildTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/c13/MarathWillOfTheWildTest.java index 111cc78e3efe..6b58cbc62884 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/c13/MarathWillOfTheWildTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/c13/MarathWillOfTheWildTest.java @@ -39,7 +39,7 @@ public void test_Play() { ManaPaidSourceWatcher watcher = game.getState().getWatcher(ManaPaidSourceWatcher.class); Permanent perm = game.getBattlefield().getAllPermanents() .stream() - .filter(p -> p.getName().equals("Marath, Will of the Wild")) + .filter(p -> p.hasName("Marath, Will of the Wild", currentGame)) .findFirst() .orElse(null); Assert.assertNotNull(perm); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/DustOfMomentsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/DustOfMomentsTest.java index 4f6a84ec631f..37c2348dded3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/DustOfMomentsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/DustOfMomentsTest.java @@ -29,7 +29,7 @@ public void testRemoveCounters() throws Exception { Assert.assertEquals(2, activeCreatures.size()); for (final Permanent creature : activeCreatures) { - Assert.assertEquals("Chronozoa", creature.getName()); + Assert.assertTrue(creature.hasName("Chronozoa", currentGame)); Assert.assertEquals(3, creature.getCounters(currentGame).getCount(CounterType.TIME)); } // Check time counters on kraken diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/inv/TravelersCloakTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/inv/TravelersCloakTest.java index 4e5c7168f2a3..2d4d4497a903 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/inv/TravelersCloakTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/inv/TravelersCloakTest.java @@ -39,7 +39,7 @@ public void test_MustHaveLandWalkOfTheChosenType() { runCode("check blocking", 1, PhaseStep.DECLARE_BLOCKERS, playerB, (info, player, game) -> { Permanent blocker = game.getBattlefield().getAllActivePermanents() .stream() - .filter(p -> p.getName().equals("Kitesail Corsair")) + .filter(p -> p.hasName("Kitesail Corsair", currentGame)) .findFirst() .get(); Assert.assertFalse("Grizzly Bears must be protected from blocking by Kitesail Corsair", @@ -50,4 +50,4 @@ public void test_MustHaveLandWalkOfTheChosenType() { setStopAt(1, PhaseStep.END_TURN); execute(); } -} \ No newline at end of file +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/WitchKingOfAngmarTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/WitchKingOfAngmarTest.java index 46930ca643c0..5c703a68a132 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/WitchKingOfAngmarTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/ltr/WitchKingOfAngmarTest.java @@ -35,7 +35,7 @@ public void test_Sacrifice() { runCode("check ring bear", 2, PhaseStep.POSTCOMBAT_MAIN, playerA, (info, player, game) -> { Assert.assertNotNull(playerA.getRingBearer(game)); - Assert.assertEquals(witchKing, playerA.getRingBearer(game).getName()); + Assert.assertTrue(playerA.getRingBearer(game).hasName(witchKing, currentGame)); Assert.assertNull(playerB.getRingBearer(game)); }); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/GristTheHungerTideTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/GristTheHungerTideTest.java index 6ccb9cd0c98c..1fdbf9245613 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/GristTheHungerTideTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh2/GristTheHungerTideTest.java @@ -30,7 +30,7 @@ public void testGristInHandBattlefieldGraveLibrary() { execute(); for (Card card : currentGame.getCards()) { - if (!card.getName().equals(grist)) { + if (!card.hasName(grist, currentGame)) { continue; } Zone zone = currentGame.getState().getZone(card.getId()); @@ -56,7 +56,7 @@ public void testGristInExile() { execute(); for (Card card : currentGame.getCards()) { - if (!card.getName().equals(grist)) { + if (!card.hasName(grist, currentGame)) { continue; } Assert.assertEquals("", Zone.EXILED, currentGame.getState().getZone(card.getId())); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/ShiftingWoodlandTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/ShiftingWoodlandTest.java index 90b80d04a13d..d9478cce93b8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/ShiftingWoodlandTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/ShiftingWoodlandTest.java @@ -91,7 +91,7 @@ public void test_Copy_StopOnLTB() { castSpell(1, PhaseStep.END_COMBAT, playerA, "Shoot the Sheriff", "Grizzly Bears", true); runCode("check that the copy effect ended", 1, PhaseStep.END_COMBAT, playerA, (info, player, game) -> { - Card card = player.getGraveyard().getCards(game).stream().filter(c -> c.getName().equals(woodland)).findFirst().orElse(null); + Card card = player.getGraveyard().getCards(game).stream().filter(c -> c.hasName(woodland, currentGame)).findFirst().orElse(null); if (card == null) { Assert.fail("Shifting Woodland is not in the graveyard"); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/neo/StoryweaveTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/neo/StoryweaveTest.java index 945d6ecec96f..106e001e5c11 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/neo/StoryweaveTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/neo/StoryweaveTest.java @@ -67,7 +67,7 @@ public void test__MultipleOnlyOnce() { .getBattlefield() .getAllActivePermanents() .stream() - .filter(permanent -> "Centaur Token".equals(permanent.getName())) + .filter(permanent -> permanent.hasName("Centaur Token", currentGame)) .noneMatch(permanent -> permanent.getCounters(currentGame).getCount(CounterType.P1P1) != 2)); } @@ -97,7 +97,7 @@ public void test__SingleOnlyOnce() { .getBattlefield() .getAllActivePermanents() .stream() - .filter(permanent -> "Centaur Token".equals(permanent.getName())) + .filter(permanent -> permanent.hasName("Centaur Token", currentGame)) .noneMatch(permanent -> permanent.getCounters(currentGame).getCount(CounterType.P1P1) != 0)); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/plc/ChronozoaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/plc/ChronozoaTest.java index e8cce2d1a319..408c9d357b13 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/plc/ChronozoaTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/plc/ChronozoaTest.java @@ -61,8 +61,8 @@ public void testDuplicationEffect() { for (final Permanent creature : creatures) { // Make sure the creatures are Chronozoa tokens - Assert.assertEquals("Chronozoa", creature.getName()); - Assert.assertEquals("Chronozoa has to be a token", true, creature instanceof PermanentToken); + Assert.assertTrue(creature.hasName("Chronozoa", currentGame)); + Assert.assertTrue("Chronozoa has to be a token", creature instanceof PermanentToken); // Make sure each token has 2 time counters final Counters counters = creature.getCounters(currentGame); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/roe/CastThroughTimeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/roe/CastThroughTimeTest.java index fd8e1bc84a12..98a10b196e8d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/roe/CastThroughTimeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/roe/CastThroughTimeTest.java @@ -67,7 +67,7 @@ public void testReboundTooltipExists() { boolean found = false; for (Card card : currentGame.getPlayer(playerA.getId()).getHand().getCards(currentGame)) { - if (card.getName().equals("Lightning Bolt")) { + if (card.hasName("Lightning Bolt", currentGame)) { for (String rule : card.getRules(currentGame)) { if (rule.startsWith("Rebound")) { found = true; diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/slx/TadeasJuniperAscendantTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/slx/TadeasJuniperAscendantTest.java index b381eb297bbe..47c1584b3de2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/slx/TadeasJuniperAscendantTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/slx/TadeasJuniperAscendantTest.java @@ -29,7 +29,7 @@ public void setUp() { private Permanent getBlocker(String blocker, mage.game.Game game) { return game.getBattlefield().getAllActivePermanents() .stream() - .filter(p -> p.getName().equals(blocker)) + .filter(p -> p.hasName(blocker, currentGame)) .findFirst() .get(); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GodEternalDiesTriggeredAbilityTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GodEternalDiesTriggeredAbilityTest.java index 307bfced15d7..3e7afb133ce8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GodEternalDiesTriggeredAbilityTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/GodEternalDiesTriggeredAbilityTest.java @@ -33,7 +33,7 @@ public void dyingTriggers() { assertPermanentCount(playerA, godEternalBontu, 0); assertGraveyardCount(playerA, godEternalBontu, 0); Card card = currentGame.getCard(playerA.getLibrary().getCardList().get(2)); - Assert.assertEquals(card.getName(), godEternalBontu); + Assert.assertTrue(card.hasName(godEternalBontu, currentGame)); } /** @@ -54,7 +54,7 @@ public void exilingTriggers() { assertPermanentCount(playerA, godEternalBontu, 0); assertExileCount(playerA, godEternalBontu, 0); Card card = currentGame.getCard(playerA.getLibrary().getCardList().get(2)); - Assert.assertEquals(card.getName(), godEternalBontu); + Assert.assertTrue(card.hasName(godEternalBontu, currentGame)); } /** diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToHandEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToHandEffectsTest.java index 2fc31b9d5483..ca173dec6262 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToHandEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/ReturnToHandEffectsTest.java @@ -97,7 +97,7 @@ private void checkZCCPermanent(String info, Player player, Game game, String car .getAllActivePermanents() .stream() .filter(Objects::nonNull) - .filter(p -> p.getName().equals(cardName)) + .filter(p -> p.hasName(cardName, currentGame)) .findFirst(); if (!optPermanent.isPresent()) { Assert.fail(info + " — no permanent named \"" + cardName + "\" found on battlefield"); @@ -133,7 +133,7 @@ private void checkZCCCardInGraveyard(String info, Player player, Game game, Stri .getCards(game) .stream() .filter(Objects::nonNull) - .filter(p -> p.getName().equals(cardName)) + .filter(p -> p.hasName(cardName, currentGame)) .findFirst(); if (!optCard.isPresent()) { Assert.fail(info + " — no card named \"" + cardName + "\" found in graveyard"); @@ -152,7 +152,7 @@ private void checkZCCCardInHand(String info, Player player, Game game, String ca .getCards(game) .stream() .filter(Objects::nonNull) - .filter(p -> p.getName().equals(cardName)) + .filter(p -> p.hasName(cardName, currentGame)) .findFirst(); if (!optCard.isPresent()) { Assert.fail(info + " — no card named \"" + cardName + "\" found in hand"); diff --git a/Mage.Tests/src/test/java/org/mage/test/mulligan/MulliganCardSorterTest.java b/Mage.Tests/src/test/java/org/mage/test/mulligan/MulliganCardSorterTest.java index 1e5e563f6df5..61bbab20d9bf 100644 --- a/Mage.Tests/src/test/java/org/mage/test/mulligan/MulliganCardSorterTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/mulligan/MulliganCardSorterTest.java @@ -29,7 +29,7 @@ private void assertHandSort(List goodList) { .stream() .map(name -> currentGame.getCards() .stream() - .filter(c -> c.getName().equals(name)) + .filter(c -> c.hasName(name, currentGame)) .findFirst() .orElseThrow(() -> new IllegalStateException("Can't find testing card " + name)) ) @@ -110,4 +110,4 @@ public void test_HandSorting() { )); } -} \ No newline at end of file +} diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayableEmblemsTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayableEmblemsTest.java index d5f411689e5a..33999b5266dd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayableEmblemsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayableEmblemsTest.java @@ -54,7 +54,7 @@ public void test_EmblemMustBePlayableInGUI() { // playable commander UUID needObjectId = game.getCommandersIds(playerA, CommanderCardType.COMMANDER_OR_OATHBREAKER, false) .stream() - .filter(id -> game.getObject(id).getName().equals("Balduvian Bears")) + .filter(id -> game.getObject(id).hasName("Balduvian Bears", currentGame)) .findFirst() .orElse(null); Assert.assertNotNull(needObjectId); @@ -63,7 +63,7 @@ public void test_EmblemMustBePlayableInGUI() { // non playable commander needObjectId = game.getCommandersIds(playerA, CommanderCardType.COMMANDER_OR_OATHBREAKER, false) .stream() - .filter(id -> game.getObject(id).getName().equals("Goblin Arsonist")) + .filter(id -> game.getObject(id).hasName("Goblin Arsonist", currentGame)) .findFirst() .orElse(null); Assert.assertNotNull(needObjectId); @@ -74,7 +74,7 @@ public void test_EmblemMustBePlayableInGUI() { .stream() .filter(obj -> obj instanceof Emblem) .filter(obj -> obj.isControlledBy(playerA.getId())) - .filter(obj -> obj.getName().equals("Emblem Momir")) + .filter(obj -> obj.hasName("Emblem Momir", currentGame)) .map(MageItem::getId) .findFirst() .orElse(null); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/TokenImagesTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/TokenImagesTest.java index 8f645ad543f4..5b3a0de8a038 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/TokenImagesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/TokenImagesTest.java @@ -150,7 +150,7 @@ private void assert_Inner(String cardName, int cardAmountInExile, int cardAmount Map> realServerStats = new LinkedHashMap<>(); currentGame.getBattlefield().getAllPermanents() .stream() - .filter(card -> card.getName().equals(tokenName)) + .filter(card -> card.hasName(tokenName, currentGame)) .filter(card -> card instanceof PermanentToken) .sorted(Comparator.comparing(Card::getExpansionSetCode)) .forEach(card -> { @@ -267,7 +267,7 @@ private void assert_Inner(String cardName, int cardAmountInExile, int cardAmount private void assert_TokenOrCardImageNumber(String tokenOrCardName, List needUniqueImages) { Set serverStats = currentGame.getBattlefield().getAllPermanents() .stream() - .filter(card -> card.getName().equals(tokenOrCardName)) + .filter(card -> card.hasName(tokenOrCardName, currentGame)) .filter(card -> card instanceof MageObjectImpl) .sorted(Comparator.comparing(Card::getExpansionSetCode)) .map(card -> (MageObjectImpl) card) diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/TokenNamesTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/TokenNamesTest.java index 6da7a7ebdea4..ae0bb9f653a4 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/TokenNamesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/TokenNamesTest.java @@ -88,8 +88,8 @@ public void test_Rules_111_4_Example3() { @Test public void test_Rules_111_4_AutoGeneratedName() { - Assert.assertEquals("Human Cleric Token", new CreatureToken(2, 2, "", SubType.HUMAN, SubType.CLERIC).getName()); - Assert.assertEquals("Warrior Token", new CreatureToken(2, 2, "", SubType.WARRIOR).getName()); - Assert.assertEquals("Custom Name", new CreatureToken(2, 2, "", SubType.WARRIOR).withName("Custom Name").getName()); + Assert.assertTrue(new CreatureToken(2, 2, "", SubType.HUMAN, SubType.CLERIC).hasName("Human Cleric Token", currentGame)); + Assert.assertTrue(new CreatureToken(2, 2, "", SubType.WARRIOR).hasName("Warrior Token", currentGame)); + Assert.assertTrue(new CreatureToken(2, 2, "", SubType.WARRIOR).withName("Custom Name").hasName("Custom Name", currentGame)); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java index 7e9cd397b471..aac0ffbd2dc1 100644 --- a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java @@ -14,7 +14,6 @@ import mage.sets.*; import mage.util.CardUtil; import org.junit.Assert; -import static org.junit.Assert.*; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; @@ -23,6 +22,12 @@ import java.util.*; import java.util.stream.Collectors; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + /** * @author nigelzor, JayDi85 */ @@ -50,7 +55,7 @@ private static boolean contains(List cards, List names, String cod private static boolean contains(List cards, String name, String code) { return cards.stream().anyMatch((card) - -> (card.getName().equals(name) + -> (card.hasName(name, currentGame) && (code == null || card.getExpansionSetCode().equals(code))) ); } @@ -331,22 +336,22 @@ public void testKaldheim_SnowLandAndMDFC() { case 2: assertEquals( "Booster can't have two snow lands unless one is Shimmerdrift Vale or Faceless Haven", 1, - snowLands.stream().filter(card -> card.getName().equals("Shimmerdrift Vale") || card.getName().equals("Faceless Haven")).count() + snowLands.stream().filter(card -> card.hasName("Shimmerdrift Vale", currentGame) || card.hasName("Faceless Haven", currentGame)).count() ); assertEquals( "Booster can't have two snow lands unless one is not Shimmerdrift Vale or Faceless Haven", 1, - snowLands.stream().filter(card -> !card.getName().equals("Shimmerdrift Vale") && !card.getName().equals("Faceless Haven")).count() + snowLands.stream().filter(card -> !card.hasName("Shimmerdrift Vale", currentGame) && !card.hasName("Faceless Haven", currentGame)).count() ); break; case 3: assertEquals("Booster can't have three snow lands unless one is Shimmerdrift Vale", 1, - snowLands.stream().filter(card -> card.getName().equals("Shimmerdrift Vale")).count() + snowLands.stream().filter(card -> card.hasName("Shimmerdrift Vale", currentGame)).count() ); assertEquals("Booster can't have three snow lands unless one is Faceless Haven", 1, - snowLands.stream().filter(card -> card.getName().equals("Faceless Haven")).count() + snowLands.stream().filter(card -> card.hasName("Faceless Haven", currentGame)).count() ); assertEquals("Booster can't have three snow lands unless one is not Shimmerdrift Vale or Faceless Haven", 1, - snowLands.stream().filter(card -> !card.getName().equals("Shimmerdrift Vale") && !card.getName().equals("Faceless Haven")).count() + snowLands.stream().filter(card -> !card.hasName("Shimmerdrift Vale", currentGame) && !card.hasName("Faceless Haven", currentGame)).count() ); break; default: diff --git a/Mage.Tests/src/test/java/org/mage/test/testapi/AddCardApiTest.java b/Mage.Tests/src/test/java/org/mage/test/testapi/AddCardApiTest.java index e04ad0bf39b7..886ccab70b3c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/testapi/AddCardApiTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/testapi/AddCardApiTest.java @@ -91,13 +91,13 @@ public void test_CardNameWithSetCode_Normal() { assertPermanentCount(playerA, "Memorial to Glory", 2); getBattlefieldCards(playerA) .stream() - .filter(info -> info.getCard().getName().equals("Memorial to Glory")) + .filter(info -> info.getCard().hasName("Memorial to Glory", currentGame)) .forEach(info -> Assert.assertEquals("40K", info.getCard().getExpansionSetCode())); assertPermanentCount(playerA, "Plains", 2); getBattlefieldCards(playerA) .stream() - .filter(info -> info.getCard().getName().equals("Plains")) + .filter(info -> info.getCard().hasName("Plains", currentGame)) .forEach(info -> Assert.assertEquals("PANA", info.getCard().getExpansionSetCode())); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandOrOnBattlefieldEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandOrOnBattlefieldEffect.java index 8f7a28686c83..0ebfc4b89e59 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandOrOnBattlefieldEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandOrOnBattlefieldEffect.java @@ -56,7 +56,7 @@ public boolean apply(Game game, Ability source) { for (UUID cardId : target.getTargets()) { Card card = game.getCard(cardId); if (card != null) { - if (card.getName().equals(nameToPutOnBattlefield)) { + if (card.hasName(nameToPutOnBattlefield, currentGame)) { askToPutOntoBf = true; cardToPutOnBf = card; } From b02f05c0c536a5bb504bed6e0270b177161aeac2 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 16 Oct 2024 11:15:30 -0400 Subject: [PATCH 13/16] fix error --- .../search/SearchLibraryPutInHandOrOnBattlefieldEffect.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandOrOnBattlefieldEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandOrOnBattlefieldEffect.java index 0ebfc4b89e59..d24cc3174861 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandOrOnBattlefieldEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandOrOnBattlefieldEffect.java @@ -56,7 +56,7 @@ public boolean apply(Game game, Ability source) { for (UUID cardId : target.getTargets()) { Card card = game.getCard(cardId); if (card != null) { - if (card.hasName(nameToPutOnBattlefield, currentGame)) { + if (card.hasName(nameToPutOnBattlefield, game)) { askToPutOntoBf = true; cardToPutOnBf = card; } From 8a3bc359ec845e0915e5869d175810664d65e527 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 16 Oct 2024 11:29:08 -0400 Subject: [PATCH 14/16] fix error --- .../cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java index 3cde69d2f4f7..bc084a6a30e5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/modaldoublefaced/ModalDoubleFacedCardsTest.java @@ -1080,7 +1080,7 @@ public void test_Copy_TokenFromCard_MustIgnoreSecondSide() { GameView gameView = getGameView(playerA); PermanentView permanentView = gameView.getMyPlayer().getBattlefield().values() .stream() - .filter(p -> p.hasName("Tergrid, God of Fright", currentGame)) + .filter(p -> p.getName().equals("Tergrid, God of Fright")) .findFirst() .orElse(null); Assert.assertNotNull(permanentView); From 542ea3664d54631869eae62a7954973d97cbd757 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 16 Oct 2024 15:15:38 -0400 Subject: [PATCH 15/16] a few more refactors --- .../serverside/performance/SerializationTest.java | 8 ++++---- .../org/mage/test/sets/BoosterGenerationTest.java | 13 ++++++------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/performance/SerializationTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/performance/SerializationTest.java index 3ebd8e0e4efb..5014289bc75d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/performance/SerializationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/performance/SerializationTest.java @@ -49,7 +49,7 @@ public void test_PermanentImpl_Simple() { Object compressed = CompressUtil.compress(permanent); Assert.assertTrue("Must be zip", compressed instanceof ZippedObjectImpl); PermanentImpl uncompressed = (PermanentImpl) CompressUtil.decompress(compressed); - Assert.assertEquals("Must be same", permanent.getName(), uncompressed.getName()); + Assert.assertTrue("Must be same", permanent.sharesName(uncompressed, currentGame)); } @Test @@ -68,7 +68,7 @@ public void test_PermanentImpl_MarkedDamageInfo() { Object compressed = CompressUtil.compress(permanent); Assert.assertTrue("Must be zip", compressed instanceof ZippedObjectImpl); PermanentImpl uncompressed = (PermanentImpl) CompressUtil.decompress(compressed); - Assert.assertEquals("Must be same", permanent.getName(), uncompressed.getName()); + Assert.assertTrue("Must be same", permanent.sharesName(uncompressed, currentGame)); // ensure that it was marked damage permanent.applyDamage(currentGame); @@ -92,7 +92,7 @@ private void processSingleCard(CardInfo cardInfo) { Object compressed = CompressUtil.compress(card); Assert.assertTrue("Must be zip", compressed instanceof ZippedObjectImpl); Card uncompressed = (Card) CompressUtil.decompress(compressed); - Assert.assertEquals("Must be same", card.getName(), uncompressed.getName()); + Assert.assertTrue("Must be same", card.sharesName(uncompressed, currentGame)); } // permanent @@ -100,7 +100,7 @@ private void processSingleCard(CardInfo cardInfo) { Object compressed = CompressUtil.compress(testPermanent); Assert.assertTrue("Must be zip", compressed instanceof ZippedObjectImpl); Card uncompressed = (Card) CompressUtil.decompress(compressed); - Assert.assertEquals("Must be same", testPermanent.getName(), uncompressed.getName()); + Assert.assertTrue("Must be same", testPermanent.sharesName(uncompressed, currentGame)); } }); } diff --git a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java index aac0ffbd2dc1..871a08eaf79c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java @@ -24,7 +24,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -74,7 +73,7 @@ private void checkOnePartnerBoost() { for (Ability ability : card.getAbilities()) { if (ability instanceof PartnerWithAbility) { if (foundPartner) { - Assert.assertEquals(Partner, card.getName()); + assertTrue(card.hasName(Partner, currentGame)); } else { foundPartner = true; Partner = ((PartnerWithAbility) ability).getPartnerName(); @@ -324,13 +323,13 @@ public void testKaldheim_SnowLandAndMDFC() { "Only one snow land, must be basic or common", snowLand.isBasic() || snowLand.getRarity() == Rarity.COMMON ); - assertNotEquals( + assertFalse( "Only one snow land, can't be Shimmerdrift Vale", - "Shimmerdrift Vale", snowLand.getName() + snowLand.hasName("Shimmerdrift Vale", currentGame) ); - assertNotEquals( + assertFalse( "Only one snow land, can't be Faceless Haven", - "Faceless Haven", snowLand.getName() + snowLand.hasName("Faceless Haven", currentGame) ); break; case 2: @@ -363,7 +362,7 @@ public void testKaldheim_SnowLandAndMDFC() { foundMDFC |= mdfcCount > 0; foundNoMDFC |= mdfcCount == 0; - foundVale |= booster.stream().map(MageObject::getName).anyMatch("Shimmerdrift Vale"::equals); + foundVale |= booster.stream().anyMatch(card -> card.hasName("Shimmerdrift Vale", currentGame)); if (foundVale && foundMDFC && foundNoMDFC && i > 20) { break; } From ad7c62cff4343e47fb6e4c429e6dd257f226c427 Mon Sep 17 00:00:00 2001 From: theelk801 Date: Wed, 16 Oct 2024 15:35:40 -0400 Subject: [PATCH 16/16] [CSP] rework Jester's Scepter --- .../src/mage/cards/j/JestersScepter.java | 135 +++++++----------- 1 file changed, 54 insertions(+), 81 deletions(-) diff --git a/Mage.Sets/src/mage/cards/j/JestersScepter.java b/Mage.Sets/src/mage/cards/j/JestersScepter.java index ae56998df617..049ed0d1adf0 100644 --- a/Mage.Sets/src/mage/cards/j/JestersScepter.java +++ b/Mage.Sets/src/mage/cards/j/JestersScepter.java @@ -1,29 +1,27 @@ package mage.cards.j; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.*; import mage.constants.*; -import mage.filter.FilterCard; -import mage.game.ExileZone; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.stack.Spell; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.TargetSpell; import mage.target.common.TargetCardInExile; +import mage.target.targetpointer.FixedTargets; import mage.util.CardUtil; -import java.util.Set; +import java.util.Optional; import java.util.UUID; /** @@ -34,21 +32,17 @@ public final class JestersScepter extends CardImpl { public JestersScepter(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); - // When Jester's Scepter enters the battlefield, exile the top five cards of target player's library face down. + // When Jester's Scepter enters the battlefield, exile the top five cards of target player's library face down. You may look at those cards for as long as they remain exiled. Ability ability = new EntersBattlefieldTriggeredAbility(new JestersScepterEffect(), false); ability.addTarget(new TargetPlayer()); this.addAbility(ability); - // You may look at those cards for as long as they remain exiled. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new JestersScepterLookAtCardEffect())); - // {2}, {tap}, Put a card exiled with Jester's Scepter into its owner's graveyard: Counter target spell if it has the same name as that card. - Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new JestersScepterCounterEffect(), new ManaCostsImpl<>("{2}")); - ability2.addCost(new TapSourceCost()); - ability2.addCost(new JestersScepterCost()); - ability2.addTarget(new TargetSpell()); - this.addAbility(ability2); - + ability = new SimpleActivatedAbility(new JestersScepterCounterEffect(), new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + ability.addCost(new JestersScepterCost()); + ability.addTarget(new TargetSpell()); + this.addAbility(ability); } private JestersScepter(final JestersScepter card) { @@ -75,22 +69,22 @@ private JestersScepterEffect(final JestersScepterEffect effect) { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Player targetedPlayer = game.getPlayer(source.getFirstTarget()); - MageObject sourceObject = game.getObject(source); - if (controller != null - && targetedPlayer != null - && sourceObject != null) { - if (targetedPlayer.getLibrary().hasCards()) { - Set cardsToExile = targetedPlayer.getLibrary().getTopCards(game, 5); - for (Card card : cardsToExile) { - if (card.moveToExile(CardUtil.getCardExileZoneId(game, source), sourceObject.getName(), source, game)) { - card.setFaceDown(true, game); - } - } - } - return true; + Player targetedPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (controller == null || targetedPlayer == null) { + return false; + } + Cards cards = new CardsImpl(targetedPlayer.getLibrary().getTopCards(game, 5)); + controller.moveCardsToExile( + cards.getCards(game), source, game, false, + CardUtil.getExileZoneId(game, source), + CardUtil.getSourceName(game, source) + ); + cards.retainZone(Zone.EXILED, game); + for (Card card : cards.getCards(game)) { + card.setFaceDown(true, game); } - return false; + game.addEffect(new JestersScepterLookAtCardEffect().setTargetPointer(new FixedTargets(cards, game)), source); + return true; } @Override @@ -122,26 +116,15 @@ public JestersScepterLookAtCardEffect copy() { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (affectedControllerId.equals(source.getControllerId())) { - Card card = game.getCard(objectId); - if (card != null) { - MageObject sourceObject = game.getObject(source); - if (sourceObject == null) { - return false; - } - UUID exileId = CardUtil.getCardExileZoneId(game, source); - ExileZone exile = game.getExile().getExileZone(exileId); - return exile != null - && exile.contains(objectId); - } - } - return false; + return objectId != null + && source.isControlledBy(affectedControllerId) + && this.getTargetPointer().getTargets(game, source).contains(objectId); } } class JestersScepterCost extends CostImpl { - public JestersScepterCost() { + JestersScepterCost() { this.text = "Put a card exiled with {this} into its owner's graveyard"; } @@ -152,37 +135,31 @@ private JestersScepterCost(final JestersScepterCost cost) { @Override public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); - if (controller != null) { - TargetCardInExile target = new TargetCardInExile(new FilterCard(), CardUtil.getCardExileZoneId(game, ability)); - target.withNotTarget(true); - Cards cards = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, ability)); - if (cards != null - && !cards.isEmpty() - && controller.choose(Outcome.Benefit, cards, target, source, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - if (controller.moveCardToGraveyardWithInfo(card, source, game, Zone.EXILED)) { - if (card instanceof SplitCard) { - game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", ((SplitCard) card).getLeftHalfCard().getName()); - game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment2", ((SplitCard) card).getRightHalfCard().getName()); - } else if (card instanceof ModalDoubleFacedCard) { - game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", ((ModalDoubleFacedCard) card).getLeftHalfCard().getName()); - game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment2", ((ModalDoubleFacedCard) card).getRightHalfCard().getName()); - } else { - game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", card.getName()); - } - paid = true; - } - } - } + if (controller == null) { + return paid; } + TargetCardInExile target = new TargetCardInExile( + 0, 1, StaticFilters.FILTER_CARD, CardUtil.getExileZoneId(game, source) + ); + target.withNotTarget(true); + controller.choose(Outcome.Neutral, target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return paid; + } + controller.moveCards(card, Zone.GRAVEYARD, source, game); + source.getEffects().setValue("graveyardCard", card); + paid = true; return paid; } @Override public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { - Player player = game.getPlayer(controllerId); - return player != null; + return Optional + .ofNullable(CardUtil.getExileZoneId(game, source)) + .map(game.getExile()::getExileZone) + .map(e -> !e.isEmpty()) + .orElse(false); } @Override @@ -195,7 +172,7 @@ class JestersScepterCounterEffect extends OneShotEffect { JestersScepterCounterEffect() { super(Outcome.Detriment); - staticText = "Counter target spell if it has the same name as that card"; + staticText = "counter target spell if it has the same name as that card"; } private JestersScepterCounterEffect(final JestersScepterCounterEffect effect) { @@ -205,15 +182,11 @@ private JestersScepterCounterEffect(final JestersScepterCounterEffect effect) { @Override public boolean apply(Game game, Ability source) { Spell spell = game.getStack().getSpell(getTargetPointer().getFirst(game, source)); - if (spell != null) { - String nameOfExiledCardPayment = (String) game.getState().getValue(source.getSourceId() + "_nameOfExiledCardPayment"); - String nameOfExiledCardPayment2 = (String) game.getState().getValue(source.getSourceId() + "_nameOfExiledCardPayment2"); - if (CardUtil.haveSameNames(spell.getCard(), nameOfExiledCardPayment, game) - || CardUtil.haveSameNames(spell.getCard(), nameOfExiledCardPayment2, game)) { - return game.getStack().counter(getTargetPointer().getFirst(game, source), source, game); - } - } - return false; + Card card = (Card) getValue("graveyardCard"); + return spell != null + && card != null + && spell.sharesName(card, game) + && game.getStack().counter(getTargetPointer().getFirst(game, source), source, game); } @Override