Different names rework (#8823)

* turn CardChangedName into record

* Add CardLists.getDifferentNamesCount

* CostDiscard: rename to +WithDifferentNames

* CostSacrifice: use getDifferentNamesCount

* Refactor DifferentCardNames_
This commit is contained in:
Hans Mackowiak
2025-10-04 15:36:17 +02:00
committed by GitHub
parent 66a8e1f04f
commit 7acfe6c240
27 changed files with 80 additions and 87 deletions

View File

@@ -113,7 +113,7 @@ public class AiCostDecision extends CostDecisionMakerBase {
randomSubset = ability.getActivatingPlayer().getController().orderMoveToZoneList(randomSubset, ZoneType.Graveyard, ability); randomSubset = ability.getActivatingPlayer().getController().orderMoveToZoneList(randomSubset, ZoneType.Graveyard, ability);
} }
return PaymentDecision.card(randomSubset); return PaymentDecision.card(randomSubset);
} else if (type.equals("DifferentNames")) { } else if (type.contains("+WithDifferentNames")) {
CardCollection differentNames = new CardCollection(); CardCollection differentNames = new CardCollection();
CardCollection discardMe = CardLists.filter(hand, CardPredicates.hasSVar("DiscardMe")); CardCollection discardMe = CardLists.filter(hand, CardPredicates.hasSVar("DiscardMe"));
while (c > 0) { while (c > 0) {

View File

@@ -43,7 +43,6 @@ import java.util.Map.Entry;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
public class AbilityUtils { public class AbilityUtils {
private final static ImmutableList<String> cmpList = ImmutableList.of("LT", "LE", "EQ", "GE", "GT", "NE"); private final static ImmutableList<String> cmpList = ImmutableList.of("LT", "LE", "EQ", "GE", "GT", "NE");
@@ -2889,21 +2888,6 @@ public class AbilityUtils {
return max; return max;
} }
if (sq[0].startsWith("DifferentCardNames_")) {
final List<String> 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")) { if (sq[0].startsWith("MostProminentCreatureType")) {
String restriction = l[0].split(" ")[1]; String restriction = l[0].split(" ")[1];
CardCollection list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), restriction, player, c, ctb); CardCollection list = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), restriction, player, c, ctb);
@@ -3760,6 +3744,10 @@ public class AbilityUtils {
return CardUtil.getColorsFromCards(paidList).countColors(); return CardUtil.getColorsFromCards(paidList).countColors();
} }
if (string.equals("DifferentCardNames")) {
return CardLists.getDifferentNamesCount(paidList);
}
if (string.equals("DifferentColorPair")) { if (string.equals("DifferentColorPair")) {
final Set<ColorSet> diffPair = new HashSet<>(); final Set<ColorSet> diffPair = new HashSet<>();
for (final Card card : paidList) { for (final Card card : paidList) {

View File

@@ -965,7 +965,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
String name = state.getName(); String name = state.getName();
for (CardChangedName change : this.changedCardNames.values()) { for (CardChangedName change : this.changedCardNames.values()) {
if (change.isOverwrite()) { if (change.isOverwrite()) {
name = change.getNewName(); name = change.newName();
} }
} }
return alt ? StaticData.instance().getCommonCards().getName(name, true) : name; return alt ? StaticData.instance().getCommonCards().getName(name, true) : name;
@@ -980,7 +980,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
for (CardChangedName change : this.changedCardNames.values()) { for (CardChangedName change : this.changedCardNames.values()) {
if (change.isOverwrite()) { if (change.isOverwrite()) {
result = false; result = false;
} else if (change.isAddNonLegendaryCreatureNames()) { } else if (change.addNonLegendaryCreatureNames()) {
result = true; result = true;
} }
} }
@@ -1013,6 +1013,12 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
currentState.getView().updateName(currentState); currentState.getView().updateName(currentState);
} }
private record CardChangedName(String newName, boolean addNonLegendaryCreatureNames) {
public boolean isOverwrite() {
return newName != null;
}
}
public void setGamePieceType(GamePieceType gamePieceType) { public void setGamePieceType(GamePieceType gamePieceType) {
this.gamePieceType = gamePieceType; this.gamePieceType = gamePieceType;
this.view.updateGamePieceType(this); this.view.updateGamePieceType(this);

View File

@@ -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;
}
}

View File

@@ -26,12 +26,17 @@ import forge.game.spellability.TargetRestrictions;
import forge.game.staticability.StaticAbilityTapPowerValue; import forge.game.staticability.StaticAbilityTapPowerValue;
import forge.util.IterableUtil; import forge.util.IterableUtil;
import forge.util.MyRandom; import forge.util.MyRandom;
import forge.util.StreamUtil;
import forge.util.collect.FCollectionView; import forge.util.collect.FCollectionView;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collector;
import java.util.stream.Collectors;
/** /**
* <p> * <p>
@@ -480,4 +485,26 @@ public class CardLists {
// (b) including the last element // (b) including the last element
return isSubsetSum(numList, sum) || isSubsetSum(numList, sum - last); return isSubsetSum(numList, sum) || isSubsetSum(numList, sum - last);
} }
public static int getDifferentNamesCount(Iterable<Card> cardList) {
// first part the ones with SpyKit, and already collect them via
Map<Boolean, List<Card>> 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<Card> 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();
}
} }

View File

@@ -18,7 +18,6 @@
package forge.game.cost; package forge.game.cost;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
import forge.game.card.*; import forge.game.card.*;
import forge.game.player.Player; import forge.game.player.Player;
@@ -29,7 +28,6 @@ import forge.util.TextUtil;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* The Class CostDiscard. * The Class CostDiscard.
@@ -63,11 +61,20 @@ public class CostDiscard extends CostPartWithList {
public Integer getMaxAmountX(SpellAbility ability, Player payer, final boolean effect) { public Integer getMaxAmountX(SpellAbility ability, Player payer, final boolean effect) {
final Card source = ability.getHostCard(); final Card source = ability.getHostCard();
String type = this.getType(); 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; CardCollectionView handList = payer.canDiscardBy(ability, effect) ? payer.getCardsIn(ZoneType.Hand) : CardCollection.EMPTY;
if (!type.equals("Random")) { if (!type.equals("Random")) {
handList = CardLists.getValidCards(handList, type.split(";"), payer, source, ability); handList = CardLists.getValidCards(handList, type.split(";"), payer, source, ability);
} }
if (differentNames) {
return CardLists.getDifferentNamesCount(handList);
}
return handList.size(); return handList.size();
} }
@@ -92,7 +99,7 @@ public class CostDiscard extends CostPartWithList {
else if (this.getType().equals("LastDrawn")) { else if (this.getType().equals("LastDrawn")) {
sb.append("the last card you drew this turn"); 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"); sb.append(Cost.convertAmountTypeToWords(i, this.getAmount(), "Card")).append(" with different names");
} }
else { else {
@@ -145,21 +152,17 @@ public class CostDiscard extends CostPartWithList {
final Card c = payer.getLastDrawnCard(); final Card c = payer.getLastDrawnCard();
return handList.contains(c); return handList.contains(c);
} }
else if (type.equals("DifferentNames")) {
Set<String> cardNames = Sets.newHashSet();
for (Card c : handList) {
if (!c.hasNoName()) {
cardNames.add(c.getName());
}
}
return cardNames.size() >= amount;
}
else { else {
boolean sameName = false; boolean sameName = false;
boolean differentNames = false;
if (type.contains("+WithSameName")) { if (type.contains("+WithSameName")) {
sameName = true; sameName = true;
type = TextUtil.fastReplace(type, "+WithSameName", ""); type = TextUtil.fastReplace(type, "+WithSameName", "");
} }
if (type.contains("+WithDifferentNames")) {
type = type.replace("+WithDifferentNames", "");
differentNames = true;
}
if (type.contains("ChosenColor") && !source.hasChosenColor()) { if (type.contains("ChosenColor") && !source.hasChosenColor()) {
//color hasn't been chosen yet, so skip getValidCards //color hasn't been chosen yet, so skip getValidCards
} else if (!type.equals("Random") && !type.contains("X")) { } else if (!type.equals("Random") && !type.contains("X")) {
@@ -173,6 +176,10 @@ public class CostDiscard extends CostPartWithList {
} }
} }
return false; return false;
} else if (differentNames) {
if (CardLists.getDifferentNamesCount(handList) < amount) {
return false;
}
} }
int adjustment = 0; int adjustment = 0;
if (source.isInZone(ZoneType.Hand) && payer.equals(source.getOwner())) { if (source.isInZone(ZoneType.Hand) && payer.equals(source.getOwner())) {

View File

@@ -17,7 +17,6 @@
*/ */
package forge.game.cost; package forge.game.cost;
import com.google.common.collect.Sets;
import forge.card.CardType; import forge.card.CardType;
import forge.game.Game; import forge.game.Game;
import forge.game.ability.AbilityKey; import forge.game.ability.AbilityKey;
@@ -31,7 +30,6 @@ import forge.game.zone.ZoneType;
import forge.util.Lang; import forge.util.Lang;
import java.util.Map; import java.util.Map;
import java.util.Set;
/** /**
* The Class CostSacrifice. * The Class CostSacrifice.
@@ -74,16 +72,7 @@ public class CostSacrifice extends CostPartWithList {
} }
typeList = CardLists.filter(typeList, CardPredicates.canBeSacrificedBy(ability, effect)); typeList = CardLists.filter(typeList, CardPredicates.canBeSacrificedBy(ability, effect));
if (differentNames) { if (differentNames) {
// TODO rewrite with sharesName to respect Spy Kit return CardLists.getDifferentNamesCount(typeList);
final Set<String> 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 typeList.size(); return typeList.size();
} }

View File

@@ -3,5 +3,5 @@ ManaCost:3
Types:Artifact Types:Artifact
A:AB$ Mana | Cost$ T | Produced$ Any | SpellDescription$ Add one mana of any color. 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. 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. 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.

View File

@@ -3,7 +3,7 @@ ManaCost:2 G
Types:Sorcery 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. 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: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 DeckHas:Ability$Token & Type$Plant
DeckHints:Ability$Token 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. Oracle:Create a 0/1 green Plant creature token, then draw cards equal to the number of differently named creature tokens you control.

View File

@@ -3,5 +3,5 @@ ManaCost:4
Types:Artifact Creature Golem Types:Artifact Creature Golem
PT:*/* 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. 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. Oracle:Awakened Amalgam's power and toughness are each equal to the number of differently named lands you control.

View File

@@ -2,7 +2,7 @@ Name:Eerie Ultimatum
ManaCost:W W B B B G G ManaCost:W W B B B G G
Types:Sorcery 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. 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 SVar:IsReanimatorCard:TRUE
DeckHas:Ability$Graveyard DeckHas:Ability$Graveyard
Oracle:Return any number of permanent cards with different names from your graveyard to the battlefield. Oracle:Return any number of permanent cards with different names from your graveyard to the battlefield.

View File

@@ -4,7 +4,7 @@ Types:Legendary Creature Treefolk Wizard
PT:6/6 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. 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: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. 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:Y:Count$Valid Wizard.YouCtrl
SVar:PumpAll:DB$ PumpAll | ValidCards$ Wizard.YouCtrl | NumAtt$ +Z | NumDef$ +Z SVar:PumpAll:DB$ PumpAll | ValidCards$ Wizard.YouCtrl | NumAtt$ +Z | NumDef$ +Z

View File

@@ -6,6 +6,6 @@ SVar:ETBTapped:DB$ Tap | Defined$ Self | ETB$ True
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}. 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. 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: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 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. 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.

View File

@@ -3,5 +3,5 @@ ManaCost:6 G
Types:Creature Fungus Beast Types:Creature Fungus Beast
PT:5/5 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. 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. Oracle:This spell costs {X} less to cast, where X is the number of differently named lands you control.

View File

@@ -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: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:DBCounters:DB$ PutCounter | Defined$ Remembered | CounterType$ P1P1 | CounterNum$ X | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True 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 DeckHas:Ability$Token|Counters
DeckHints:Type$Artifact & Ability$Token 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. 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.

View File

@@ -3,7 +3,7 @@ ManaCost:3 B B
Types:Enchantment 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. 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: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. 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:TrigDraw:DB$ Draw | Defined$ You | NumCards$ 4 | SubAbility$ DBLoseLife
SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ 4 SVar:DBLoseLife:DB$ LoseLife | LifeAmount$ 4

View File

@@ -6,6 +6,6 @@ SVar:ETBTapped:DB$ Tap | Defined$ Self | ETB$ True
A:AB$ Mana | Cost$ T | Produced$ C | SpellDescription$ Add {C}. 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. 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: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 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. 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.

View File

@@ -3,7 +3,7 @@ ManaCost:2
Types:Artifact 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$ 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. 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 DeckHas:Type$Phyrexian|Construct|Artifact
DeckNeeds:Type$Locus|Sphere 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. 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.

View File

@@ -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: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: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: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:Y:Count$CreaturesAttackedThisTurn Creature.IsCommander+YouCtrl
SVar:HasAttackEffect:TRUE 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. 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.

View File

@@ -5,6 +5,6 @@ PT:5/5
K:Flying 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. 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 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 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. 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.

View File

@@ -5,6 +5,6 @@ PT:4/4
K:Trample 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.) 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: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 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.) 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.)

View File

@@ -8,6 +8,6 @@ SVar:TrigExile:DB$ Repeat | RepeatSubAbility$ DBExileCleanup | RepeatCheckSVar$
SVar:DBExileCleanup:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBExile SVar:DBExileCleanup:DB$ Cleanup | ClearRemembered$ True | SubAbility$ DBExile
SVar:DBExile:DB$ Dig | Defined$ TriggeredTarget | DigNum$ 4 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True SVar:DBExile:DB$ Dig | Defined$ TriggeredTarget | DigNum$ 4 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$DifferentCardNames_Card.IsRemembered SVar:X:Remembered$DifferentCardNames
SVar:Y:Count$RememberedSize 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. 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.

View File

@@ -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: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:DBShuffle:DB$ Shuffle | Defined$ You | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$DifferentCardNames_Creature.IsRemembered SVar:X:Remembered$DifferentCardNames
AI:RemoveDeck:All 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. 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.

View File

@@ -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. 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:DBDraw:DB$ Draw | NumCards$ 3 | ValidTgts$ Player | SubAbility$ DBGainLife
SVar:DBGainLife:DB$ GainLife | Defined$ ParentTarget | LifeAmount$ 3 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. 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.

View File

@@ -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: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: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:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$DifferentCardNames_Boar.YouCtrl+inRealZoneBattlefield SVar:X:Count$Valid Boar.YouCtrl$DifferentCardNames
DeckHints:Type$Boar DeckHints:Type$Boar
DeckHas: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. 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.

View File

@@ -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: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: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: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.) 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 DeckHas:Ability$Token & Type$Zombie
DeckHints:Ability$Mill DeckHints:Ability$Mill

View File

@@ -113,7 +113,7 @@ public class HumanCostDecision extends CostDecisionMakerBase {
} }
return PaymentDecision.card(randomSubset); return PaymentDecision.card(randomSubset);
} }
if (discardType.equals("DifferentNames")) { if (discardType.contains("+WithDifferentNames")) {
final CardCollection discarded = new CardCollection(); final CardCollection discarded = new CardCollection();
while (c > 0) { while (c > 0) {
final InputSelectCardsFromList inp = new InputSelectCardsFromList(controller, 1, 1, hand, ability); final InputSelectCardsFromList inp = new InputSelectCardsFromList(controller, 1, 1, hand, ability);