diff --git a/forge-ai/src/main/java/forge/ai/AiCostDecision.java b/forge-ai/src/main/java/forge/ai/AiCostDecision.java index 65d59b3c534..88de7ba4eb4 100644 --- a/forge-ai/src/main/java/forge/ai/AiCostDecision.java +++ b/forge-ai/src/main/java/forge/ai/AiCostDecision.java @@ -113,7 +113,7 @@ public class AiCostDecision extends CostDecisionMakerBase { randomSubset = ability.getActivatingPlayer().getController().orderMoveToZoneList(randomSubset, ZoneType.Graveyard, ability); } return PaymentDecision.card(randomSubset); - } else if (type.equals("DifferentNames")) { + } else if (type.contains("+WithDifferentNames")) { CardCollection differentNames = new CardCollection(); CardCollection discardMe = CardLists.filter(hand, CardPredicates.hasSVar("DiscardMe")); while (c > 0) { diff --git a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java index 78d13487b62..a7a4437854f 100644 --- a/forge-game/src/main/java/forge/game/ability/AbilityUtils.java +++ b/forge-game/src/main/java/forge/game/ability/AbilityUtils.java @@ -43,7 +43,6 @@ import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; - public class AbilityUtils { private final static ImmutableList cmpList = ImmutableList.of("LT", "LE", "EQ", "GE", "GT", "NE"); @@ -2889,21 +2888,6 @@ public class AbilityUtils { return max; } - if (sq[0].startsWith("DifferentCardNames_")) { - final List crdname = Lists.newArrayList(); - final String restriction = l[0].substring(19); - CardCollection list = CardLists.getValidCards(game.getCardsInGame(), restriction, player, c, ctb); - // TODO rewrite with sharesName to respect Spy Kit - for (final Card card : list) { - String name = card.getName(); - // CR 201.2b Those objects have different names only if each of them has at least one name and no two objects in that group have a name in common - if (!crdname.contains(name) && !name.isEmpty()) { - crdname.add(name); - } - } - return doXMath(crdname.size(), expr, c, ctb); - } - if (sq[0].startsWith("MostProminentCreatureType")) { String restriction = l[0].split(" ")[1]; CardCollection list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), restriction, player, c, ctb); @@ -3760,6 +3744,10 @@ public class AbilityUtils { return CardUtil.getColorsFromCards(paidList).countColors(); } + if (string.equals("DifferentCardNames")) { + return CardLists.getDifferentNamesCount(paidList); + } + if (string.equals("DifferentColorPair")) { final Set diffPair = new HashSet<>(); for (final Card card : paidList) { diff --git a/forge-game/src/main/java/forge/game/card/Card.java b/forge-game/src/main/java/forge/game/card/Card.java index 5033e19a81b..d5ea3aaf3e5 100644 --- a/forge-game/src/main/java/forge/game/card/Card.java +++ b/forge-game/src/main/java/forge/game/card/Card.java @@ -965,7 +965,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr String name = state.getName(); for (CardChangedName change : this.changedCardNames.values()) { if (change.isOverwrite()) { - name = change.getNewName(); + name = change.newName(); } } return alt ? StaticData.instance().getCommonCards().getName(name, true) : name; @@ -980,7 +980,7 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr for (CardChangedName change : this.changedCardNames.values()) { if (change.isOverwrite()) { result = false; - } else if (change.isAddNonLegendaryCreatureNames()) { + } else if (change.addNonLegendaryCreatureNames()) { result = true; } } @@ -1013,6 +1013,12 @@ public class Card extends GameEntity implements Comparable, IHasSVars, ITr currentState.getView().updateName(currentState); } + private record CardChangedName(String newName, boolean addNonLegendaryCreatureNames) { + public boolean isOverwrite() { + return newName != null; + } + } + public void setGamePieceType(GamePieceType gamePieceType) { this.gamePieceType = gamePieceType; this.view.updateGamePieceType(this); diff --git a/forge-game/src/main/java/forge/game/card/CardChangedName.java b/forge-game/src/main/java/forge/game/card/CardChangedName.java deleted file mode 100644 index 63dcd82ac8f..00000000000 --- a/forge-game/src/main/java/forge/game/card/CardChangedName.java +++ /dev/null @@ -1,24 +0,0 @@ -package forge.game.card; - -public class CardChangedName { - - protected String newName; - protected boolean addNonLegendaryCreatureNames = false; - - public CardChangedName(String newName, boolean addNonLegendaryCreatureNames) { - this.newName = newName; - this.addNonLegendaryCreatureNames = addNonLegendaryCreatureNames; - } - - public String getNewName() { - return newName; - } - - public boolean isOverwrite() { - return newName != null; - } - - public boolean isAddNonLegendaryCreatureNames() { - return addNonLegendaryCreatureNames; - } -} diff --git a/forge-game/src/main/java/forge/game/card/CardLists.java b/forge-game/src/main/java/forge/game/card/CardLists.java index 279499db015..8f91260b10d 100644 --- a/forge-game/src/main/java/forge/game/card/CardLists.java +++ b/forge-game/src/main/java/forge/game/card/CardLists.java @@ -26,12 +26,17 @@ import forge.game.spellability.TargetRestrictions; import forge.game.staticability.StaticAbilityTapPowerValue; import forge.util.IterableUtil; import forge.util.MyRandom; +import forge.util.StreamUtil; import forge.util.collect.FCollectionView; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Map; import java.util.function.Predicate; +import java.util.stream.Collector; +import java.util.stream.Collectors; /** *

@@ -480,4 +485,26 @@ public class CardLists { // (b) including the last element return isSubsetSum(numList, sum) || isSubsetSum(numList, sum - last); } + + public static int getDifferentNamesCount(Iterable cardList) { + // first part the ones with SpyKit, and already collect them via + Map> parted = StreamUtil.stream(cardList).collect(Collectors + .partitioningBy(Card::hasNonLegendaryCreatureNames, Collector.of(ArrayList::new, (list, c) -> { + if (!c.hasNoName() && list.stream().noneMatch(c2 -> c.sharesNameWith(c2))) { + list.add(c); + } + }, (l1, l2) -> { + l1.addAll(l2); + return l1; + }))); + List preList = parted.get(Boolean.FALSE); + + // then try to apply the SpyKit ones + for (Card c : parted.get(Boolean.TRUE)) { + if (preList.stream().noneMatch(c2 -> c.sharesNameWith(c2))) { + preList.add(c); + } + } + return preList.size(); + } } diff --git a/forge-game/src/main/java/forge/game/cost/CostDiscard.java b/forge-game/src/main/java/forge/game/cost/CostDiscard.java index e89a8213419..755c341ed14 100644 --- a/forge-game/src/main/java/forge/game/cost/CostDiscard.java +++ b/forge-game/src/main/java/forge/game/cost/CostDiscard.java @@ -18,7 +18,6 @@ package forge.game.cost; import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import forge.game.ability.AbilityKey; import forge.game.card.*; import forge.game.player.Player; @@ -29,7 +28,6 @@ import forge.util.TextUtil; import java.util.List; import java.util.Map; -import java.util.Set; /** * The Class CostDiscard. @@ -63,11 +61,20 @@ public class CostDiscard extends CostPartWithList { public Integer getMaxAmountX(SpellAbility ability, Player payer, final boolean effect) { final Card source = ability.getHostCard(); String type = this.getType(); + + boolean differentNames = false; + if (type.contains("+WithDifferentNames")) { + type = type.replace("+WithDifferentNames", ""); + differentNames = true; + } CardCollectionView handList = payer.canDiscardBy(ability, effect) ? payer.getCardsIn(ZoneType.Hand) : CardCollection.EMPTY; if (!type.equals("Random")) { handList = CardLists.getValidCards(handList, type.split(";"), payer, source, ability); } + if (differentNames) { + return CardLists.getDifferentNamesCount(handList); + } return handList.size(); } @@ -92,7 +99,7 @@ public class CostDiscard extends CostPartWithList { else if (this.getType().equals("LastDrawn")) { sb.append("the last card you drew this turn"); } - else if (this.getType().equals("DifferentNames")) { + else if (this.getType().contains("+WithDifferentNames")) { sb.append(Cost.convertAmountTypeToWords(i, this.getAmount(), "Card")).append(" with different names"); } else { @@ -145,21 +152,17 @@ public class CostDiscard extends CostPartWithList { final Card c = payer.getLastDrawnCard(); return handList.contains(c); } - else if (type.equals("DifferentNames")) { - Set cardNames = Sets.newHashSet(); - for (Card c : handList) { - if (!c.hasNoName()) { - cardNames.add(c.getName()); - } - } - return cardNames.size() >= amount; - } else { boolean sameName = false; + boolean differentNames = false; if (type.contains("+WithSameName")) { sameName = true; type = TextUtil.fastReplace(type, "+WithSameName", ""); } + if (type.contains("+WithDifferentNames")) { + type = type.replace("+WithDifferentNames", ""); + differentNames = true; + } if (type.contains("ChosenColor") && !source.hasChosenColor()) { //color hasn't been chosen yet, so skip getValidCards } else if (!type.equals("Random") && !type.contains("X")) { @@ -173,6 +176,10 @@ public class CostDiscard extends CostPartWithList { } } return false; + } else if (differentNames) { + if (CardLists.getDifferentNamesCount(handList) < amount) { + return false; + } } int adjustment = 0; if (source.isInZone(ZoneType.Hand) && payer.equals(source.getOwner())) { diff --git a/forge-game/src/main/java/forge/game/cost/CostSacrifice.java b/forge-game/src/main/java/forge/game/cost/CostSacrifice.java index a99c3da8b2d..357235f88bc 100644 --- a/forge-game/src/main/java/forge/game/cost/CostSacrifice.java +++ b/forge-game/src/main/java/forge/game/cost/CostSacrifice.java @@ -17,7 +17,6 @@ */ package forge.game.cost; -import com.google.common.collect.Sets; import forge.card.CardType; import forge.game.Game; import forge.game.ability.AbilityKey; @@ -31,7 +30,6 @@ import forge.game.zone.ZoneType; import forge.util.Lang; import java.util.Map; -import java.util.Set; /** * The Class CostSacrifice. @@ -74,16 +72,7 @@ public class CostSacrifice extends CostPartWithList { } typeList = CardLists.filter(typeList, CardPredicates.canBeSacrificedBy(ability, effect)); if (differentNames) { - // TODO rewrite with sharesName to respect Spy Kit - final Set crdname = Sets.newHashSet(); - for (final Card card : typeList) { - String name = card.getName(); - // CR 201.2b Those objects have different names only if each of them has at least one name and no two objects in that group have a name in common - if (!card.hasNoName()) { - crdname.add(name); - } - } - return crdname.size(); + return CardLists.getDifferentNamesCount(typeList); } return typeList.size(); } diff --git a/forge-gui/res/cardsfolder/a/all_fates_scroll.txt b/forge-gui/res/cardsfolder/a/all_fates_scroll.txt index 1499d57f567..5b7a41b234f 100644 --- a/forge-gui/res/cardsfolder/a/all_fates_scroll.txt +++ b/forge-gui/res/cardsfolder/a/all_fates_scroll.txt @@ -3,5 +3,5 @@ ManaCost:3 Types:Artifact A:AB$ Mana | Cost$ T | Produced$ Any | SpellDescription$ Add one mana of any color. A:AB$ Draw | Cost$ 7 T Sac<1/CARDNAME> | NumCards$ X | SpellDescription$ Draw X cards, where X is the number of differently named lands you control. -SVar:X:Count$DifferentCardNames_Land.YouCtrl+inZoneBattlefield +SVar:X:Count$Valid Land.YouCtrl$DifferentCardNames Oracle:{T}: Add one mana of any color.\n{7}, {T}, Sacrifice this artifact: Draw X cards, where X is the number of differently named lands you control. diff --git a/forge-gui/res/cardsfolder/a/audience_with_trostani.txt b/forge-gui/res/cardsfolder/a/audience_with_trostani.txt index dd2ba9d7f0a..372fd29d0ff 100644 --- a/forge-gui/res/cardsfolder/a/audience_with_trostani.txt +++ b/forge-gui/res/cardsfolder/a/audience_with_trostani.txt @@ -3,7 +3,7 @@ ManaCost:2 G Types:Sorcery A:SP$ Token | TokenScript$ g_0_1_plant | SubAbility$ DBDraw | SpellDescription$ Create a 0/1 green Plant creature token, then draw cards equal to the number of differently named creature tokens you control. SVar:DBDraw:DB$ Draw | Defined$ You | NumCards$ X | StackDescription$ None -SVar:X:Count$DifferentCardNames_Creature.YouCtrl+token+inZoneBattlefield +SVar:X:Count$Valid Creature.YouCtrl+token$DifferentCardNames DeckHas:Ability$Token & Type$Plant DeckHints:Ability$Token Oracle:Create a 0/1 green Plant creature token, then draw cards equal to the number of differently named creature tokens you control. diff --git a/forge-gui/res/cardsfolder/a/awakened_amalgam.txt b/forge-gui/res/cardsfolder/a/awakened_amalgam.txt index c98e4b02b80..74720c705b9 100644 --- a/forge-gui/res/cardsfolder/a/awakened_amalgam.txt +++ b/forge-gui/res/cardsfolder/a/awakened_amalgam.txt @@ -3,5 +3,5 @@ ManaCost:4 Types:Artifact Creature Golem PT:*/* S:Mode$ Continuous | CharacteristicDefining$ True | SetPower$ X | SetToughness$ X | Description$ CARDNAME's power and toughness are each equal to the number of differently named lands you control. -SVar:X:Count$DifferentCardNames_Land.YouCtrl+inZoneBattlefield +SVar:X:Count$Valid Land.YouCtrl$DifferentCardNames Oracle:Awakened Amalgam's power and toughness are each equal to the number of differently named lands you control. diff --git a/forge-gui/res/cardsfolder/e/eerie_ultimatum.txt b/forge-gui/res/cardsfolder/e/eerie_ultimatum.txt index 355ff616eff..cba20ce6570 100644 --- a/forge-gui/res/cardsfolder/e/eerie_ultimatum.txt +++ b/forge-gui/res/cardsfolder/e/eerie_ultimatum.txt @@ -2,7 +2,7 @@ Name:Eerie Ultimatum ManaCost:W W B B B G G Types:Sorcery A:SP$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ChangeType$ Permanent.YouOwn | ChangeNumDesc$ any number of | ChangeTypeDesc$ permanent cards with different names | DifferentNames$ True | ChangeNum$ X | Hidden$ True | SpellDescription$ Return any number of permanent cards with different names from your graveyard to the battlefield. -SVar:X:Count$DifferentCardNames_Permanent.YouOwn+inZoneGraveyard +SVar:X:Count$ValidGraveyard Permanent.YouOwn$DifferentCardNames SVar:IsReanimatorCard:TRUE DeckHas:Ability$Graveyard Oracle:Return any number of permanent cards with different names from your graveyard to the battlefield. diff --git a/forge-gui/res/cardsfolder/e/euroakus.txt b/forge-gui/res/cardsfolder/e/euroakus.txt index d1f03154637..262a250357b 100644 --- a/forge-gui/res/cardsfolder/e/euroakus.txt +++ b/forge-gui/res/cardsfolder/e/euroakus.txt @@ -4,7 +4,7 @@ Types:Legendary Creature Treefolk Wizard PT:6/6 T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigToken | TriggerDescription$ When CARDNAME enters, create a number of 1/1 blue Human Wizard creature tokens equal to the number of differently named lands you control. SVar:TrigToken:DB$ Token | TokenAmount$ X | TokenScript$ u_1_1_human_wizard -SVar:X:Count$DifferentCardNames_Land.YouCtrl+inZoneBattlefield +SVar:X:Count$Valid Land.YouCtrl$DifferentCardNames A:AB$ Draw | Cost$ 4 G U | NumCards$ Y | SubAbility$ PumpAll | SpellDescription$ Draw a card for each Wizard you control. They each get +1/+1 until end of turn for each card in your hand. SVar:Y:Count$Valid Wizard.YouCtrl SVar:PumpAll:DB$ PumpAll | ValidCards$ Wizard.YouCtrl | NumAtt$ +Z | NumDef$ +Z diff --git a/forge-gui/res/cardsfolder/f/field_of_the_dead.txt b/forge-gui/res/cardsfolder/f/field_of_the_dead.txt index 39bd2e04423..d941c9e4fd6 100644 --- a/forge-gui/res/cardsfolder/f/field_of_the_dead.txt +++ b/forge-gui/res/cardsfolder/f/field_of_the_dead.txt @@ -6,6 +6,6 @@ SVar:ETBTapped:DB$ Tap | Defined$ Self | ETB$ True A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Land.Other+YouCtrl | CheckSVar$ X | SVarCompare$ GE7 | Execute$ TrigToken | TriggerDescription$ Whenever CARDNAME or another land you control enters, if you control seven or more lands with different names, create a 2/2 black Zombie creature token. SVar:TrigToken:DB$ Token | TokenScript$ b_2_2_zombie | TokenOwner$ You | TokenAmount$ 1 -SVar:X:Count$DifferentCardNames_Land.YouCtrl+inZoneBattlefield +SVar:X:Count$Valid Land.YouCtrl$DifferentCardNames DeckHas:Ability$Token Oracle:Field of the Dead enters tapped.\n{T}: Add {C}.\nWhenever Field of the Dead or another land you control enters, if you control seven or more lands with different names, create a 2/2 black Zombie creature token. diff --git a/forge-gui/res/cardsfolder/f/fungal_colossus.txt b/forge-gui/res/cardsfolder/f/fungal_colossus.txt index 54d0be698a6..0409a9e823e 100644 --- a/forge-gui/res/cardsfolder/f/fungal_colossus.txt +++ b/forge-gui/res/cardsfolder/f/fungal_colossus.txt @@ -3,5 +3,5 @@ ManaCost:6 G Types:Creature Fungus Beast PT:5/5 S:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ X | EffectZone$ All | Description$ This spell costs {X} less to cast, where X is the number of differently named lands you control. -SVar:X:Count$DifferentCardNames_Land.YouCtrl+inZoneBattlefield +SVar:X:Count$Valid Land.YouCtrl$DifferentCardNames Oracle:This spell costs {X} less to cast, where X is the number of differently named lands you control. diff --git a/forge-gui/res/cardsfolder/g/gimbal_gremlin_prodigy.txt b/forge-gui/res/cardsfolder/g/gimbal_gremlin_prodigy.txt index 9aa3b8aa800..125325c25f2 100644 --- a/forge-gui/res/cardsfolder/g/gimbal_gremlin_prodigy.txt +++ b/forge-gui/res/cardsfolder/g/gimbal_gremlin_prodigy.txt @@ -7,7 +7,7 @@ T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefiel SVar:TrigToken:DB$ Token | TokenScript$ r_0_0_a_gremlin | RememberTokens$ True | SubAbility$ DBCounters SVar:DBCounters:DB$ PutCounter | Defined$ Remembered | CounterType$ P1P1 | CounterNum$ X | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True -SVar:X:Count$DifferentCardNames_Artifact.YouCtrl+inZoneBattlefield+token +SVar:X:Count$Valid Artifact.YouCtrl+token$DifferentCardNames DeckHas:Ability$Token|Counters DeckHints:Type$Artifact & Ability$Token Oracle:Artifact creatures you control have trample.\nAt the beginning of your end step, create a 0/0 red Gremlin artifact creature token. Put X +1/+1 counters on it, where X is the number of differently named artifact tokens you control. diff --git a/forge-gui/res/cardsfolder/l/lilianas_contract.txt b/forge-gui/res/cardsfolder/l/lilianas_contract.txt index b6946fef4da..51abebdd572 100644 --- a/forge-gui/res/cardsfolder/l/lilianas_contract.txt +++ b/forge-gui/res/cardsfolder/l/lilianas_contract.txt @@ -3,7 +3,7 @@ ManaCost:3 B B Types:Enchantment T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | Execute$ DBWin | TriggerZones$ Battlefield | CheckSVar$ Contractors | SVarCompare$ GE4 | TriggerDescription$ At the beginning of your upkeep, if you control four or more Demons with different names, you win the game. SVar:DBWin:DB$ WinsGame | Defined$ You | ConditionCheckSVar$ Contractors | ConditionSVarCompare$ GE4 -SVar:Contractors:Count$DifferentCardNames_Demon.YouCtrl+inRealZoneBattlefield +SVar:Contractors:Count$Valid Demon.YouCtrl$DifferentCardNames T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigDraw | TriggerDescription$ When CARDNAME enters, you draw four cards and you lose 4 life. SVar:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 4 | SubAbility$ DBLoseLife SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ 4 diff --git a/forge-gui/res/cardsfolder/m/mazes_end.txt b/forge-gui/res/cardsfolder/m/mazes_end.txt index 5b0c03d6450..016ff08dcbd 100644 --- a/forge-gui/res/cardsfolder/m/mazes_end.txt +++ b/forge-gui/res/cardsfolder/m/mazes_end.txt @@ -6,6 +6,6 @@ SVar:ETBTapped:DB$ Tap | Defined$ Self | ETB$ True A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}. A:AB$ ChangeZone | Cost$ 3 T Return<1/CARDNAME> | ChangeType$ Gate | ChangeNum$ 1 | Origin$ Library | Destination$ Battlefield | AILogic$ MazesEnd | SubAbility$ DBWin | SpellDescription$ Search your library for a Gate card, put it onto the battlefield, then shuffle. If you control ten or more Gates with different names, you win the game. SVar:DBWin:DB$ WinsGame | Defined$ You | ConditionCheckSVar$ MazeGate | ConditionSVarCompare$ GE10 -SVar:MazeGate:Count$DifferentCardNames_Gate.YouCtrl+inZoneBattlefield +SVar:X:Count$Valid Gate.YouCtrl$DifferentCardNames AI:RemoveDeck:Random Oracle:Maze's End enters tapped.\n{T}: Add {C}.\n{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. If you control ten or more Gates with different names, you win the game. diff --git a/forge-gui/res/cardsfolder/m/monument_to_perfection.txt b/forge-gui/res/cardsfolder/m/monument_to_perfection.txt index 8de4eb6e0c1..a39c9e3356b 100644 --- a/forge-gui/res/cardsfolder/m/monument_to_perfection.txt +++ b/forge-gui/res/cardsfolder/m/monument_to_perfection.txt @@ -3,7 +3,7 @@ ManaCost:2 Types:Artifact A:AB$ ChangeZone | Cost$ 3 T | Origin$ Library | Destination$ Hand | ChangeType$ Land.Basic,Land.Locus,Land.Sphere | ChangeTypeDesc$ basic, Sphere, or Locus land card | SpellDescription$ Search your library for a basic, Sphere, or Locus land card, reveal it, put it into your hand, then shuffle. A:AB$ Animate | Cost$ 3 | CheckSVar$ CountAll | SVarCompare$ GE9 | Power$ 9 | Toughness$ 9 | Types$ Artifact,Creature,Phyrexian,Construct | RemoveCreatureTypes$ True | RemoveAllAbilities$ True | Defined$ Self | Keywords$ Indestructible & Toxic:9 | Duration$ Permanent | SpellDescription$ CARDNAME becomes a 9/9 Phyrexian Construct artifact creature, loses all abilities, and gains indestructible and toxic 9. Activate only if there are nine or more lands with different names among the basic, Sphere, and Locus lands you control. -SVar:CountAll:Count$DifferentCardNames_Land.YouCtrl+inZoneBattlefield+Basic,Sphere.YouCtrl+inZoneBattlefield,Locus.YouCtrl+inZoneBattlefield +SVar:CountAll:Count$Valid Land.YouCtrl+Basic,Sphere.YouCtrl,Locus.YouCtrl$DifferentCardNames DeckHas:Type$Phyrexian|Construct|Artifact DeckNeeds:Type$Locus|Sphere Oracle:{3}, {T}: Search your library for a basic, Sphere, or Locus land card, reveal it, put it into your hand, then shuffle.\n{3}: Monument to Perfection becomes a 9/9 Phyrexian Construct artifact creature, loses all abilities, and gains indestructible and toxic 9. Activate only if there are nine or more lands with different names among the basic, Sphere, and Locus lands you control. diff --git a/forge-gui/res/cardsfolder/n/neriv_crackling_vanguard.txt b/forge-gui/res/cardsfolder/n/neriv_crackling_vanguard.txt index 943d36038bf..b5c3405fbe8 100644 --- a/forge-gui/res/cardsfolder/n/neriv_crackling_vanguard.txt +++ b/forge-gui/res/cardsfolder/n/neriv_crackling_vanguard.txt @@ -11,7 +11,7 @@ SVar:TrigExile:DB$ Dig | Defined$ You | DigNum$ X | ChangeNum$ All | Destination SVar:DBEffectYou:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ STPlay | SubAbility$ DBCleanup | ForgetOnMoved$ Exile | Duration$ Permanent SVar:STPlay:Mode$ Continuous | MayPlay$ True | Affected$ Card.IsRemembered | AffectedZone$ Exile | CheckSVar$ Y | Description$ During any turn you attacked with a commander, you may play those cards. SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True -SVar:X:Count$DifferentCardNames_Permanent.token+YouCtrl+inZoneBattlefield +SVar:X:Count$Valid Permanent.YouCtrl+token$DifferentCardNames SVar:Y:Count$CreaturesAttackedThisTurn Creature.IsCommander+YouCtrl SVar:HasAttackEffect:TRUE Oracle:Flying,deathtouch\nWhen Neriv enters, create two 1/1 red Goblin creature tokens.\nWhenever Neriv attacks, exile a number of cards from the top of your library equal to the number of differently named tokens you control. During any turn you attacked with a commander, you may play those cards. diff --git a/forge-gui/res/cardsfolder/o/ormos_archive_keeper.txt b/forge-gui/res/cardsfolder/o/ormos_archive_keeper.txt index a8162c859d5..417b4d2919c 100644 --- a/forge-gui/res/cardsfolder/o/ormos_archive_keeper.txt +++ b/forge-gui/res/cardsfolder/o/ormos_archive_keeper.txt @@ -5,6 +5,6 @@ PT:5/5 K:Flying R:Event$ Draw | ActiveZones$ Battlefield | ValidPlayer$ You | IsPresent$ Card.YouOwn | PresentZone$ Library | PresentCompare$ EQ0 | ReplaceWith$ AddCounters | Description$ If you would draw a card while your library has no cards in it, instead put five +1/+1 counters on CARDNAME. SVar:AddCounters:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ 5 | Defined$ Self -A:AB$ Draw | Cost$ 1 U U Discard<3/DifferentNames> | NumCards$ 5 | SpellDescription$ Draw five cards. +A:AB$ Draw | Cost$ 1 U U Discard<3/Card+WithDifferentNames> | NumCards$ 5 | SpellDescription$ Draw five cards. AI:RemoveDeck:All Oracle:Flying\nIf you would draw a card while your library has no cards in it, instead put five +1/+1 counters on Ormos, Archive Keeper.\n{1}{U}{U}, Discard three cards with different names: Draw five cards. diff --git a/forge-gui/res/cardsfolder/s/sandsteppe_war_riders.txt b/forge-gui/res/cardsfolder/s/sandsteppe_war_riders.txt index 29f0206aa2c..05084018acc 100644 --- a/forge-gui/res/cardsfolder/s/sandsteppe_war_riders.txt +++ b/forge-gui/res/cardsfolder/s/sandsteppe_war_riders.txt @@ -5,6 +5,6 @@ PT:4/4 K:Trample T:Mode$ Phase | Phase$ BeginCombat | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ At the beginning of combat on your turn, bolster X, where X is the number of differently named artifact tokens you control. (Choose a creature with the least toughness among creatures you control and put X +1/+1 counters on it.) SVar:TrigPutCounter:DB$ PutCounter | CounterType$ P1P1 | CounterNum$ X | Bolster$ True -SVar:X:Count$DifferentCardNames_Artifact.YouCtrl+token+inZoneBattlefield +SVar:X:Count$Valid Artifact.YouCtrl+token$DifferentCardNames DeckHas:Ability$Counters Oracle:Trample\nAt the beginning of combat on your turn, bolster X, where X is the number of differently named artifact tokens you control. (Choose a creature with the least toughness among creatures you control and put X +1/+1 counters on it.) diff --git a/forge-gui/res/cardsfolder/s/scalpelexis.txt b/forge-gui/res/cardsfolder/s/scalpelexis.txt index 050f476d302..e6820f26a0e 100644 --- a/forge-gui/res/cardsfolder/s/scalpelexis.txt +++ b/forge-gui/res/cardsfolder/s/scalpelexis.txt @@ -8,6 +8,6 @@ SVar:TrigExile:DB$ Repeat | RepeatSubAbility$ DBExileCleanup | RepeatCheckSVar$ SVar:DBExileCleanup:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBExile SVar:DBExile:DB$ Dig | Defined$ TriggeredTarget | DigNum$ 4 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True -SVar:X:Count$DifferentCardNames_Card.IsRemembered +SVar:X:Remembered$DifferentCardNames SVar:Y:Count$RememberedSize Oracle:Flying (This creature can't be blocked except by creatures with flying or reach.)\nWhenever Scalpelexis deals combat damage to a player, that player exiles the top four cards of their library. If two or more of those cards have the same name, repeat this process. diff --git a/forge-gui/res/cardsfolder/s/signal_the_clans.txt b/forge-gui/res/cardsfolder/s/signal_the_clans.txt index d449618dc05..a0a4574f962 100644 --- a/forge-gui/res/cardsfolder/s/signal_the_clans.txt +++ b/forge-gui/res/cardsfolder/s/signal_the_clans.txt @@ -6,6 +6,6 @@ SVar:DBChoose:DB$ ChooseCard | Defined$ You | Amount$ 1 | AtRandom$ True | Choic SVar:DBChange:DB$ ChangeZone | Origin$ Library | Destination$ Hand | Defined$ ChosenCard | StackDescription$ None | SubAbility$ DBShuffle | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ3 SVar:DBShuffle:DB$ Shuffle | Defined$ You | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True -SVar:X:Count$DifferentCardNames_Creature.IsRemembered +SVar:X:Remembered$DifferentCardNames AI:RemoveDeck:All Oracle:Search your library for three creature cards and reveal them. If you reveal three cards with different names, choose one of them at random and put that card into your hand. Shuffle the rest into your library. diff --git a/forge-gui/res/cardsfolder/s/survey_mechan.txt b/forge-gui/res/cardsfolder/s/survey_mechan.txt index aba0c2c2635..b87e31264cf 100644 --- a/forge-gui/res/cardsfolder/s/survey_mechan.txt +++ b/forge-gui/res/cardsfolder/s/survey_mechan.txt @@ -7,5 +7,5 @@ K:Hexproof A:AB$ DealDamage | Cost$ 10 Sac<1/CARDNAME> | ValidTgts$ Any | NumDmg$ 3 | ReduceCost$ X | SubAbility$ DBDraw | SpellDescription$ It deals 3 damage to any target. Target player draws three cards and gains 3 life. This ability costs {X} less to activate, where X is the number of differently named lands you control. SVar:DBDraw:DB$ Draw | NumCards$ 3 | ValidTgts$ Player | SubAbility$ DBGainLife SVar:DBGainLife:DB$ GainLife | Defined$ ParentTarget | LifeAmount$ 3 -SVar:X:Count$DifferentCardNames_Land.YouCtrl+inZoneBattlefield +SVar:X:Count$Valid Land.YouCtrl$DifferentCardNames Oracle:Flying\nHexproof (This creature can't be the target of spells or abilities your opponents control.)\n{10}, Sacrifice this creature: It deals 3 damage to any target. Target player draws three cards and gains 3 life. This ability costs {X} less to activate, where X is the number of differently named lands you control. diff --git a/forge-gui/res/cardsfolder/s/swine_rebellion.txt b/forge-gui/res/cardsfolder/s/swine_rebellion.txt index c740ec7f736..abb939ffff9 100644 --- a/forge-gui/res/cardsfolder/s/swine_rebellion.txt +++ b/forge-gui/res/cardsfolder/s/swine_rebellion.txt @@ -6,7 +6,7 @@ SVar:DBConjureAll:DB$ MakeCard | Conjure$ True | Names$ First Little Pig,Second SVar:DBConjureTwo:DB$ MakeCard | Conjure$ True | SpellbookName$ the Three Pigs | Spellbook$ First Little Pig,Second Little Pig,Third Little Pig | SpellbookAmount$ 2 | RememberMade$ True | Zone$ Hand | SubAbility$ DBPutBattlefield SVar:DBPutBattlefield:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChangeType$ Card.IsRemembered | ChangeNum$ 1 | Mandatory$ True | SelectPrompt$ Select a card to put onto the battlefield | SubAbility$ DBCleanup SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True -SVar:X:Count$DifferentCardNames_Boar.YouCtrl+inRealZoneBattlefield +SVar:X:Count$Valid Boar.YouCtrl$DifferentCardNames DeckHints:Type$Boar DeckHas:Type$Boar Oracle:If you control three or more Boars with different names, conjure each card from the Three Pigs spellbook onto the battlefield.\nIf you control two or fewer Boars with different names, conjure two cards of your choice from the Three Pigs spellbook into your hand, then put one of them onto the battlefield. diff --git a/forge-gui/res/cardsfolder/t/the_necrobloom.txt b/forge-gui/res/cardsfolder/t/the_necrobloom.txt index b615362e816..bc8fc3cf677 100644 --- a/forge-gui/res/cardsfolder/t/the_necrobloom.txt +++ b/forge-gui/res/cardsfolder/t/the_necrobloom.txt @@ -6,7 +6,7 @@ T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Land.Y SVar:TrigBranch:DB$ Branch | BranchConditionSVar$ X | BranchConditionSVarCompare$ GE7 | TrueSubAbility$ DBZombie | FalseSubAbility$ DBPlant SVar:DBPlant:DB$ Token | TokenAmount$ 1 | TokenScript$ g_0_1_plant | TokenOwner$ You SVar:DBZombie:DB$ Token | TokenAmount$ 1 | TokenScript$ b_2_2_zombie | TokenOwner$ You -SVar:X:Count$DifferentCardNames_Land.YouCtrl+inZoneBattlefield +SVar:X:Count$Valid Land.YouCtrl$DifferentCardNames S:Mode$ Continuous | AffectedZone$ Graveyard | Affected$ Land.YouOwn | AddKeyword$ Dredge:2 | Description$ Land cards in your graveyard have dredge 2. (You may return a land card from your graveyard to your hand and mill two cards instead of drawing a card.) DeckHas:Ability$Token & Type$Zombie DeckHints:Ability$Mill diff --git a/forge-gui/src/main/java/forge/player/HumanCostDecision.java b/forge-gui/src/main/java/forge/player/HumanCostDecision.java index cab21c22947..b8824798392 100644 --- a/forge-gui/src/main/java/forge/player/HumanCostDecision.java +++ b/forge-gui/src/main/java/forge/player/HumanCostDecision.java @@ -113,7 +113,7 @@ public class HumanCostDecision extends CostDecisionMakerBase { } return PaymentDecision.card(randomSubset); } - if (discardType.equals("DifferentNames")) { + if (discardType.contains("+WithDifferentNames")) { final CardCollection discarded = new CardCollection(); while (c > 0) { final InputSelectCardsFromList inp = new InputSelectCardsFromList(controller, 1, 1, hand, ability);