Commit 53d17162 authored by Michael Kamensky's avatar Michael Kamensky

Merge branch 'deckAnyNumber' into 'master'

DeckFormat: A deck can have any number of cards named CARDNAME.

See merge request core-developers/forge!1270
parents af3c6455 0606a009
......@@ -20,6 +20,8 @@ package forge.deck;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import forge.StaticData;
import forge.card.CardRules;
import forge.card.CardRulesPredicates;
......@@ -47,7 +49,7 @@ public enum DeckFormat {
QuestDeck ( Range.between(40, Integer.MAX_VALUE), Range.between(0, 15), 4),
Limited ( Range.between(40, Integer.MAX_VALUE), null, Integer.MAX_VALUE),
Commander ( Range.is(99), Range.between(0, 10), 1, new Predicate<CardRules>() {
private final Set<String> bannedCards = new HashSet<String>(Arrays.asList(
private final Set<String> bannedCards = ImmutableSet.of(
"Adriana's Valor", "Advantageous Proclamation", "Amulet of Quoz", "Ancestral Recall", "Assemble the Rank and Vile",
"Backup Plan", "Balance", "Biorhythm", "Black Lotus", "Brago's Favor", "Braids, Cabal Minion", "Bronze Tablet",
"Channel", "Chaos Orb", "Coalition Victory", "Contract from Below", "Darkpact", "Demonic Attorney", "Double Stroke",
......@@ -59,7 +61,7 @@ public enum DeckFormat {
"Rebirth", "Recurring Nightmare", "Rofellos, Llanowar Emissary", "Secret Summoning", "Secrets of Paradise",
"Sentinel Dispatch", "Shahrazad", "Sovereign's Realm", "Summoner's Bond", "Sundering Titan", "Sway of the Stars",
"Sylvan Primordial", "Tempest Efreet", "Time Vault", "Time Walk", "Timmerian Fiends", "Tinker", "Tolarian Academy",
"Trade Secrets", "Unexpected Potential", "Upheaval", "Weight Advantage", "Worldfire", "Worldknit", "Yawgmoth's Bargain"));
"Trade Secrets", "Unexpected Potential", "Upheaval", "Weight Advantage", "Worldfire", "Worldknit", "Yawgmoth's Bargain");
@Override
public boolean apply(CardRules rules) {
if (bannedCards.contains(rules.getName())) {
......@@ -70,8 +72,8 @@ public enum DeckFormat {
}),
Pauper ( Range.is(60), Range.between(0, 10), 1),
Brawl ( Range.is(59), Range.between(0, 15), 1, null, new Predicate<PaperCard>() {
private final Set<String> bannedCards = new HashSet<String>(Arrays.asList(
"Baral, Chief of Compliance","Smuggler's Copter","Sorcerous Spyglass"));
private final Set<String> bannedCards = ImmutableSet.of(
"Baral, Chief of Compliance","Smuggler's Copter","Sorcerous Spyglass");
@Override
public boolean apply(PaperCard card) {
//why do we need to hard code the bannings here - they are defined in the GameFormat predicate used below
......@@ -81,7 +83,7 @@ public enum DeckFormat {
return StaticData.instance() == null ? false : StaticData.instance().getBrawlPredicate().apply(card);
}
}) {
private final ImmutableSet<String> bannedCommanders = ImmutableSet.of("Baral, Chief of Compliance");
private final Set<String> bannedCommanders = ImmutableSet.of("Baral, Chief of Compliance");
@Override
public boolean isLegalCommander(CardRules rules) {
......@@ -89,11 +91,11 @@ public enum DeckFormat {
}
},
TinyLeaders ( Range.is(49), Range.between(0, 10), 1, new Predicate<CardRules>() {
private final Set<String> bannedCards = new HashSet<String>(Arrays.asList(
private final Set<String> bannedCards = ImmutableSet.of(
"Ancestral Recall", "Balance", "Black Lotus", "Black Vise", "Channel", "Chaos Orb", "Contract From Below", "Counterbalance", "Darkpact", "Demonic Attorney", "Demonic Tutor", "Earthcraft", "Edric, Spymaster of Trest", "Falling Star",
"Fastbond", "Flash", "Goblin Recruiter", "Grindstone", "Hermit Druid", "Imperial Seal", "Jeweled Bird", "Karakas", "Library of Alexandria", "Mana Crypt", "Mana Drain", "Mana Vault", "Metalworker", "Mind Twist", "Mishra's Workshop",
"Mox Emerald", "Mox Jet", "Mox Pearl", "Mox Ruby", "Mox Sapphire", "Necropotence", "Shahrazad", "Skullclamp", "Sol Ring", "Strip Mine", "Survival of the Fittest", "Sword of Body and Mind", "Time Vault", "Time Walk", "Timetwister",
"Timmerian Fiends", "Tolarian Academy", "Umezawa's Jitte", "Vampiric Tutor", "Wheel of Fortune", "Yawgmoth's Will"));
"Timmerian Fiends", "Tolarian Academy", "Umezawa's Jitte", "Vampiric Tutor", "Wheel of Fortune", "Yawgmoth's Will");
@Override
public boolean apply(CardRules rules) {
......@@ -112,7 +114,7 @@ public enum DeckFormat {
return true;
}
}) {
private final ImmutableSet<String> bannedCommanders = ImmutableSet.of("Derevi, Empyrial Tactician", "Erayo, Soratami Ascendant", "Rofellos, Llanowar Emissary");
private final Set<String> bannedCommanders = ImmutableSet.of("Derevi, Empyrial Tactician", "Erayo, Soratami Ascendant", "Rofellos, Llanowar Emissary");
@Override
public boolean isLegalCommander(CardRules rules) {
......@@ -141,13 +143,6 @@ public enum DeckFormat {
private final static String ADVPROCLAMATION = "Advantageous Proclamation";
private final static String SOVREALM = "Sovereign's Realm";
private static final List<String> limitExceptions = Arrays.asList(
new String[]{"Relentless Rats", "Shadowborn Apostle", "Rat Colony"});
public static List<String> getLimitExceptions(){
return limitExceptions;
}
private DeckFormat(Range<Integer> mainRange0, Range<Integer> sideRange0, int maxCardCopies0, Predicate<CardRules> cardPoolFilter0, Predicate<PaperCard> paperCardPoolFilter0) {
mainRange = mainRange0;
sideRange = sideRange0;
......@@ -342,7 +337,6 @@ public enum DeckFormat {
//basic lands, Shadowborn Apostle, Relentless Rats and Rat Colony
final CardPool allCards = deck.getAllCardsInASinglePool(hasCommander());
final ImmutableSet<String> limitExceptions = ImmutableSet.of("Relentless Rats", "Shadowborn Apostle", "Rat Colony");
// should group all cards by name, so that different editions of same card are really counted as the same card
for (final Entry<String, Integer> cp : Aggregates.groupSumBy(allCards, PaperCard.FN_GET_NAME)) {
......@@ -351,8 +345,7 @@ public enum DeckFormat {
return TextUtil.concatWithSpace("contains the nonexisting card", cp.getKey());
}
final boolean canHaveMultiple = simpleCard.getRules().getType().isBasicLand() || limitExceptions.contains(cp.getKey());
if (!canHaveMultiple && cp.getValue() > maxCopies) {
if (!canHaveAnyNumberOf(simpleCard) && cp.getValue() > maxCopies) {
return TextUtil.concatWithSpace("must not contain more than", String.valueOf(maxCopies), "copies of the card", cp.getKey());
}
}
......@@ -370,6 +363,12 @@ public enum DeckFormat {
return null;
}
public static boolean canHaveAnyNumberOf(final IPaperCard icard) {
return icard.getRules().getType().isBasicLand()
|| Iterables.contains(icard.getRules().getMainPart().getKeywords(),
"A deck can have any number of cards named CARDNAME.");
}
public static String getPlaneSectionConformanceProblem(final CardPool planes) {
//Must contain at least 10 planes/phenomenons, but max 2 phenomenons. Singleton.
if (planes == null || planes.countAll() < 10) {
......
......@@ -201,8 +201,7 @@ public abstract class ACEditorBase<TItem extends InventoryItem, TModel extends D
int qty = itemEntry.getValue();
int max;
if (deck == null || card == null || card.getRules().getType().isBasic() ||
limit == CardLimit.None || DeckFormat.getLimitExceptions().contains(card.getName())) {
if (deck == null || card == null || limit == CardLimit.None || DeckFormat.canHaveAnyNumberOf(card)) {
max = Integer.MAX_VALUE;
}
else {
......
......@@ -730,7 +730,7 @@ public class FDeckEditor extends TabPageScreen<FDeckEditor> {
if (deck == null || card == null) {
max = Integer.MAX_VALUE;
}
else if (limit == CardLimit.None || card.getRules().getType().isBasic() || DeckFormat.getLimitExceptions().contains(card.getName())) {
else if (limit == CardLimit.None || DeckFormat.canHaveAnyNumberOf(card)) {
max = Integer.MAX_VALUE;
if (parentScreen.isLimitedEditor() && !isAddSource) {
//prevent adding more than is in other pool when editing limited decks
......
Name:Rat Colony
ManaCost:1 B
Types:Creature Rat
Text:A deck can have any number of cards named Rat Colony.
PT:2/1
K:A deck can have any number of cards named CARDNAME.
S:Mode$ Continuous | Affected$ Card.Self | AddPower$ X | References$ X | Description$ CARDNAME gets +1/+0 for each other Rat you control.
SVar:X:Count$Valid Rat.YouCtrl+Other
SVar:BuffedBy:Rat
......
Name:Relentless Rats
ManaCost:1 B B
Types:Creature Rat
Text:A deck can have any number of cards named Relentless Rats.
PT:2/2
K:A deck can have any number of cards named CARDNAME.
S:Mode$ Continuous | Affected$ Card.Self | AddPower$ X | AddToughness$ X | References$ X | Description$ CARDNAME gets +1/+1 for each other creature on the battlefield named Relentless Rats.
SVar:X:Count$Valid Creature.namedRelentless Rats+Other
SVar:BuffedBy:Creature.namedRelentless Rats
......
Name:Shadowborn Apostle
ManaCost:B
Types:Creature Human Cleric
Text:A deck can have any number of cards named Shadowborn Apostle.
PT:1/1
K:A deck can have any number of cards named CARDNAME.
A:AB$ ChangeZone | Cost$ B Sac<6/Creature.namedShadowborn Apostle/creatures named Shadowborn Apostle> | Origin$ Library | Destination$ Battlefield | ChangeType$ Creature.Demon | ChangeNum$ 1 | SpellDescription$ Search your library for a Demon creature, put it onto the battlefield, then shuffle your library.
DeckNeeds:Name$Shadowborn Apostle
DeckNeeds:Type$Demon
DeckHints:Name$Shadowborn Demon
SVar:Picture:http://www.wizards.com/global/images/magic/general/shadowborn_apostle.jpg
Oracle:A deck can have any number of cards named Shadowborn Apostle.\n{B}, Sacrifice six creatures named Shadowborn Apostle: Search your library for a Demon creature card, put it onto the battlefield, then shuffle your library.
\ No newline at end of file
Oracle:A deck can have any number of cards named Shadowborn Apostle.\n{B}, Sacrifice six creatures named Shadowborn Apostle: Search your library for a Demon creature card, put it onto the battlefield, then shuffle your library.
Name:Persistent Petitioners
ManaCost:1 U
Types:Creature Human Advisor
PT:1/3
K:A deck can have any number of cards named CARDNAME.
A:AB$ Mill | Cost$ 1 T | NumCards$ 1 | ValidTgts$ Player | TgtPrompt$ Choose a player | SpellDescription$ Target player puts the top card of their library into their graveyard.
A:AB$ Mill | Cost$ tapXType<4/Advisor> | NumCards$ 12 | ValidTgts$ Player | TgtPrompt$ Choose a player | SpellDescription$ Target player puts the top twelve cards of their library into their graveyard.
SVar:BuffedBy:Creature.namedPersistent Petitioners
DeckNeeds:Type$Advisor
Oracle:{1}, {T}: Target player puts the top card of their library into their graveyard.\nTap four untapped Advisors you control: Target player puts the top twelve cards of their library into their graveyard.\nA deck can have any number of cards named Persistent Petitioners.
......@@ -358,7 +358,7 @@ public class QuestSpellShop {
}
//If this card has an exception to the card limit, e.g.: Relentless Rats, get the quest preference
if (DeckFormat.getLimitExceptions().contains(card.getName())) {
if (DeckFormat.canHaveAnyNumberOf(card)) {
numToKeep = FModel.getQuestPreferences().getPrefInt(QPref.PLAYSET_ANY_NUMBER_SIZE);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment