Merge branch 'master' into fix_hints_on_ward

# Conflicts:
#	Mage.Sets/src/mage/cards/g/GavonyDawnguard.java
This commit is contained in:
Alex Vasile 2022-05-12 08:35:45 -06:00
commit f0b28ff21b
5305 changed files with 66292 additions and 32486 deletions

View file

@ -63,13 +63,6 @@
<version>0.9.1</version>
</dependency>
<dependency>
<!-- image scaling for card images -->
<!-- TODO: library is dead, must be replaced -->
<groupId>com.mortennobel</groupId>
<artifactId>java-image-scaling</artifactId>
<version>0.8.6</version>
</dependency>
<dependency>
<!-- graphic lib to draw GUI with effects -->
<!-- TODO: library is dead, must be replaced -->

View file

@ -110,7 +110,7 @@ public class DeckEditorPanel extends javax.swing.JPanel {
// deck legality cards selection
Arrays.stream(deckLegalityDisplay.getComponents())
.filter(c -> c instanceof LegalityLabel)
.filter(LegalityLabel.class::isInstance)
.forEach(c -> {
c.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {

View file

@ -9,9 +9,9 @@
<Value id="APPLICATION_EXCLUDE"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[600, 450]"/>
<Dimension value="[875, 475]"/>
</Property>
<Property name="resizable" type="boolean" value="false"/>
<Property name="resizable" type="boolean" value="true"/>
</Properties>
<SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
@ -71,8 +71,8 @@
<Container class="java.awt.Panel" name="pnlPacks">
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridLayout">
<Property name="columns" type="int" value="13"/>
<Property name="rows" type="int" value="12"/>
<Property name="columns" type="int" value="14"/>
<Property name="rows" type="int" value="14"/>
</Layout>
</Container>
<Container class="javax.swing.JPanel" name="pnlSelect">

View file

@ -116,15 +116,15 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog {
setTitle("Random Booster Draft Packs Selector");
setModal(true);
setModalExclusionType(java.awt.Dialog.ModalExclusionType.APPLICATION_EXCLUDE);
setPreferredSize(new java.awt.Dimension(600, 450));
setResizable(false);
setPreferredSize(new java.awt.Dimension(875, 475));
setResizable(true);
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent evt) {
formWindowClosing(evt);
}
});
pnlPacks.setLayout(new java.awt.GridLayout(12, 13));
pnlPacks.setLayout(new java.awt.GridLayout(14, 14));
pnlSelect.setLayout(new javax.swing.BoxLayout(pnlSelect, javax.swing.BoxLayout.LINE_AXIS));

View file

@ -508,7 +508,7 @@ public class CallbackClientImpl implements CallbackClient {
.append("<br/>").append("<b>/h username </b> - show player's stats (history)")
.append("<br/>").append("<b>/w username message</b> - send private message to player (whisper)")
.append("<br/>").append("<b>/pings</b> - show players and watchers ping")
.append("<br/>").append("<b>/fix</b> - fix freezed game")
.append("<br/>").append("<b>/fix</b> - fix frozen game")
.toString(),
null, null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE);
break;
@ -628,7 +628,7 @@ public class CallbackClientImpl implements CallbackClient {
logger.fatal("Client error\n", ex);
String errorMessage = ex.getMessage();
if (errorMessage == null || errorMessage.isEmpty() || errorMessage.equals("Null")) {
errorMessage = ex.getClass().getSimpleName() + " - look server or client logs for more details";
errorMessage = ex.getClass().getSimpleName() + " - look at server or client logs for more details";
}
frame.showError("Server's error: " + errorMessage);
}

View file

@ -3,8 +3,6 @@ package mage.client.util;
import java.awt.*;
import java.awt.image.BufferedImage;
import com.mortennobel.imagescaling.ResampleOp;
/**
*
* @author user
@ -95,9 +93,12 @@ public final class TransformedImageCache {
}
private static BufferedImage resizeImage(BufferedImage original, int width, int height) {
ResampleOp resampleOp = new ResampleOp(width, height);
BufferedImage image = resampleOp.filter(original, null);
return image;
Image scaled = original.getScaledInstance(width, height, Image.SCALE_SMOOTH);
BufferedImage output = new BufferedImage(width, height, original.getType());
Graphics2D graphics = output.createGraphics();
graphics.drawImage(scaled, 0, 0, null);
graphics.dispose();
return output;
}
public static BufferedImage getResizedImage(BufferedImage image, int width, int height) {

View file

@ -49,8 +49,8 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
rightHalf.manaCostString = ManaSymbols.getClearManaCost(cardView.getRightSplitCostsStr());
leftHalf.manaCostString = ManaSymbols.getClearManaCost(cardView.getLeftSplitCostsStr());
rightHalf.color = getColorFromManaCostHack(cardView.getRightSplitCostsStr());
leftHalf.color = getColorFromManaCostHack(cardView.getLeftSplitCostsStr());
rightHalf.color = new ObjectColor(cardView.getRightSplitCostsStr());
leftHalf.color = new ObjectColor(cardView.getLeftSplitCostsStr());
parseRules(view.getRightSplitRules(), rightHalf.keywords, rightHalf.rules);
parseRules(view.getLeftSplitRules(), leftHalf.keywords, leftHalf.rules);
@ -123,24 +123,6 @@ public class ModernSplitCardRenderer extends ModernCardRenderer {
}
}
// Ugly hack used here because the card database doesn't actually store color
// for each half of split cards separately.
private ObjectColor getColorFromManaCostHack(String costs) {
ObjectColor c = new ObjectColor();
if (costs.contains("W")) {
c.setWhite(true);
} else if (costs.contains("U")) {
c.setBlue(true);
} else if (costs.contains("B")) {
c.setBlack(true);
} else if (costs.contains("R")) {
c.setRed(true);
} else if (costs.contains("G")) {
c.setGreen(true);
}
return c;
}
@Override
protected void drawBackground(Graphics2D g) {
if (cardView.isFaceDown()) {

View file

@ -28,6 +28,7 @@ public class GathererSymbols implements Iterable<DownloadJob> {
private static final String[] symbols = {"W", "U", "B", "R", "G",
"W/U", "U/B", "B/R", "R/G", "G/W", "W/B", "U/R", "B/G", "R/W", "G/U",
"W/U/P", "U/B/P", "B/R/P", "R/G/P", "G/W/P", "W/B/P", "U/R/P", "B/G/P", "R/W/P", "G/U/P",
"2/W", "2/U", "2/B", "2/R", "2/G",
"WP", "UP", "BP", "RP", "GP",
"X", "S", "T", "Q", "C", "E"};

View file

@ -189,7 +189,7 @@ public class ScryfallImageSupportCards {
add("ALA"); // Shards of Alara
add("PALA"); // Shards of Alara Promos
add("DD2"); // Duel Decks: Jace vs. Chandra
add("PWP09"); // Wizards Play Network 2009
add("PW09"); // Wizards Play Network 2009
add("PDTP"); // Duels of the Planeswalkers 2009 Promos
//add("PMPS09"); // Magic Premiere Shop 2009
add("P09"); // Magic Player Rewards 2009
@ -209,7 +209,7 @@ public class ScryfallImageSupportCards {
add("DDD"); // Duel Decks: Garruk vs. Liliana
add("H09"); // Premium Deck Series: Slivers
add("PDP10"); // Duels of the Planeswalkers 2010 Promos
add("PWP10"); // Wizards Play Network 2010
add("PW10"); // Wizards Play Network 2010
//add("PMPS10"); // Magic Premiere Shop 2010
add("P10"); // Magic Player Rewards 2010
add("G10"); // Judge Gift Cards 2010
@ -230,7 +230,7 @@ public class ScryfallImageSupportCards {
add("TD0"); // Magic Online Theme Decks
add("PD2"); // Premium Deck Series: Fire and Lightning
//add("PMPS11"); // Magic Premiere Shop 2011
add("PWP11"); // Wizards Play Network 2011
add("PW11"); // Wizards Play Network 2011
//add("PS11"); // Salvat 2011
add("P11"); // Magic Player Rewards 2011
add("G11"); // Judge Gift Cards 2011
@ -252,7 +252,7 @@ public class ScryfallImageSupportCards {
add("ISD"); // Innistrad
add("PD3"); // Premium Deck Series: Graveborn
add("PIDW"); // IDW Comics 2012
add("PWP12"); // Wizards Play Network 2012
add("PW12"); // Wizards Play Network 2012
add("PDP12"); // Duels of the Planeswalkers 2012 Promos
add("J12"); // Judge Gift Cards 2012
add("F12"); // Friday Night Magic 2012
@ -503,6 +503,14 @@ public class ScryfallImageSupportCards {
add("MIC"); // Midnight Hunt Commander
add("VOW"); // Innistrad: Crimson Vow
add("VOC"); // Crimson Vow Commander
add("Y22"); // Alchemy: Innistrad
add("DBL"); // Innistrad: Double Feature
add("NEO"); // Kamigawa: Neon Dynasty
add("NEC"); // Neon Dynasty Commander
add("SNC"); // Streets of New Capenna
add("NCC"); // New Capenna Commander
add("SLX"); // Universes Within
add("CLB"); // Commander Legends: Battle for Baldur's Gate
}
};

View file

@ -712,6 +712,136 @@ public class ScryfallImageSupportTokens {
put("VOW/Zombie/1", "https://api.scryfall.com/cards/tvow/8/en?format=image"); // 2/2
put("VOW/Zombie/2", "https://api.scryfall.com/cards/tvow/5/en?format=image"); // */*
// UMA
put ("UMA/Citizen", "https://api.scryfall.com/cards/tuma/1/en?format=image");
put ("UMA/Drake", "https://api.scryfall.com/cards/tuma/3/en?format=image");
put ("UMA/Elemental/1", "https://api.scryfall.com/cards/tuma/13/en?format=image"); // green
put ("UMA/Elemental/2", "https://api.scryfall.com/cards/tuma/9/en?format=image");
put ("UMA/Elemental/3", "https://api.scryfall.com/cards/tuma/10/en?format=image");
put ("UMA/Faerie Rogue", "https://api.scryfall.com/cards/tuma/5/en?format=image");
put ("UMA/Homunculus", "https://api.scryfall.com/cards/tuma/4/en?format=image");
put ("UMA/Marit Lage", "https://api.scryfall.com/cards/tuma/6/en?format=image");
put ("UMA/Ooze", "https://api.scryfall.com/cards/tuma/14/en?format=image");
put ("UMA/Soldier", "https://api.scryfall.com/cards/tuma/11/en?format=image");
put ("UMA/Spark Elemental", "https://api.scryfall.com/cards/tuma/12/en?format=image");
put ("UMA/Spider", "https://api.scryfall.com/cards/tuma/15/en?format=image");
put ("UMA/Spirit/1", "https://api.scryfall.com/cards/tuma/2/en?format=image"); // white
put ("UMA/Spirit/2", "https://api.scryfall.com/cards/tuma/16/en?format=image"); // white, black
put ("UMA/Wurm", "https://api.scryfall.com/cards/tuma/7/en?format=image");
put ("UMA/Zombie", "https://api.scryfall.com/cards/tuma/8/en?format=image");
// MMA
put ("MMA/Bat", "https://api.scryfall.com/cards/tmma/5/en?format=image");
put ("MMA/Dragon", "https://api.scryfall.com/cards/tmma/9/en?format=image");
put ("MMA/Elemental", "https://api.scryfall.com/cards/tmma/11/en?format=image");
put ("MMA/Emblem Elspeth, Knight Errant", "https://api.scryfall.com/cards/tmma/16/en?format=image");
put ("MMA/Faerie Rogue", "https://api.scryfall.com/cards/tmma/14/en?format=image");
put ("MMA/Giant Warrior", "https://api.scryfall.com/cards/tmma/1/en?format=image");
put ("MMA/Goblin", "https://api.scryfall.com/cards/tmma/10/en?format=image");
put ("MMA/Goblin Rogue", "https://api.scryfall.com/cards/tmma/6/en?format=image");
put ("MMA/Illusion", "https://api.scryfall.com/cards/tmma/4/en?format=image");
put ("MMA/Kithkin Soldier", "https://api.scryfall.com/cards/tmma/2/en?format=image");
put ("MMA/Saproling", "https://api.scryfall.com/cards/tmma/12/en?format=image");
put ("MMA/Soldier", "https://api.scryfall.com/cards/tmma/3/en?format=image");
put ("MMA/Spider", "https://api.scryfall.com/cards/tmma/7/en?format=image");
put ("MMA/Treefolk Shaman", "https://api.scryfall.com/cards/tmma/13/en?format=image");
put ("MMA/Worm", "https://api.scryfall.com/cards/tmma/15/en?format=image");
put ("MMA/Zombie", "https://api.scryfall.com/cards/tmma/8/en?format=image");
// SHM
put ("SHM/Elemental/1", "https://api.scryfall.com/cards/tshm/9/en?format=image"); // black, red
put ("SHM/Elemental/2", "https://api.scryfall.com/cards/tshm/4/en?format=image"); // haste
put ("SHM/Elf Warrior/1", "https://api.scryfall.com/cards/tshm/5/en?format=image"); // green
put ("SHM/Elf Warrior/2", "https://api.scryfall.com/cards/tshm/12/en?format=image"); // white, green
put ("SHM/Faerie Rogue", "https://api.scryfall.com/cards/tshm/8/en?format=image");
put ("SHM/Giant Warrior", "https://api.scryfall.com/cards/tshm/10/en?format=image");
put ("SHM/Goblin Warrior", "https://api.scryfall.com/cards/tshm/11/en?format=image");
put ("SHM/Kithkin Soldier", "https://api.scryfall.com/cards/tshm/1/en?format=image");
put ("SHM/Rat", "https://api.scryfall.com/cards/tshm/3/en?format=image");
put ("SHM/Spider", "https://api.scryfall.com/cards/tshm/6/en?format=image");
put ("SHM/Spirit", "https://api.scryfall.com/cards/tshm/2/en?format=image");
put ("SHM/Wolf", "https://api.scryfall.com/cards/tshm/7/en?format=image");
// NEO
put ("NEO/Construct/1", "https://api.scryfall.com/cards/tneo/15/en?format=image"); // 1/1
put ("NEO/Construct/2", "https://api.scryfall.com/cards/tneo/6/en?format=image"); // haste
put ("NEO/Dragon Spirit", "https://api.scryfall.com/cards/tneo/7/en?format=image");
put ("NEO/Goblin Shaman", "https://api.scryfall.com/cards/tneo/8/en?format=image");
put ("NEO/Human Monk", "https://api.scryfall.com/cards/tneo/10/en?format=image");
put ("NEO/Emblem Kaito Shizuki", "https://api.scryfall.com/cards/tneo/18/en?format=image");
put ("NEO/Keimi", "https://api.scryfall.com/cards/tneo/13/en?format=image");
put ("NEO/Mechtitan", "https://api.scryfall.com/cards/tneo/14/en?format=image");
put ("NEO/Ninja", "https://api.scryfall.com/cards/tneo/4/en?format=image");
put ("NEO/Pilot", "https://api.scryfall.com/cards/tneo/1/en?format=image");
put ("NEO/Rat Rogue", "https://api.scryfall.com/cards/tneo/5/en?format=image");
put ("NEO/Samurai", "https://api.scryfall.com/cards/tneo/3/en?format=image");
put ("NEO/Spirit/1", "https://api.scryfall.com/cards/tneo/2/en?format=image"); // colorless
put ("NEO/Spirit/2", "https://api.scryfall.com/cards/tneo/12/en?format=image"); // */*
put ("NEO/Spirit/3", "https://api.scryfall.com/cards/tneo/11/en?format=image"); // green
put ("NEO/Spirit/4", "https://api.scryfall.com/cards/tneo/9/en?format=image"); // red
put ("NEO/Tamiyo's Notebook", "https://api.scryfall.com/cards/tneo/16/en?format=image");
put ("NEO/Emblem Tezzeret, Betrayer of Flesh", "https://api.scryfall.com/cards/tneo/19/en?format=image");
put ("NEO/Treasure", "https://api.scryfall.com/cards/tneo/17/en?format=image");
// NEC
put ("NEC/Angel", "https://api.scryfall.com/cards/tnec/2/en?format=image");
put ("NEC/Beast", "https://api.scryfall.com/cards/tnec/7/en?format=image");
put ("NEC/Elemental", "https://api.scryfall.com/cards/tnec/4/en?format=image");
put ("NEC/Elephant", "https://api.scryfall.com/cards/tnec/8/en?format=image");
put ("NEC/Goblin", "https://api.scryfall.com/cards/tnec/5/en?format=image");
put ("NEC/Myr", "https://api.scryfall.com/cards/tnec/11/en?format=image");
put ("NEC/Phyrexian Germ", "https://api.scryfall.com/cards/tnec/3/en?format=image");
put ("NEC/Plant", "https://api.scryfall.com/cards/tnec/9/en?format=image");
put ("NEC/Saproling", "https://api.scryfall.com/cards/tnec/10/en?format=image");
put ("NEC/Shrine", "https://api.scryfall.com/cards/tnec/1/en?format=image");
put ("NEC/Smoke Blessing", "https://api.scryfall.com/cards/tnec/6/en?format=image");
put ("NEC/Thopter", "https://api.scryfall.com/cards/tnec/12/en?format=image");
// SLD
put ("SLD/Clue", "https://api.scryfall.com/cards/sld/348/en?format=image");
put ("SLD/Faerie Rogue/1", "https://api.scryfall.com/cards/sld/13/en?format=image");
put ("SLD/Faerie Rogue/2", "https://api.scryfall.com/cards/sld/14/en?format=image");
put ("SLD/Faerie Rogue/3", "https://api.scryfall.com/cards/sld/15/en?format=image");
put ("SLD/Faerie Rogue/4", "https://api.scryfall.com/cards/sld/16/en?format=image");
put ("SLD/Treasure", "https://api.scryfall.com/cards/sld/153/en?format=image");
put ("SLD/Walker/1", "https://api.scryfall.com/cards/sld/148/en?format=image");
put ("SLD/Walker/2", "https://api.scryfall.com/cards/sld/149/en?format=image");
put ("SLD/Walker/3", "https://api.scryfall.com/cards/sld/150/en?format=image");
put ("SLD/Walker/4", "https://api.scryfall.com/cards/sld/151/en?format=image");
put ("SLD/Walker/5", "https://api.scryfall.com/cards/sld/152/en?format=image");
// 2XM
put ("2XM/Angel", "https://api.scryfall.com/cards/t2xm/3/en?format=image");
put ("2XM/Ape", "https://api.scryfall.com/cards/t2xm/12/en?format=image");
put ("2XM/Beast", "https://api.scryfall.com/cards/t2xm/13/en?format=image");
put ("2XM/Cat", "https://api.scryfall.com/cards/t2xm/4/en?format=image");
put ("2XM/Clue", "https://api.scryfall.com/cards/t2xm/22/en?format=image");
put ("2XM/Demon", "https://api.scryfall.com/cards/t2xm/9/en?format=image");
put ("2XM/Eldrazi Spawn", "https://api.scryfall.com/cards/t2xm/1/en?format=image");
put ("2XM/Elemental", "https://api.scryfall.com/cards/t2xm/20/en?format=image");
put ("2XM/Elephant", "https://api.scryfall.com/cards/t2xm/14/en?format=image");
put ("2XM/Elf Warrior", "https://api.scryfall.com/cards/t2xm/21/en?format=image");
put ("2XM/Phyrexian Germ", "https://api.scryfall.com/cards/t2xm/10/en?format=image");
put ("2XM/Golem", "https://api.scryfall.com/cards/t2xm/23/en?format=image");
put ("2XM/Human Soldier", "https://api.scryfall.com/cards/t2xm/5/en?format=image");
put ("2XM/Marit Lage", "https://api.scryfall.com/cards/t2xm/11/en?format=image");
put ("2XM/Myr", "https://api.scryfall.com/cards/t2xm/24/en?format=image");
put ("2XM/Phyrexian Myr", "https://api.scryfall.com/cards/t2xm/7/en?format=image");
put ("2XM/Ooze", "https://api.scryfall.com/cards/t2xm/15/en?format=image");
put ("2XM/Plant", "https://api.scryfall.com/cards/t2xm/16/en?format=image");
put ("2XM/Saproling", "https://api.scryfall.com/cards/t2xm/17/en?format=image");
put ("2XM/Servo", "https://api.scryfall.com/cards/t2xm/25/en?format=image");
put ("2XM/Shapeshifter", "https://api.scryfall.com/cards/t2xm/2/en?format=image");
put ("2XM/Soldier", "https://api.scryfall.com/cards/t2xm/6/en?format=image");
put ("2XM/Squirrel", "https://api.scryfall.com/cards/t2xm/18/en?format=image");
put ("2XM/Thopter/1", "https://api.scryfall.com/cards/t2xm/26/en?format=image");
put ("2XM/Thopter/2", "https://api.scryfall.com/cards/t2xm/8/en?format=image");
put ("2XM/Treasure", "https://api.scryfall.com/cards/t2xm/27/en?format=image");
put ("2XM/Tuktuk the Returned", "https://api.scryfall.com/cards/t2xm/28/en?format=image");
put ("2XM/Wolf", "https://api.scryfall.com/cards/t2xm/19/en?format=image");
put ("2XM/Phyrexian Wurm/1", "https://api.scryfall.com/cards/t2xm/29/en?format=image");
put ("2XM/Phyrexian Wurm/2", "https://api.scryfall.com/cards/t2xm/30/en?format=image");
// generate supported sets
supportedSets.clear();
for (String cardName : this.keySet()) {

View file

@ -42,6 +42,7 @@ public class ScryfallSymbolsSource implements Iterable<DownloadJob> {
// copy-past symbols list from gatherer download
private static final String[] SYMBOLS_LIST = {"W", "U", "B", "R", "G",
"W/U", "U/B", "B/R", "R/G", "G/W", "W/B", "U/R", "B/G", "R/W", "G/U",
"W/U/P", "U/B/P", "B/R/P", "R/G/P", "G/W/P", "W/B/P", "U/R/P", "B/G/P", "R/W/P", "G/U/P",
"2/W", "2/U", "2/B", "2/R", "2/G",
"WP", "UP", "BP", "RP", "GP",
"X", "S", "T", "Q", "C", "E"};

View file

@ -487,7 +487,7 @@ public final class ImageCache {
* Returns the map key for a card, without any suffixes for the image size.
*/
private static String getKey(CardView card, String name, String suffix) {
return name
return (card.isToken() ? name.replace(" Token", "") : name)
+ '#' + card.getExpansionSetCode()
+ '#' + card.getType()
+ '#' + card.getCardNumber()

View file

@ -115,6 +115,8 @@
|Generate|EMBLEM:MID|Teferi, Who Slows the Sunset||Emblem Teferi|TeferiWhoSlowsTheSunsetEmblem|
|Generate|EMBLEM:MID|Wrenn and Seven||Emblem Wrenn|WrennAndSevenEmblem|
|Generate|EMBLEM:VOW|Chandra, Dressed to Kill||Emblem Chandra|ChandraDressedToKillEmblem|
|Generate|EMBLEM:NEO|Kaito Shizuki||Emblem Kaito|KaitoShizukiEmblem|
|Generate|EMBLEM:NEO|Tezzeret, Betrayer of Flesh||Emblem Tezzeret|TezzeretBetrayerOfFleshEmblem|
# Planes
|Generate|PLANE:PCA|Plane - Academy at Tolaria West|||AcademyAtTolariaWestPlane|
@ -234,7 +236,7 @@
|Generate|TOK:ALL|Zombie|||ZombieToken|
|Generate|TOK:APC|Angel|||HauntedAngelToken|
|Generate|TOK:APC|Cat|||PenumbraBobcatToken|
|Generate|TOK:APC|Goblin Soldier|||GoblinTrenchesToken|
|Generate|TOK:APC|Goblin Soldier|||GoblinSoldierToken|
|Generate|TOK:APC|Kavu|||PenumbraKavuToken|
|Generate|TOK:APC|Saproling|||SaprolingToken|
|Generate|TOK:APC|Wurm|||PenumbraWurmToken|
@ -506,7 +508,7 @@
|Generate|TOK:CNS|Wolf|||WolfToken|
|Generate|TOK:CNS|Zombie|||ZombieToken|
|Generate|TOK:CON|Angel|||AngelToken|
|Generate|TOK:CON|Elemental|||RakkaMarElementalToken|
|Generate|TOK:CON|Elemental|||ElementalTokenWithHaste|
|Generate|TOK:CON|Saproling|||SaprolingToken|
|Generate|TOK:CON|Soldier|||SoldierToken|
|Generate|TOK:CON|Zombie|||ZombieToken|
@ -589,7 +591,7 @@
|Generate|TOK:DGM|Spirit|||TeysaEnvoyOfGhostsToken|
|Generate|TOK:DGM|Wurm|1||WurmWithTrampleToken|
|Generate|TOK:DGM|Wurm|2||Wurm55Token|
|Generate|TOK:DIS|Bird|||DovescapeToken|
|Generate|TOK:DIS|Bird|||WhiteBlueBirdToken|
|Generate|TOK:DIS|Drake|||LeafdrakeRoostDrakeToken|
|Generate|TOK:DIS|Elemental|||ResearchDevelopmentToken|
|Generate|TOK:DIS|Goblin|||RakdosGuildmageGoblinToken|
@ -643,7 +645,7 @@
|Generate|TOK:EMA|Elemental|2||CallTheSkyBreakerElementalToken|
|Generate|TOK:EMA|Elephant|||ElephantToken|
|Generate|TOK:EMA|Elf Warrior|||ElfWarriorToken|
|Generate|TOK:EMA|Goblin Soldier|||GoblinTrenchesToken|
|Generate|TOK:EMA|Goblin Soldier|||GoblinSoldierToken|
|Generate|TOK:EMA|Goblin|||GoblinToken|
|Generate|TOK:EMA|Serf|||SerfToken|
|Generate|TOK:EMA|Soldier|||SoldierToken|
@ -667,10 +669,10 @@
|Generate|TOK:EMN|Zombie|3||ZombieToken|
|Generate|TOK:EMN|Zombie|4||ZombieToken2|
|Generate|TOK:EVE|Beast|||BeastToken|
|Generate|TOK:EVE|Bird|||OwlToken|
|Generate|TOK:EVE|Bird|||BlueBirdToken|
|Generate|TOK:EVE|Elemental|||CallTheSkyBreakerElementalToken|
|Generate|TOK:EVE|Goat|||GoatToken|
|Generate|TOK:EVE|Goblin Soldier|||GoblinTrenchesToken|
|Generate|TOK:EVE|Goblin Soldier|||GoblinSoldierToken|
|Generate|TOK:EVE|Kithkin Soldier|||KithkinSoldierToken|
|Generate|TOK:EVE|Spirit|||BeckonApparitionToken|
|Generate|TOK:EVE|Wolf|||WolfToken|
@ -733,7 +735,7 @@
|Generate|TOK:HOU|Steadfast Sentinel||||
|Generate|TOK:HOU|Sunscourge Champion||||
|Generate|TOK:ICE|Caribou|||CaribouToken|
|Generate|TOK:INV|Bird|||OwlToken|
|Generate|TOK:INV|Bird|||BlueBirdToken|
|Generate|TOK:INV|Elephant|||ElephantToken|
|Generate|TOK:INV|Reflection|||ReflectionToken|
|Generate|TOK:INV|Saproling|||SaprolingToken|
@ -931,7 +933,7 @@
|Generate|TOK:MMA|Bat|||BatToken|
|Generate|TOK:MMA|Dragon|||DragonToken|
|Generate|TOK:MMA|Elemental|||WalkerOfTheGroveToken|
|Generate|TOK:MMA|Faerie Rogue|||OonaQueenFaerieToken|
|Generate|TOK:MMA|Faerie Rogue|||OonaQueenFaerieRogueToken|
|Generate|TOK:MMA|Giant Warrior|||GiantWarriorToken|
|Generate|TOK:MMA|Goblin Rogue|||GoblinRogueToken|
|Generate|TOK:MMA|Goblin|||GoblinToken|
@ -1050,7 +1052,7 @@
|Generate|TOK:RAV|Wolf|||VojaToken|
|Generate|TOK:RAV|Faerie|||FaerieToken|
|Generate|TOK:RIX|Elemental|1||RekindlingPhoenixToken|
|Generate|TOK:RIX|Elemental|2||TilonallisSummonerElementalToken|
|Generate|TOK:RIX|Elemental|2||RedElementalToken|
|Generate|TOK:RIX|Golem|||GoldForgeGarrisonGolemToken|
|Generate|TOK:RIX|Saproling|||SaprolingToken|
|Generate|TOK:ROE|Dragon|||DragonToken2|
@ -1081,12 +1083,10 @@
|Generate|TOK:SCG|Goblin|||GoblinToken|
|Generate|TOK:SCG|Soldier|||SoldierToken|
|Generate|TOK:SHM|Elemental|1||DinOfTheFireherdToken|
|Generate|TOK:SHM|Elemental|2||RedElementalToken|
|Generate|TOK:SHM|Elf Warrior|1|
|Generate|TOK:SHM|Elf Warrior|2|
|Generate|TOK:SHM|Elemental|2||ElementalMasteryElementalToken|
|Generate|TOK:SHM|Elf Warrior|1||ElfWarriorToken|
|Generate|TOK:SHM|Elf Warrior|2||RhysTheRedeemedToken|
|Generate|TOK:SHM|Faerie Rogue|||OonaQueenFaerieToken|
|Generate|TOK:SHM|Elf Warrior|2||GreenWhiteElfWarriorToken|
|Generate|TOK:SHM|Faerie Rogue|||OonaQueenFaerieRogueToken|
|Generate|TOK:SHM|Giant Warrior|||GiantBaitingGiantWarriorToken|
|Generate|TOK:SHM|Goblin Warrior|||WortTheRaidmotherToken|
|Generate|TOK:SHM|Kithkin Soldier|||KithkinSoldierToken|
@ -1139,7 +1139,7 @@
|Generate|TOK:THS|Cleric|||HeliodGodOfTheSunToken|
|Generate|TOK:THS|Elemental|||MasterOfWavesElementalToken|
|Generate|TOK:THS|Golem|||HammerOfPurphorosGolemToken|
|Generate|TOK:THS|Harpy|||AbhorrentOverlordHarpyToken|
|Generate|TOK:THS|Harpy|||HarpyToken|
|Generate|TOK:THS|Satyr|||XenagosSatyrToken|
|Generate|TOK:THS|Soldier|1||SoldierToken|
|Generate|TOK:THS|Soldier|2||SoldierToken|
@ -1192,7 +1192,7 @@
|Generate|TOK:VMA|Boar|||BoarToken|
|Generate|TOK:VMA|Demon|||ReignOfThePitToken|
|Generate|TOK:VMA|Elephant|||ElephantToken|
|Generate|TOK:VMA|Goblin Soldier|||GoblinTrenchesToken|
|Generate|TOK:VMA|Goblin Soldier|||GoblinSoldierToken|
|Generate|TOK:VMA|Goblin|||GoblinToken|
|Generate|TOK:VMA|Insect|||InsectToken|
|Generate|TOK:VMA|Reflection|||ReflectionToken|
@ -1467,7 +1467,7 @@
# KHM
|Generate|TOK:KHM|Angel Warrior|||AngelWarriorVigilanceToken|
|Generate|TOK:KHM|Bear|||BearToken|
|Generate|TOK:KHM|Bird|||OwlToken|
|Generate|TOK:KHM|Bird|||BlueBirdToken|
|Generate|TOK:KHM|Cat|||GreenCat2Token|
|Generate|TOK:KHM|Demon Berserker|||DemonBerserkerToken|
|Generate|TOK:KHM|Dragon|||DragonToken2|
@ -1665,3 +1665,99 @@
|Generate|TOK:VOW|Wolf|2||RedWolfToken|
|Generate|TOK:VOW|Zombie|1||ZombieToken|
|Generate|TOK:VOW|Zombie|2||StitcherGeralfZombieToken|
# UMA
|Generate|TOK:UMA|Citizen|||CitizenToken|
|Generate|TOK:UMA|Drake|||DrakeToken|
|Generate|TOK:UMA|Elemental|1||WalkerOfTheGroveToken|
|Generate|TOK:UMA|Elemental|2||RedElementalToken|
|Generate|TOK:UMA|Elemental|3||RedElementalToken|
|Generate|TOK:UMA|Faerie Rogue|||FaerieRogueToken|
|Generate|TOK:UMA|Homunculus|||StitchersApprenticeHomunculusToken|
|Generate|TOK:UMA|Marit Lage|||MaritLageToken|
|Generate|TOK:UMA|Ooze|||OozeToken|
|Generate|TOK:UMA|Soldier|||AkroanSoldierToken|
|Generate|TOK:UMA|Spark Elemental|||SparkElementalToken|
|Generate|TOK:UMA|Spider|||SpiderToken|
|Generate|TOK:UMA|Spirit|1||SpiritWhiteToken|
|Generate|TOK:UMA|Spirit|2||WhiteBlackSpiritToken|
|Generate|TOK:UMA|Wurm|||PenumbraWurmToken|
|Generate|TOK:UMA|Zombie|||ZombieToken|
# NEO
|Generate|TOK:NEO|Construct|1||ConstructToken|
|Generate|TOK:NEO|Construct|2||ConstructRedToken|
|Generate|TOK:NEO|Dragon Spirit|||DragonSpiritToken|
|Generate|TOK:NEO|Goblin Shaman|||FableOfTheMirrorBreakerToken|
|Generate|TOK:NEO|Human Monk|||HumanMonkToken|
|Generate|TOK:NEO|Keimi|||KeimiToken|
|Generate|TOK:NEO|Mechtitan|||MechtitanToken|
|Generate|TOK:NEO|Ninja|||NinjaToken|
|Generate|TOK:NEO|Pilot|||PilotToken|
|Generate|TOK:NEO|Rat Rogue|||RatRogueToken|
|Generate|TOK:NEO|Samurai|||SamuraiToken|
|Generate|TOK:NEO|Spirit|1||SpiritToken|
|Generate|TOK:NEO|Spirit|2||SpiritGreenXToken|
|Generate|TOK:NEO|Spirit|3||SpiritGreenToken|
|Generate|TOK:NEO|Spirit|4||SpiritRedToken|
|Generate|TOK:NEO|Tamiyo's Notebook|||TamiyosNotebookToken|
|Generate|TOK:NEO|Treasure|||TreasureToken|
# NEC
|Generate|TOK:NEC|Angel|||AngelVigilanceToken|
|Generate|TOK:NEC|Beast|||BeastToken|
|Generate|TOK:NEC|Elemental|||RedElementalToken|
|Generate|TOK:NEC|Elephant|||ElephantToken|
|Generate|TOK:NEC|Goblin|||GoblinToken|
|Generate|TOK:NEC|Myr|||MyrToken|
|Generate|TOK:NEC|Phyrexian Germ|||PhyrexianGermToken|
|Generate|TOK:NEC|Plant|||PlantToken|
|Generate|TOK:NEC|Saproling|||SaprolingToken|
|Generate|TOK:NEC|Shrine|||ShrineToken|
|Generate|TOK:NEC|Smoke Blessing|||SmokeBlessingToken|
|Generate|TOK:NEC|Thopter|||ThopterColorlessToken|
# SLD
|Generate|TOK:SLD|Clue|||ClueArtifactToken|
|Generate|TOK:SLD|Faerie Rogue|1||FaerieRogueToken|
|Generate|TOK:SLD|Faerie Rogue|2||FaerieRogueToken|
|Generate|TOK:SLD|Faerie Rogue|3||FaerieRogueToken|
|Generate|TOK:SLD|Faerie Rogue|4||FaerieRogueToken|
|Generate|TOK:SLD|Treasure|||TreasureToken|
|Generate|TOK:SLD|Walker|1||WalkerToken|
|Generate|TOK:SLD|Walker|2||WalkerToken|
|Generate|TOK:SLD|Walker|3||WalkerToken|
|Generate|TOK:SLD|Walker|4||WalkerToken|
|Generate|TOK:SLD|Walker|5||WalkerToken|
# 2XM
|Generate|TOK:2XM|Angel|||AngelToken|
|Generate|TOK:2XM|Ape|||ApeToken|
|Generate|TOK:2XM|Beast|||BeastToken|
|Generate|TOK:2XM|Cat|||CatToken|
|Generate|TOK:2XM|Clue|||ClueArtifactToken|
|Generate|TOK:2XM|Demon|||DemonToken|
|Generate|TOK:2XM|Eldrazi Spawn|||EldraziSpawnToken|
|Generate|TOK:2XM|Elemental|||VoiceOfResurgenceToken|
|Generate|TOK:2XM|Elephant|||ElephantToken|
|Generate|TOK:2XM|Elf Warrior|||GreenWhiteElfWarriorToken|
|Generate|TOK:2XM|Phyrexian Germ|||PhyrexianGermToken|
|Generate|TOK:2XM|Golem|||GolemToken|
|Generate|TOK:2XM|Human Soldier|||HumanSoldierToken|
|Generate|TOK:2XM|Marit Lage|||MaritLageToken|
|Generate|TOK:2XM|Myr|||MyrToken|
|Generate|TOK:2XM|Phyrexian Myr|||BrudicladTelchorMyrToken|
|Generate|TOK:2XM|Ooze|||OozeToken|
|Generate|TOK:2XM|Plant|||PlantToken|
|Generate|TOK:2XM|Saproling|||SaprolingToken|
|Generate|TOK:2XM|Servo|||ServoToken|
|Generate|TOK:2XM|Shapeshifter|||CribSwapShapeshifterWhiteToken|
|Generate|TOK:2XM|Soldier|||SoldierToken|
|Generate|TOK:2XM|Squirrel|||SquirrelToken|
|Generate|TOK:2XM|Thopter|1||ThopterColorlessToken|
|Generate|TOK:2XM|Thopter|2||ThopterToken|
|Generate|TOK:2XM|Treasure|||TreasureToken|
|Generate|TOK:2XM|Tuktuk the Returned|||TuktukTheReturnedToken|
|Generate|TOK:2XM|Wolf|||WolfToken|
|Generate|TOK:2XM|Phyrexian Wurm|1||WurmWithDeathtouchToken|
|Generate|TOK:2XM|Phyrexian Wurm|2||WurmWithLifelinkToken|

View file

@ -40,7 +40,7 @@ public class Connection {
// private boolean confirmEmptyManaPool;
// private String flagName;
// private UserSkipPrioritySteps userSkipPrioritySteps;
private static final String serialization = "?serializationtype=jboss";
private static final String serialization = "?serializationtype=java";
private static final String transport = "bisocket";
private static final String threadpool = "onewayThreadPool=mage.remote.CustomThreadPool";

View file

@ -32,6 +32,7 @@ import mage.game.permanent.PermanentToken;
import mage.game.permanent.token.Token;
import mage.game.stack.Spell;
import mage.game.stack.StackAbility;
import mage.game.stack.StackObject;
import mage.players.Player;
import mage.target.Target;
import mage.target.Targets;
@ -237,8 +238,8 @@ public class CardView extends SimpleCardView {
* @param card
* @param game
* @param controlled is the card view created for the card controller - used
* for morph / face down cards to know which player may
* see information for the card
* for morph / face down cards to know which player may see information for
* the card
*/
public CardView(Card card, Game game, boolean controlled) {
this(card, game, controlled, false, false);
@ -264,14 +265,12 @@ public class CardView extends SimpleCardView {
/**
* @param card
* @param game
* @param controlled is the card view created for the card controller
* - used for morph / face down cards to know which
* player may see information for the card
* @param controlled is the card view created for the card controller - used
* for morph / face down cards to know which player may see information for
* the card
* @param showFaceDownCard if true and the card is not on the battlefield,
* also a face down card is shown in the view, face
* down cards will be shown
* @param storeZone if true the card zone will be set in the zone
* attribute.
* also a face down card is shown in the view, face down cards will be shown
* @param storeZone if true the card zone will be set in the zone attribute.
*/
public CardView(Card card, Game game, boolean controlled, boolean showFaceDownCard, boolean storeZone) {
super(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), card.getTokenSetCode(), game != null, card.getTokenDescriptor());
@ -543,7 +542,7 @@ public class CardView extends SimpleCardView {
} else if (spell.getCard() != null) {
SplitCard wholeCard = ((SplitCardHalf) spell.getCard()).getParentCard();
Abilities<Ability> aftermathHalfAbilities = wholeCard.getRightHalfCard().getAbilities(game);
if (aftermathHalfAbilities.stream().anyMatch(halfAbility -> halfAbility instanceof AftermathAbility)) {
if (aftermathHalfAbilities.stream().anyMatch(AftermathAbility.class::isInstance)) {
if (ty == SpellAbilityType.SPLIT_RIGHT) {
artRect = ArtRect.AFTERMATH_BOTTOM;
} else {
@ -564,6 +563,23 @@ public class CardView extends SimpleCardView {
this.rules.add("<span color='green'><i>Chosen mode: " + mode.getEffects().getText(mode) + "</i></span>");
}
}
// show target of a spell on the stack
if (!spell.getSpellAbility().getTargets().isEmpty()) {
StackObject stackObjectTarget = null;
for (Target target : spell.getSpellAbility().getTargets()) {
for (UUID targetId : target.getTargets()) {
MageObject mo = game.getObject(targetId);
if (mo instanceof StackObject) {
stackObjectTarget = (StackObject) mo;
}
if (stackObjectTarget != null) {
this.rules.add("<span color='green'><i>Target on stack: " + stackObjectTarget.getIdName());
}
}
}
}
}
// Frame color
@ -573,7 +589,7 @@ public class CardView extends SimpleCardView {
this.frameStyle = card.getFrameStyle();
// Get starting loyalty
this.startingLoyalty = "" + card.getStartingLoyalty();
this.startingLoyalty = CardUtil.convertStartingLoyalty(card.getStartingLoyalty());
}
public CardView(MageObject object, Game game) {
@ -647,7 +663,7 @@ public class CardView extends SimpleCardView {
// Frame style
this.frameStyle = object.getFrameStyle();
// Starting loyalty. Must be extracted from an ability
this.startingLoyalty = "" + object.getStartingLoyalty();
this.startingLoyalty = CardUtil.convertStartingLoyalty(object.getStartingLoyalty());
}
protected CardView() {
@ -993,7 +1009,8 @@ public class CardView extends SimpleCardView {
}
/**
* Name of the other side (transform), flipped, modal double faces card or copying card name.
* Name of the other side (transform), flipped, modal double faces card or
* copying card name.
*
* @return name
*/

View file

@ -21,6 +21,8 @@ import mage.util.GameLog;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import mage.game.stack.StackObject;
import mage.target.Target;
/**
* @author BetaSteward_at_googlemail.com
@ -140,6 +142,24 @@ public class StackAbilityView extends CardView {
HintUtils.appendHints(rules, abilityHints);
}
}
// show target of an ability on the stack if "related objects" is empty
if (!ability.getTargets().isEmpty()
&& names.isEmpty()) {
StackObject stackObjectTarget = null;
for (Target target : ability.getTargets()) {
for (UUID targetId : target.getTargets()) {
MageObject mo = game.getObject(targetId);
if (mo instanceof StackObject) {
stackObjectTarget = (StackObject) mo;
}
if (stackObjectTarget != null) {
this.rules.add("<span color='green'><i>Targeted ability related to this card: " + game.getCard(stackObjectTarget.getSourceId()).getIdName());
}
}
}
}
}
public CardView getSourceCard() {

View file

@ -72,7 +72,7 @@ public class ConnectionTest {
void serialisation() {
final String query = make(testeeBuilder).getQuery();
assertThat(query).contains("serializationtype=jboss");
assertThat(query).contains("serializationtype=java");
}
@Test

View file

@ -0,0 +1,998 @@
package mage.deck;
import mage.MageObject;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.common.CanBeYourCommanderAbility;
import mage.abilities.common.CommanderChooseColorAbility;
import mage.abilities.keyword.CompanionAbility;
import mage.abilities.keyword.FriendsForeverAbility;
import mage.abilities.keyword.PartnerAbility;
import mage.abilities.keyword.PartnerWithAbility;
import mage.cards.Card;
import mage.cards.decks.Constructed;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckValidatorErrorType;
import mage.constants.CardType;
import mage.filter.FilterMana;
import mage.util.CardUtil;
import mage.util.ManaUtil;
import java.util.*;
import java.util.stream.Stream;
/**
* @author TheElk801
*/
public abstract class AbstractCommander extends Constructed {
protected final List<String> bannedCommander = new ArrayList<>();
protected final List<String> bannedPartner = new ArrayList<>();
protected boolean partnerAllowed = true;
public AbstractCommander(String name) {
super(name);
}
@Override
public int getDeckMinSize() {
return 98;
}
@Override
public int getSideboardMinSize() {
return 1;
}
protected abstract boolean checkBanned(Map<String, Integer> counts);
protected boolean checkCommander(Card commander) {
if ((!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) || !commander.isLegendary())
&& !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance())) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true);
return false;
}
return true;
}
private boolean checkColorIdentity(Deck deck, FilterMana colorIdentity, Set<Card> commanders) {
int piperCount = commanders
.stream()
.filter(CommanderChooseColorAbility::checkCard)
.mapToInt(x -> 1)
.sum();
if (piperCount == 0) {
boolean valid = true;
for (Card card : deck.getCards()) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false;
}
}
for (Card card : deck.getSideboard()) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false;
}
}
return valid;
}
FilterMana filterMana = new FilterMana();
Stream.concat(
deck.getCards().stream(),
deck.getSideboard().stream()
).map(Card::getColorIdentity).forEach(filterMana::addAll);
if (colorIdentity.getColorCount() + piperCount >= filterMana.getColorCount()) {
return true;
}
StringBuilder sb = new StringBuilder()
.append("Invalid color, commander color identity has ")
.append(colorIdentity.getColorCount())
.append(" color")
.append(colorIdentity.getColorCount() > 1 ? "s" : "")
.append(", plus ")
.append(piperCount)
.append(" cop")
.append(piperCount > 1 ? "ies" : "y")
.append(" of The Prismatic Piper, but the total amount of colors in the deck is ")
.append(filterMana.getColorCount());
addError(DeckValidatorErrorType.OTHER, "The Prismatic Piper", sb.toString());
return false;
}
@Override
public boolean validate(Deck deck) {
boolean valid = true;
errorsList.clear();
FilterMana colorIdentity = new FilterMana();
Set<Card> commanders = new HashSet<>();
Card companion;
int sbsize = deck.getSideboard().size();
Card card1;
Card card2;
Card card3;
Iterator<Card> iter;
switch (deck.getSideboard().size()) {
case 1:
companion = null;
commanders.add(deck.getSideboard().iterator().next());
break;
case 2:
iter = deck.getSideboard().iterator();
card1 = iter.next();
card2 = iter.next();
if (card1.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) {
companion = card1;
commanders.add(card2);
} else if (card2.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) {
companion = card2;
commanders.add(card1);
} else {
companion = null;
commanders.add(card1);
commanders.add(card2);
}
break;
case 3:
iter = deck.getSideboard().iterator();
card1 = iter.next();
card2 = iter.next();
card3 = iter.next();
if (card1.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) {
companion = card1;
commanders.add(card2);
commanders.add(card3);
} else if (card2.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) {
companion = card2;
commanders.add(card1);
commanders.add(card3);
} else if (card3.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) {
companion = card3;
commanders.add(card1);
commanders.add(card2);
} else {
companion = null;
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion");
valid = false;
}
break;
default:
companion = null;
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion");
valid = false;
}
if (companion != null && deck.getCards().size() + deck.getSideboard().size() != 101) {
addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 101 + " cards (companion doesn't count for deck size): has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
valid = false;
} else if (companion == null && deck.getCards().size() + deck.getSideboard().size() != 100) {
addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
valid = false;
}
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
valid = checkCounts(1, counts) && valid;
valid = checkBanned(counts) && valid;
Set<String> commanderNames = new HashSet<>();
for (Card commander : commanders) {
commanderNames.add(commander.getName());
}
if (commanders.size() == 2
&& commanders
.stream()
.map(MageObject::getAbilities)
.filter(abilities -> abilities.contains(PartnerAbility.getInstance()))
.count() != 2
&& commanders
.stream()
.map(MageObject::getAbilities)
.filter(abilities -> abilities.contains(FriendsForeverAbility.getInstance()))
.count() != 2
&& !CardUtil
.castStream(commanders.stream().map(MageObject::getAbilities), PartnerWithAbility.class)
.map(PartnerWithAbility::getPartnerName)
.allMatch(commanderNames::contains)) {
for (Card commander : commanders) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander with invalid Partner (" + commander.getName() + ')', true);
valid = false;
}
}
for (Card commander : commanders) {
if (bannedCommander.contains(commander.getName())) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander banned (" + commander.getName() + ')', true);
valid = false;
}
if ((!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) || !commander.isLegendary())
&& !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance())) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true);
valid = false;
}
if (commanders.size() == 2 && bannedPartner.contains(commander.getName())) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander Partner banned (" + commander.getName() + ')', true);
valid = false;
}
ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity());
}
// no needs in cards check on wrong commanders
if (!valid) {
return false;
}
valid = checkColorIdentity(deck, colorIdentity, commanders);
for (Card card : deck.getCards()) {
if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
valid = false;
}
}
}
for (Card card : deck.getSideboard()) {
if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
valid = false;
}
}
}
// Check for companion legality
if (companion != null) {
Set<Card> cards = new HashSet<>(deck.getCards());
cards.addAll(commanders);
for (Ability ability : companion.getAbilities()) {
if (ability instanceof CompanionAbility) {
CompanionAbility companionAbility = (CompanionAbility) ability;
if (!companionAbility.isLegal(cards, getDeckMinSize())) {
addError(DeckValidatorErrorType.PRIMARY, companion.getName(),
String.format("Commander companion illegal: %s", companionAbility.getLegalRule()), true);
valid = false;
}
break;
}
}
}
return valid;
}
@Override
public int getEdhPowerLevel(Deck deck) {
if (deck == null) {
return 0;
}
int edhPowerLevel = 0;
int commanderColors = 0;
int numberInfinitePieces = 0;
for (Card card : deck.getCards()) {
int thisMaxPower = 0;
// Examine rules to work out most egregious functions in edh
boolean anyNumberOfTarget = false;
boolean annihilator = false;
boolean buyback = false;
boolean cascade = false;
boolean cantBe = false;
boolean cantUntap = false;
boolean copy = false;
boolean costLessEach = false;
boolean createToken = false;
boolean dredge = false;
boolean exile = false;
boolean exileAll = false;
boolean counter = false;
boolean destroy = false;
boolean destroyAll = false;
boolean each = false;
boolean exalted = false;
boolean doesntUntap = false;
boolean drawCards = false;
boolean evoke = false;
boolean extraTurns = false;
boolean flash = false;
boolean flashback = false;
boolean flicker = false;
boolean gainControl = false;
boolean hexproof = false;
boolean infect = false;
boolean lifeTotalBecomes = false;
boolean mayCastForFree = false;
boolean menace = false;
boolean miracle = false;
boolean overload = false;
boolean persist = false;
boolean preventDamage = false;
boolean proliferate = false;
boolean protection = false;
boolean putUnderYourControl = false;
boolean retrace = false;
boolean returnFromYourGY = false;
boolean sacrifice = false;
boolean shroud = false;
boolean skip = false;
boolean sliver = false;
boolean storm = false;
boolean trample = false;
boolean tutor = false;
boolean tutorBasic = false;
boolean twiceAs = false;
boolean unblockable = false;
boolean undying = false;
boolean untapTarget = false;
boolean wheneverEnters = false;
boolean whenCounterThatSpell = false;
boolean xCost = false;
boolean youControlTarget = false;
boolean yourOpponentsControl = false;
boolean whenYouCast = false;
for (String str : card.getRules()) {
String s = str.toLowerCase(Locale.ENGLISH);
annihilator |= s.contains("annihilator");
anyNumberOfTarget |= s.contains("any number");
buyback |= s.contains("buyback");
cantUntap |= s.contains("can't untap") || s.contains("don't untap");
cantBe |= s.contains("can't be");
cascade |= s.contains("cascade");
copy |= s.contains("copy");
costLessEach |= s.contains("cost") || s.contains("less") || s.contains("each");
counter |= s.contains("counter") && s.contains("target");
createToken |= s.contains("create") && s.contains("token");
destroy |= s.contains("destroy");
destroyAll |= s.contains("destroy all");
doesntUntap |= s.contains("doesn't untap");
doesntUntap |= s.contains("don't untap");
drawCards |= s.contains("draw cards");
dredge |= s.contains("dredge");
each |= s.contains("each");
evoke |= s.contains("evoke");
exalted |= s.contains("exalted");
exile |= s.contains("exile");
exileAll |= s.contains("exile") && s.contains(" all ");
extraTurns |= s.contains("extra turn");
flicker |= s.contains("exile") && s.contains("return") && s.contains("to the battlefield under");
flash |= s.contains("flash");
flashback |= s.contains("flashback");
gainControl |= s.contains("gain control");
hexproof |= s.contains("hexproof");
infect |= s.contains("infect");
lifeTotalBecomes |= s.contains("life total becomes");
mayCastForFree |= s.contains("may cast") && s.contains("without paying");
menace |= s.contains("menace");
miracle |= s.contains("miracle");
overload |= s.contains("overload");
persist |= s.contains("persist");
preventDamage |= s.contains("prevent") && s.contains("all") && s.contains("damage");
proliferate |= s.contains("proliferate");
protection |= s.contains("protection");
putUnderYourControl |= s.contains("put") && s.contains("under your control");
retrace |= s.contains("retrace");
returnFromYourGY |= s.contains("return") && s.contains("from your graveyard");
sacrifice |= s.contains("sacrifice");
shroud |= s.contains("shroud");
skip |= s.contains("skip");
sliver |= s.contains("sliver");
storm |= s.contains("storm");
trample |= s.contains("trample");
tutor |= s.contains("search your library") && !s.contains("basic land");
tutorBasic |= s.contains("search your library") && s.contains("basic land");
twiceAs |= s.contains("twice that many") || s.contains("twice as much");
unblockable |= s.contains("can't be blocked");
undying |= s.contains("undying");
untapTarget |= s.contains("untap target");
whenCounterThatSpell |= s.contains("when") && s.contains("counter that spell");
wheneverEnters |= s.contains("when") && s.contains("another") && s.contains("enters");
youControlTarget |= s.contains("you control target");
yourOpponentsControl |= s.contains("your opponents control");
whenYouCast |= s.contains("when you cast") || s.contains("whenever you cast");
}
for (String s : card.getManaCostSymbols()) {
if (s.contains("X")) {
xCost = true;
}
}
for (Ability a : card.getAbilities()) {
for (String s : a.getManaCostSymbols()) {
if (s.contains("X")) {
xCost = true;
}
}
}
if (extraTurns) {
thisMaxPower = Math.max(thisMaxPower, 7);
}
if (buyback) {
thisMaxPower = Math.max(thisMaxPower, 6);
}
if (tutor) {
thisMaxPower = Math.max(thisMaxPower, 6);
}
if (annihilator) {
thisMaxPower = Math.max(thisMaxPower, 5);
}
if (cantUntap) {
thisMaxPower = Math.max(thisMaxPower, 5);
}
if (costLessEach) {
thisMaxPower = Math.max(thisMaxPower, 5);
}
if (infect) {
thisMaxPower = Math.max(thisMaxPower, 5);
}
if (overload) {
thisMaxPower = Math.max(thisMaxPower, 5);
}
if (twiceAs) {
thisMaxPower = Math.max(thisMaxPower, 5);
}
if (cascade) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (doesntUntap) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (each) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (exileAll) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (flash) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (flashback) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (flicker) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (gainControl) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (lifeTotalBecomes) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (mayCastForFree) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (preventDamage) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (proliferate) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (protection) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (putUnderYourControl) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (returnFromYourGY) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (sacrifice) {
thisMaxPower = Math.max(thisMaxPower, 2);
}
if (skip) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (storm) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (unblockable) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (whenCounterThatSpell) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (wheneverEnters) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (xCost) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (youControlTarget) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (yourOpponentsControl) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (whenYouCast) {
thisMaxPower = Math.max(thisMaxPower, 4);
}
if (anyNumberOfTarget) {
thisMaxPower = Math.max(thisMaxPower, 3);
}
if (createToken) {
thisMaxPower = Math.max(thisMaxPower, 3);
}
if (destroyAll) {
thisMaxPower = Math.max(thisMaxPower, 3);
}
if (dredge) {
thisMaxPower = Math.max(thisMaxPower, 3);
}
if (hexproof) {
thisMaxPower = Math.max(thisMaxPower, 3);
}
if (shroud) {
thisMaxPower = Math.max(thisMaxPower, 3);
}
if (undying) {
thisMaxPower = Math.max(thisMaxPower, 3);
}
if (persist) {
thisMaxPower = Math.max(thisMaxPower, 3);
}
if (cantBe) {
thisMaxPower = Math.max(thisMaxPower, 2);
}
if (evoke) {
thisMaxPower = Math.max(thisMaxPower, 2);
}
if (exile) {
thisMaxPower = Math.max(thisMaxPower, 2);
}
if (menace) {
thisMaxPower = Math.max(thisMaxPower, 2);
}
if (miracle) {
thisMaxPower = Math.max(thisMaxPower, 2);
}
if (sliver) {
thisMaxPower = Math.max(thisMaxPower, 2);
}
if (untapTarget) {
thisMaxPower = Math.max(thisMaxPower, 2);
}
if (copy) {
thisMaxPower = Math.max(thisMaxPower, 1);
}
if (counter) {
thisMaxPower = Math.max(thisMaxPower, 1);
}
if (destroy) {
thisMaxPower = Math.max(thisMaxPower, 1);
}
if (drawCards) {
thisMaxPower = Math.max(thisMaxPower, 1);
}
if (exalted) {
thisMaxPower = Math.max(thisMaxPower, 1);
}
if (retrace) {
thisMaxPower = Math.max(thisMaxPower, 1);
}
if (trample) {
thisMaxPower = Math.max(thisMaxPower, 1);
}
if (tutorBasic) {
thisMaxPower = Math.max(thisMaxPower, 1);
}
if (card.isPlaneswalker()) {
thisMaxPower = Math.max(thisMaxPower, 6);
}
String cn = card.getName().toLowerCase(Locale.ENGLISH);
if (cn.equals("ancient tomb")
|| cn.equals("anafenza, the foremost")
|| cn.equals("arcum dagsson")
|| cn.equals("armageddon")
|| cn.equals("aura shards")
|| cn.equals("azami, lady of scrolls")
|| cn.equals("azusa, lost but seeking")
|| cn.equals("back to basics")
|| cn.equals("bane of progress")
|| cn.equals("basalt monolith")
|| cn.equals("blightsteel collossus")
|| cn.equals("blood moon")
|| cn.equals("braids, cabal minion")
|| cn.equals("cabal coffers")
|| cn.equals("captain sisay")
|| cn.equals("celestial dawn")
|| cn.equals("child of alara")
|| cn.equals("coalition relic")
|| cn.equals("craterhoof behemoth")
|| cn.equals("deepglow skate")
|| cn.equals("derevi, empyrial tactician")
|| cn.equals("dig through time")
|| cn.equals("edric, spymaster of trest")
|| cn.equals("elesh norn, grand cenobite")
|| cn.equals("entomb")
|| cn.equals("force of will")
|| cn.equals("food chain")
|| cn.equals("gaddock teeg")
|| cn.equals("gaea's cradle")
|| cn.equals("grand arbiter augustin iv")
|| cn.equals("grim monolith")
|| cn.equals("hermit druid")
|| cn.equals("hokori, dust drinker")
|| cn.equals("humility")
|| cn.equals("imperial seal")
|| cn.equals("iona, shield of emeria")
|| cn.equals("jin-gitaxias, core augur")
|| cn.equals("karador, ghost chieftain")
|| cn.equals("karakas")
|| cn.equals("kataki, war's wage")
|| cn.equals("knowledge pool")
|| cn.equals("linvala, keeper of silence")
|| cn.equals("living death")
|| cn.equals("llawan, cephalid empress")
|| cn.equals("loyal retainers")
|| cn.equals("maelstrom wanderer")
|| cn.equals("malfegor")
|| cn.equals("master of cruelties")
|| cn.equals("mana crypt")
|| cn.equals("mana drain")
|| cn.equals("mana vault")
|| cn.equals("michiko konda, truth seeker")
|| cn.equals("nath of the gilt-leaf")
|| cn.equals("natural order")
|| cn.equals("necrotic ooze")
|| cn.equals("nicol bolas")
|| cn.equals("numot, the devastator")
|| cn.equals("oath of druids")
|| cn.equals("pattern of rebirth")
|| cn.equals("protean hulk")
|| cn.equals("purphoros, god of the forge")
|| cn.equals("ravages of war")
|| cn.equals("reclamation sage")
|| cn.equals("sen triplets")
|| cn.equals("serra's sanctum")
|| cn.equals("sheoldred, whispering one")
|| cn.equals("sol ring")
|| cn.equals("spore frog")
|| cn.equals("stasis")
|| cn.equals("strip mine")
|| cn.equals("the tabernacle at pendrell vale")
|| cn.equals("tinker")
|| cn.equals("treasure cruise")
|| cn.equals("urabrask the hidden")
|| cn.equals("vorinclex, voice of hunger")
|| cn.equals("winter orb")
|| cn.equals("zur the enchanter")) {
thisMaxPower = Math.max(thisMaxPower, 12);
}
// Parts of infinite combos
if (cn.equals("animate artifact") || cn.equals("animar, soul of element")
|| cn.equals("archaeomancer")
|| cn.equals("ashnod's altar") || cn.equals("azami, lady of scrolls")
|| cn.equals("aura flux")
|| cn.equals("basalt monolith") || cn.equals("brago, king eternal")
|| cn.equals("candelabra of tawnos") || cn.equals("cephalid aristocrat")
|| cn.equals("cephalid illusionist") || cn.equals("changeling berserker")
|| cn.equals("consecrated sphinx")
|| cn.equals("cyclonic rift")
|| cn.equals("the chain veil")
|| cn.equals("cinderhaze wretch") || cn.equals("cryptic gateway")
|| cn.equals("deadeye navigator") || cn.equals("derevi, empyrial tactician")
|| cn.equals("doubling season") || cn.equals("dross scorpion")
|| cn.equals("earthcraft") || cn.equals("erratic portal")
|| cn.equals("enter the infinite") || cn.equals("omniscience")
|| cn.equals("exquisite blood") || cn.equals("future sight")
|| cn.equals("genesis chamber")
|| cn.equals("ghave, guru of spores")
|| cn.equals("grave pact")
|| cn.equals("grave titan") || cn.equals("great whale")
|| cn.equals("grim monolith") || cn.equals("gush")
|| cn.equals("hellkite charger") || cn.equals("intruder alarm")
|| cn.equals("helm of obedience")
|| cn.equals("hermit druid")
|| cn.equals("humility")
|| cn.equals("iona, shield of emeria")
|| cn.equals("karn, silver golem") || cn.equals("kiki-jiki, mirror breaker")
|| cn.equals("krark-clan ironworks") || cn.equals("krenko, mob boss")
|| cn.equals("krosan restorer") || cn.equals("laboratory maniac")
|| cn.equals("leonin relic-warder") || cn.equals("leyline of the void")
|| cn.equals("memnarch")
|| cn.equals("meren of clan nel toth") || cn.equals("mikaeus, the unhallowed")
|| cn.equals("mindcrank") || cn.equals("mindslaver")
|| cn.equals("minion reflector") || cn.equals("mycosynth lattice")
|| cn.equals("myr turbine") || cn.equals("narset, enlightened master")
|| cn.equals("nekusar, the mindrazer") || cn.equals("norin the wary")
|| cn.equals("notion thief")
|| cn.equals("opalescence") || cn.equals("ornithopter")
|| cn.equals("paradox engine")
|| cn.equals("purphoros, god of the forge")
|| cn.equals("peregrine drake") || cn.equals("palinchron")
|| cn.equals("planar portal") || cn.equals("power artifact")
|| cn.equals("rings of brighthearth") || cn.equals("rite of replication")
|| cn.equals("sanguine bond") || cn.equals("sensei's divining top")
|| cn.equals("splinter twin") || cn.equals("stony silence")
|| cn.equals("sunder")
|| cn.equals("storm cauldron") || cn.equals("teferi's puzzle box")
|| cn.equals("tangle wire")
|| cn.equals("teferi, mage of zhalfir")
|| cn.equals("tezzeret the seeker") || cn.equals("time stretch")
|| cn.equals("time warp") || cn.equals("training grounds")
|| cn.equals("triskelavus") || cn.equals("triskelion")
|| cn.equals("turnabout") || cn.equals("umbral mantle")
|| cn.equals("uyo, silent prophet") || cn.equals("voltaic key")
|| cn.equals("workhorse") || cn.equals("worldgorger dragon")
|| cn.equals("worthy cause") || cn.equals("yawgmoth's will")
|| cn.equals("zealous conscripts")) {
thisMaxPower = Math.max(thisMaxPower, 15);
numberInfinitePieces++;
}
// Saltiest cards (edhrec)
if (cn.equals("acid rain")
|| cn.equals("agent of treachery")
|| cn.equals("apocalypse")
|| cn.equals("armageddon")
|| cn.equals("atraxa, praetors' voice")
|| cn.equals("aura shards")
|| cn.equals("avacyn, angel of hope")
|| cn.equals("back to basics")
|| cn.equals("bend or break")
|| cn.equals("blightsteel colossus")
|| cn.equals("blood moon")
|| cn.equals("boil")
|| cn.equals("boiling seas")
|| cn.equals("bribery")
|| cn.equals("burning sands")
|| cn.equals("card view")
|| cn.equals("cataclysm")
|| cn.equals("catastrophe")
|| cn.equals("chulane, teller of tales")
|| cn.equals("confusion in the ranks")
|| cn.equals("consecrated sphinx")
|| cn.equals("contamination")
|| cn.equals("craterhoof behemoth")
|| cn.equals("cyclonic rift")
|| cn.equals("death cloud")
|| cn.equals("decree of annihilation")
|| cn.equals("decree of silence")
|| cn.equals("demonic consultation")
|| cn.equals("derevi, empyrial tactician")
|| cn.equals("devastation")
|| cn.equals("divine intervention")
|| cn.equals("dockside extortionist")
|| cn.equals("doomsday")
|| cn.equals("doubling season")
|| cn.equals("drannith magistrate")
|| cn.equals("elesh norn, grand cenobite")
|| cn.equals("embargo")
|| cn.equals("emrakul, the promised end")
|| cn.equals("epicenter")
|| cn.equals("expropriate")
|| cn.equals("fall of the thran")
|| cn.equals("fierce guardianship")
|| cn.equals("food chain")
|| cn.equals("force of negation")
|| cn.equals("force of will")
|| cn.equals("gaddock teeg")
|| cn.equals("gaea's cradle")
|| cn.equals("gilded drake")
|| cn.equals("glenn, the voice of calm")
|| cn.equals("global ruin")
|| cn.equals("golos, tireless pilgrim")
|| cn.equals("grand arbiter augustin iv")
|| cn.equals("grip of chaos")
|| cn.equals("hokori, dust drinker")
|| cn.equals("humility")
|| cn.equals("impending disaster")
|| cn.equals("invoke prejudice")
|| cn.equals("iona, shield of emeria")
|| cn.equals("jin-gitaxias, core augur")
|| cn.equals("jokulhaups")
|| cn.equals("keldon firebombers")
|| cn.equals("kinnan, bonder prodigy")
|| cn.equals("kozilek, butcher of truth")
|| cn.equals("land equilibrium")
|| cn.equals("linvala, keeper of silence")
|| cn.equals("magister sphinx")
|| cn.equals("mana breach")
|| cn.equals("mana crypt")
|| cn.equals("mana drain")
|| cn.equals("mana vortex")
|| cn.equals("mindslaver")
|| cn.equals("narset, enlightened master")
|| cn.equals("narset, parter of veils")
|| cn.equals("negan, the cold-blooded")
|| cn.equals("nether void")
|| cn.equals("nexus of fate")
|| cn.equals("notion thief")
|| cn.equals("obliterate")
|| cn.equals("oko, thief of crowns")
|| cn.equals("oloro, ageless ascetic")
|| cn.equals("omniscience")
|| cn.equals("opposition agent")
|| cn.equals("oppression")
|| cn.equals("overwhelming splendor")
|| cn.equals("palinchron")
|| cn.equals("paradox engine")
|| cn.equals("possessed portal")
|| cn.equals("price of glory")
|| cn.equals("protean hulk")
|| cn.equals("ravages of war")
|| cn.equals("rhystic study")
|| cn.equals("rick, steadfast leader")
|| cn.equals("rising waters")
|| cn.equals("ruination")
|| cn.equals("scrambleverse")
|| cn.equals("seedborn muse")
|| cn.equals("sen triplets")
|| cn.equals("sire of insanity")
|| cn.equals("skithiryx, the blight dragon")
|| cn.equals("smokestack")
|| cn.equals("smothering tithe")
|| cn.equals("sorin markov")
|| cn.equals("stasis")
|| cn.equals("static orb")
|| cn.equals("storage matrix")
|| cn.equals("sunder")
|| cn.equals("survival of the fittest")
|| cn.equals("table view")
|| cn.equals("tainted aether")
|| cn.equals("tectonic break")
|| cn.equals("teferi's protection")
|| cn.equals("teferi, master of time")
|| cn.equals("teferi, time raveler")
|| cn.equals("temporal manipulation")
|| cn.equals("tergrid, god of fright")
|| cn.equals("text view")
|| cn.equals("thassa's oracle")
|| cn.equals("the tabernacle at pendrell vale")
|| cn.equals("thieves' auction")
|| cn.equals("thoughts of ruin")
|| cn.equals("thrasios, triton hero")
|| cn.equals("time stretch")
|| cn.equals("time warp")
|| cn.equals("tooth and nail")
|| cn.equals("torment of hailfire")
|| cn.equals("torpor orb")
|| cn.equals("triumph of the hordes")
|| cn.equals("ugin, the spirit dragon")
|| cn.equals("ulamog, the ceaseless hunger")
|| cn.equals("ulamog, the infinite gyre")
|| cn.equals("urza, lord high artificer")
|| cn.equals("void winnower")
|| cn.equals("vorinclex, voice of hunger")
|| cn.equals("wake of destruction")
|| cn.equals("warp world")
|| cn.equals("winter orb")
|| cn.equals("xanathar, guild kingpin")
|| cn.equals("zur the enchanter")) {
thisMaxPower = Math.max(thisMaxPower, 15);
}
edhPowerLevel += thisMaxPower;
}
ObjectColor color = null;
for (Card commander : deck.getSideboard()) {
int thisMaxPower = 0;
String cn = commander.getName().toLowerCase(Locale.ENGLISH);
if (color == null) {
color = commander.getColor(null);
} else {
color = color.union(commander.getColor(null));
}
FilterMana commanderColor = commander.getColorIdentity();
if (commanderColor.isWhite()) {
color.setWhite(true);
}
if (commanderColor.isBlue()) {
color.setBlue(true);
}
if (commanderColor.isBlack()) {
color.setBlack(true);
}
if (commanderColor.isRed()) {
color.setRed(true);
}
if (commanderColor.isGreen()) {
color.setGreen(true);
}
// Least fun commanders
if (cn.equals("animar, soul of element")
|| cn.equals("anafenza, the foremost")
|| cn.equals("arcum dagsson")
|| cn.equals("azami, lady of scrolls")
|| cn.equals("azusa, lost but seeking")
|| cn.equals("brago, king eternal")
|| cn.equals("braids, cabal minion")
|| cn.equals("captain sisay")
|| cn.equals("child of alara")
|| cn.equals("derevi, empyrial tactician")
|| cn.equals("edric, spymaster of trest")
|| cn.equals("elesh norn, grand cenobite")
|| cn.equals("gaddock teeg")
|| cn.equals("grand arbiter augustin iv")
|| cn.equals("hokori, dust drinker")
|| cn.equals("iona, shield of emeria")
|| cn.equals("jin-gitaxias, core augur")
|| cn.equals("kaalia of the vast")
|| cn.equals("karador, ghost chieftain")
|| cn.equals("leovold, emissary of trest")
|| cn.equals("linvala, keeper of silence")
|| cn.equals("llawan, cephalid empress")
|| cn.equals("maelstrom wanderer")
|| cn.equals("malfegor")
|| cn.equals("memnarch")
|| cn.equals("meren of clan nel toth")
|| cn.equals("michiko konda, truth seeker")
|| cn.equals("mikaeus the unhallowed")
|| cn.equals("narset, enlightened master")
|| cn.equals("nath of the gilt-leaf")
|| cn.equals("nekusar, the mindrazer")
|| cn.equals("norin the wary")
|| cn.equals("numot, the devastator")
|| cn.equals("prossh, skyraider of kher")
|| cn.equals("purphoros, god of the forge")
|| cn.equals("sen triplets")
|| cn.equals("sheoldred, whispering one")
|| cn.equals("teferi, mage of zhalfir")
|| cn.equals("urabrask the hidden")
|| cn.equals("vorinclex, voice of hunger")
|| cn.equals("zur the enchanter")) {
thisMaxPower = Math.max(thisMaxPower, 25);
}
// Saltiest commanders
if (cn.equals("atraxa, praetors' voice")
|| cn.equals("avacyn, angel of hope")
|| cn.equals("chulane, teller of tales")
|| cn.equals("derevi, empyrial tactician")
|| cn.equals("elesh norn, grand cenobite")
|| cn.equals("emrakul, the promised end")
|| cn.equals("gaddock teeg")
|| cn.equals("glenn, the voice of calm")
|| cn.equals("golos, tireless pilgrim")
|| cn.equals("grand arbiter augustin iv")
|| cn.equals("hokori, dust drinker")
|| cn.equals("iona, shield of emeria")
|| cn.equals("jin-gitaxias, core augur")
|| cn.equals("kinnan, bonder prodigy")
|| cn.equals("kozilek, butcher of truth")
|| cn.equals("linvala, keeper of silence")
|| cn.equals("narset, enlightened master")
|| cn.equals("negan, the cold-blooded")
|| cn.equals("oko, thief of crowns")
|| cn.equals("oloro, ageless ascetic")
|| cn.equals("rick, steadfast leader")
|| cn.equals("sen triplets")
|| cn.equals("skithiryx, the blight dragon")
|| cn.equals("teferi, master of time")
|| cn.equals("teferi, time raveler")
|| cn.equals("thrasios, triton hero")
|| cn.equals("ulamog, the ceaseless hunger")
|| cn.equals("ulamog, the infinite gyre")
|| cn.equals("urza, lord high artificer")
|| cn.equals("vorinclex, voice of hunger")
|| cn.equals("xanathar, guild kingpin")
|| cn.equals("zur the enchanter")) {
thisMaxPower = Math.max(thisMaxPower, 20);
}
edhPowerLevel += thisMaxPower;
}
edhPowerLevel += numberInfinitePieces * 18;
edhPowerLevel = Math.round(edhPowerLevel / 10);
if (edhPowerLevel >= 100) {
edhPowerLevel = 99;
}
if (color != null) {
edhPowerLevel += (color.isWhite() ? 10000000 : 0);
edhPowerLevel += (color.isBlue() ? 1000000 : 0);
edhPowerLevel += (color.isBlack() ? 100000 : 0);
edhPowerLevel += (color.isRed() ? 10000 : 0);
edhPowerLevel += (color.isGreen() ? 1000 : 0);
}
return edhPowerLevel;
}
}

View file

@ -112,32 +112,6 @@ public class AusHighlander extends Constructed {
valid = false;
}
banned.add("Advantageous Proclamation");
banned.add("Amulet of Quoz");
banned.add("Backup Plan");
banned.add("Brago's Favor");
banned.add("Bronze Tablet");
banned.add("Chaos Orb");
banned.add("Contract from Below");
banned.add("Darkpact");
banned.add("Demonic Attorney");
banned.add("Double Stroke");
banned.add("Falling Star");
banned.add("Immediate Action");
banned.add("Iterative Analysis");
banned.add("Jeweled Bird");
banned.add("Muzzio's Preparations");
banned.add("Power Play");
banned.add("Rebirth");
banned.add("Secret Summoning");
banned.add("Secrets of Paradise");
banned.add("Sentinel Dispatch");
banned.add("Shahrazad");
banned.add("Tempest Efreet");
banned.add("Timmerian Fiends");
banned.add("Unexpected Potential");
banned.add("Worldknit");
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());

View file

@ -57,10 +57,10 @@ public class Brawl extends Constructed {
Iterator<Card> iter = deck.getSideboard().iterator();
Card card1 = iter.next();
Card card2 = iter.next();
if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
if (card1.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) {
companion = card1;
brawler = card2;
} else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
} else if (card2.getAbilities().stream().anyMatch(CompanionAbility.class::isInstance)) {
companion = card2;
brawler = card1;
} else {
@ -156,7 +156,8 @@ public class Brawl extends Constructed {
if (ability instanceof CompanionAbility) {
CompanionAbility companionAbility = (CompanionAbility) ability;
if (!companionAbility.isLegal(cards, getDeckMinSize())) {
addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Brawl Companion Invalid", true);
addError(DeckValidatorErrorType.PRIMARY, companion.getName(),
String.format("Brawl companion illegal: %s", companionAbility.getLegalRule()), true);
valid = false;
}
break;

View file

@ -1,8 +1,6 @@
package mage.deck;
/**
*
* @author andreacosta
*/
public class CenturionCommander extends Commander {
@ -16,14 +14,12 @@ public class CenturionCommander extends Commander {
banned.add("Bazaar of Baghdad");
banned.add("Black Lotus");
banned.add("Channel");
banned.add("Chaos Orb");
banned.add("Chrome Mox");
banned.add("Demonic Tutor");
banned.add("Dig Through Time");
banned.add("Emrakul, the Aeons Torn");
banned.add("Emrakul, the Promised End");
banned.add("Entomb");
banned.add("Falling Star");
banned.add("Fastbond");
banned.add("Food Chain");
banned.add("Gaea's Cradle");
@ -53,7 +49,6 @@ public class CenturionCommander extends Commander {
banned.add("Parallax Tide");
banned.add("Protean Hulk");
banned.add("Sensei's Diving Top");
banned.add("Sharazad");
banned.add("Survival of the Fittest");
banned.add("Sol Ring");
banned.add("Strip Mine");
@ -83,5 +78,4 @@ public class CenturionCommander extends Commander {
bannedPartner.add("Kraum, Ludevic's Opus");
bannedPartner.add("Thrasios, Triton Hero ");
}
}

View file

@ -15,8 +15,6 @@ public class DuelCommander extends Commander {
banned.add("Cavern of Souls");
banned.add("Channel");
banned.add("Chrome Mox");
banned.add("Cleanse");
banned.add("Crusade");
banned.add("Deflecting Swat");
banned.add("Dig Through Time");
banned.add("Eidolon of the Great Revel");
@ -34,15 +32,12 @@ public class DuelCommander extends Commander {
banned.add("High Tide");
banned.add("Humility");
banned.add("Imperial Seal");
banned.add("Imprison");
banned.add("Invoke Prejudice");
banned.add("Jeweled Lotus");
banned.add("Jihad");
banned.add("Karakas");
banned.add("Library of Alexandria");
banned.add("Lion's Eye Diamond");
banned.add("Lutri, The Spellchaser");
banned.add("Loyal Retainers");
banned.add("Lutri, the Spellchaser");
banned.add("Maddening Hex");
banned.add("Mana Crypt");
banned.add("Mana Drain");
@ -60,13 +55,11 @@ public class DuelCommander extends Commander {
banned.add("Necrotic Ooze");
banned.add("Oath of Druids");
banned.add("Polymorph");
banned.add("Pradesh Gypsies");
banned.add("Price of Progress");
banned.add("Protean Hulk");
banned.add("Scapeshift");
banned.add("Sensei's Divining Top");
banned.add("Sol Ring");
banned.add("Stone-Throwing Devils");
banned.add("Strip Mine");
banned.add("Temporal Manipulation");
banned.add("Thassa's Oracle");

View file

@ -10,6 +10,7 @@ import java.util.HashMap;
import java.util.Map;
/**
* @author ddzn
* @brief European Highlander is a classic competitive singleton format formalized around 2003.
* It is also known as 'German Highlander'.
* In short: 20 pts starting life, 100 card singleton deck without sideboard.
@ -18,7 +19,6 @@ import java.util.Map;
* More info at http://highlandermagic.info
* Banned list here http://highlandermagic.info/banned-list
* Watch list here http://highlandermagic.info/watch-list
* @author ddzn
*/
public class EuropeanHighlander extends Constructed {
@ -34,91 +34,10 @@ public class EuropeanHighlander extends Constructed {
// Since then, the tournament organizer must decide if the cards are allowed
// The following ban list is decided by the council in cooperation with the community (last update: 15.11.2020)
// Silver-bordered cards are banned
// Conspiracy cards are banned
banned.add("Adriana's Valor");
banned.add("Advantageous Proclamation");
banned.add("Assemble the Rank and Vile");
banned.add("Backup Plan");
banned.add("Brago's Favor");
banned.add("Cleanse");
banned.add("Crusade");
banned.add("Double Stroke");
banned.add("Echoing Boon");
banned.add("Emissary's Ploy");
banned.add("Hired Heist");
banned.add("Hold the Perimeter");
banned.add("Hymn of the Wilds");
banned.add("Immediate Action");
banned.add("Imprison");
banned.add("Incendiary Dissent");
banned.add("Iterative Analysis");
banned.add("Invoke Prejudice");
banned.add("Jihad");
banned.add("Muzzio's Preparations");
banned.add("Natural Unity");
banned.add("Power Play");
banned.add("Pradesh Gypsies");
banned.add("Secrets of Paradise");
banned.add("Secret Summoning");
banned.add("Sentinel Dispatch");
banned.add("Sovereign's Realm");
banned.add("Stone-Throwing Devils");
banned.add("Summoner's Bond");
banned.add("Unexpected Potential");
banned.add("Weight Advantage");
banned.add("Worldknit");
// Dexterity cards are bannee
banned.add("Chaos Orb");
banned.add("Falling Star");
// Sub-game cards are banned
banned.add("Shahrazad");
// Ante cards are banned
banned.add("Amulet of Quoz");
banned.add("Bronze Tablet");
banned.add("Contract from Below");
banned.add("Darkpact");
banned.add("Demonic Attorney");
banned.add("Jeweled Bird");
banned.add("Rebirth");
banned.add("Tempest Efreet");
banned.add("Timmerian Fiends");
// Potentially offensive cards are banned
banned.add("Cleanse");
banned.add("Crusade");
banned.add("Imprison");
banned.add("Invoke Prejudice");
banned.add("Jihad");
banned.add("Pradesh Gypsies");
banned.add("Stone-Throwing Devils");
// Cards from the "Living Dead" TV show crossover are banned
banned.add("Daryl, Hunter of Walkers");
banned.add("Glenn, the Voice of Calm");
banned.add("Michonne, Ruthless Survivor");
banned.add("Negan, the Cold-Blooded");
banned.add("Rick, Steadfast Leader");
banned.add("Lucille");
// Power 9 except Time Twister
banned.add("Black Lotus");
banned.add("Ancestral Recall");
banned.add("Mox Emerald");
banned.add("Mox Jet");
banned.add("Mox Pearl");
banned.add("Mox Ruby");
banned.add("Mox Sapphire");
banned.add("Time Walk");
// Remaining cards
banned.add("Balance");
banned.add("Birthing Pod");
banned.add("Black Lotus");
banned.add("Flash");
banned.add("Gifts Ungiven");
banned.add("Library of Alexandria");
@ -126,6 +45,11 @@ public class EuropeanHighlander extends Constructed {
banned.add("Mana Vault");
banned.add("Mind Twist");
banned.add("Mystical Tutor");
banned.add("Mox Emerald");
banned.add("Mox Jet");
banned.add("Mox Pearl");
banned.add("Mox Ruby");
banned.add("Mox Sapphire");
banned.add("Natural Order");
banned.add("Sensei's Divining Top");
banned.add("Skullclamp");
@ -133,6 +57,7 @@ public class EuropeanHighlander extends Constructed {
banned.add("Strip Mine");
banned.add("Survival of the Fittest");
banned.add("Time Vault");
banned.add("Time Walk");
banned.add("Tinker");
banned.add("Tolarian Academy");
banned.add("Treasure Cruise");

View file

@ -10,11 +10,7 @@ import mage.cards.decks.DeckValidatorErrorType;
public class Freeform extends DeckValidator {
public Freeform() {
super("Constructed - Freeform");
}
public Freeform(String name) {
super(name);
this("Constructed - Freeform", null);
}
public Freeform(String name, String shortName) {

View file

@ -1,28 +1,17 @@
package mage.deck;
import mage.abilities.Ability;
import mage.abilities.keyword.CompanionAbility;
import mage.abilities.keyword.PartnerAbility;
import mage.abilities.keyword.PartnerWithAbility;
import mage.cards.Card;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckValidatorErrorType;
import mage.constants.CardType;
import mage.filter.FilterMana;
import mage.util.ManaUtil;
import java.util.*;
import java.util.Map;
/**
* @author spjspj
*/
public class FreeformCommander extends Constructed {
protected List<String> bannedCommander = new ArrayList<>();
private static final Map<String, Integer> pdAllowed = new HashMap<>();
public class FreeformCommander extends AbstractCommander {
public FreeformCommander() {
super("Freeform Commander");
@ -38,141 +27,17 @@ public class FreeformCommander extends Constructed {
super(name);
}
public FreeformCommander(String name, String shortName) {
super(name, shortName);
@Override
protected boolean checkBanned(Map<String, Integer> counts) {
return true;
}
@Override
public int getDeckMinSize() {
return 98;
}
@Override
public int getSideboardMinSize() {
return 1;
}
@Override
public boolean validate(Deck deck) {
boolean valid = true;
errorsList.clear();
FilterMana colorIdentity = new FilterMana();
Set<Card> commanders = new HashSet<>();
Card companion = null;
if (deck.getSideboard().size() == 1) {
commanders.add(deck.getSideboard().iterator().next());
} else if (deck.getSideboard().size() == 2) {
Iterator<Card> iter = deck.getSideboard().iterator();
Card card1 = iter.next();
Card card2 = iter.next();
if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
companion = card1;
commanders.add(card2);
} else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
companion = card2;
commanders.add(card1);
} else {
commanders.add(card1);
commanders.add(card2);
}
} else if (deck.getSideboard().size() == 3) {
Iterator<Card> iter = deck.getSideboard().iterator();
Card card1 = iter.next();
Card card2 = iter.next();
Card card3 = iter.next();
if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
companion = card1;
commanders.add(card2);
commanders.add(card3);
} else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
companion = card2;
commanders.add(card1);
commanders.add(card3);
} else if (card3.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
companion = card3;
commanders.add(card1);
commanders.add(card2);
} else {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion");
valid = false;
}
} else {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion");
valid = false;
}
if (companion != null && deck.getCards().size() + deck.getSideboard().size() != 101) {
addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 101 + " cards (companion doesn't count for deck size): has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
valid = false;
} else if (companion == null && deck.getCards().size() + deck.getSideboard().size() != 100) {
addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
valid = false;
}
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
valid = checkCounts(1, counts) && valid;
Set<String> commanderNames = new HashSet<>();
for (Card commander : commanders) {
commanderNames.add(commander.getName());
}
for (Card commander : commanders) {
protected boolean checkCommander(Card commander) {
if (!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) && !commander.isLegendary()) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "For Freeform Commander, the commander must be a creature or be legendary. Yours was: " + commander.getName(), true);
valid = false;
}
if (commanders.size() == 2) {
if (!commander.getAbilities().contains(PartnerAbility.getInstance())) {
boolean partnersWith = commander.getAbilities()
.stream()
.filter(PartnerWithAbility.class::isInstance)
.map(PartnerWithAbility.class::cast)
.map(PartnerWithAbility::getPartnerName)
.anyMatch(commanderNames::contains);
if (!partnersWith) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander without Partner (" + commander.getName() + ')', true);
valid = false;
}
}
}
ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity());
}
// no needs in cards check on wrong commanders
if (!valid) {
return false;
}
for (Card card : deck.getCards()) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false;
}
}
for (Card card : deck.getSideboard()) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false;
}
}
// Check for companion legality
if (companion != null) {
Set<Card> cards = new HashSet<>(deck.getCards());
cards.addAll(commanders);
for (Ability ability : companion.getAbilities()) {
if (ability instanceof CompanionAbility) {
CompanionAbility companionAbility = (CompanionAbility) ability;
if (!companionAbility.isLegal(cards, getDeckMinSize())) {
addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Commander Companion (deck invalid for companion)", true);
valid = false;
}
break;
}
}
}
return valid;
return true;
}
}

View file

@ -16,31 +16,18 @@ public class Legacy extends Constructed {
setCodes.add(set.getCode());
}
}
banned.add("Advantageous Proclamation");
banned.add("Arcum's Astrolabe");
banned.add("Amulet of Quoz");
banned.add("Ancestral Recall");
banned.add("Backup Plan");
banned.add("Arcum's Astrolabe");
banned.add("Balance");
banned.add("Bazaar of Baghdad");
banned.add("Black Lotus");
banned.add("Brago's Favor");
banned.add("Bronze Tablet");
banned.add("Channel");
banned.add("Chaos Orb");
banned.add("Cleanse");
banned.add("Contract from Below");
banned.add("Crusade");
banned.add("Darkpact");
banned.add("Deathrite Shaman");
banned.add("Demonic Attorney");
banned.add("Demonic Consultation");
banned.add("Demonic Tutor");
banned.add("Dig Through Time");
banned.add("Double Stroke");
banned.add("Dreadhorde Arcanist");
banned.add("Earthcraft");
banned.add("Falling Star");
banned.add("Fastbond");
banned.add("Flash");
banned.add("Frantic Search");
@ -48,13 +35,7 @@ public class Legacy extends Constructed {
banned.add("Goblin Recruiter");
banned.add("Gush");
banned.add("Hermit Druid");
banned.add("Immediate Action");
banned.add("Imperial Seal");
banned.add("Imprison");
banned.add("Invoke Prejudice");
banned.add("Iterative Analysis");
banned.add("Jeweled Bird");
banned.add("Jihad");
banned.add("Library of Alexandria");
banned.add("Lurrus of the Dream-Den");
banned.add("Mana Crypt");
@ -62,47 +43,34 @@ public class Legacy extends Constructed {
banned.add("Mana Vault");
banned.add("Memory Jar");
banned.add("Mental Misstep");
banned.add("Mind Twist");
banned.add("Mind's Desire");
banned.add("Mind Twist");
banned.add("Mishra's Workshop");
banned.add("Mox Emerald");
banned.add("Mox Jet");
banned.add("Mox Pearl");
banned.add("Mox Ruby");
banned.add("Mox Sapphire");
banned.add("Muzzio's Preparations");
banned.add("Mystical Tutor");
banned.add("Necropotence");
banned.add("Oath of Druids");
banned.add("Oko, Thief of Crowns");
banned.add("Power Play");
banned.add("Pradesh Gypsies");
banned.add("Ragavan, Nimble Pilferer");
banned.add("Rebirth");
banned.add("Secret Summoning");
banned.add("Secrets of Paradise");
banned.add("Sensei's Divining Top");
banned.add("Sentinel Dispatch");
banned.add("Shahrazad");
banned.add("Skullclamp");
banned.add("Sol Ring");
banned.add("Stone-Throwing Devils");
banned.add("Strip Mine");
banned.add("Survival of the Fittest");
banned.add("Tempest Efreet");
banned.add("Timetwister");
banned.add("Time Vault");
banned.add("Time Walk");
banned.add("Timetwister");
banned.add("Timmerian Fiends");
banned.add("Tinker");
banned.add("Tolarian Academy");
banned.add("Treasure Cruise");
banned.add("Underworld Breach");
banned.add("Unexpected Potential");
banned.add("Vampiric Tutor");
banned.add("Wheel of Fortune");
banned.add("Windfall");
banned.add("Worldknit");
banned.add("Wrenn and Six");
banned.add("Yawgmoth's Bargain");
banned.add("Yawgmoth's Will");

View file

@ -1,7 +1,6 @@
package mage.deck;
/**
*
* @author fireshoes
*/
public class MTGO1v1Commander extends Commander {

View file

@ -45,6 +45,7 @@ public class Modern extends Constructed {
banned.add("Hogaak, Arisen Necropolis");
banned.add("Hypergenesis");
banned.add("Krark-Clan Ironworks");
banned.add("Lurrus of the Dream-Den");
banned.add("Mental Misstep");
banned.add("Mox Opal");
banned.add("Mycosynth Lattice");

View file

@ -4,6 +4,7 @@ import mage.abilities.Ability;
import mage.abilities.keyword.PartnerAbility;
import mage.abilities.keyword.PartnerWithAbility;
import mage.cards.Card;
import mage.cards.decks.Constructed;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckValidatorErrorType;
import mage.constants.CardType;
@ -15,14 +16,13 @@ import java.util.*;
/**
* @author JayDi85
*/
public class Oathbreaker extends Vintage {
public class Oathbreaker extends Constructed {
protected List<String> bannedCommander = new ArrayList<>();
private static final Map<String, Integer> pdAllowed = new HashMap<>();
public Oathbreaker() {
super();
setName("Oathbreaker");
super("Oathbreaker");
// banned = vintage + oathbreaker's list: https://oathbreakermtg.org/banned-list/
banned.add("Ad Nauseam");
@ -31,21 +31,14 @@ public class Oathbreaker extends Vintage {
banned.add("Biorhythm");
banned.add("Black Lotus");
banned.add("Channel");
banned.add("Chaos Orb");
banned.add("Cleanse");
banned.add("Crusade");
banned.add("Dark Ritual");
banned.add("Doomsday");
banned.add("Emrakul, the Aeons Torn");
banned.add("Expropriate");
banned.add("Falling Star");
banned.add("Fastbond");
banned.add("Gifts Ungiven");
banned.add("Griselbrand");
banned.add("High Tide");
banned.add("Imprison");
banned.add("Invoke Prejudice");
banned.add("Jihad");
banned.add("Jeweled Lotus");
banned.add("Library of Alexandria");
banned.add("Limited Resources");
@ -61,12 +54,9 @@ public class Oathbreaker extends Vintage {
banned.add("Natural Order");
banned.add("Painter's Servant");
banned.add("Panoptic Mirror");
banned.add("Pradesh Gypsies");
banned.add("Primal Surge");
banned.add("Saheeli, the Gifted");
banned.add("Shahrazad");
banned.add("Sol Ring");
banned.add("Stone-Throwing Devils");
banned.add("Sundering Titan");
banned.add("Sylvan Primordial");
banned.add("Time Vault");

View file

@ -1,20 +1,16 @@
package mage.deck;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import mage.constants.SetType;
/**
* This class validates a deck for the Old School 93/94 format.
*
* <p>
* This was originally made to follow the deck construction rules found at the
* Old School Mtg blog found at:
* http://oldschool-mtg.blogspot.com/p/banrestriction.html
*
* <p>
* There is no mana burn in this version of old school.
*
* <p>
* If there are any questions or corrections, feel free to contact me.
*
* @author Marthinwurer (at gmail.com)
@ -33,31 +29,6 @@ public class OldSchool9394 extends Constructed {
setCodes.add(mage.sets.Legends.getInstance().getCode());
setCodes.add(mage.sets.TheDark.getInstance().getCode());
// ante cards and conspiracies banned, with specifically mentioned ones called out.
banned.add("Advantageous Proclamation");
banned.add("Amulet of Quoz");
banned.add("Backup Plan");
banned.add("Brago's Favor");
banned.add("Bronze Tablet"); ///
banned.add("Contract from Below"); ///
banned.add("Darkpact"); ///
banned.add("Demonic Attorney"); ///
banned.add("Double Stroke");
banned.add("Immediate Action");
banned.add("Iterative Analysis");
banned.add("Jeweled Bird"); ///
banned.add("Muzzio's Preparations");
banned.add("Power Play");
banned.add("Rebirth"); ///
banned.add("Secret Summoning");
banned.add("Secrets of Paradise");
banned.add("Sentinel Dispatch");
banned.add("Shahrazad");
banned.add("Tempest Efreet"); ///
banned.add("Timmerian Fiends");
banned.add("Unexpected Potential");
banned.add("Worldknit");
restricted.add("Ancestral Recall");
restricted.add("Balance");
restricted.add("Black Lotus");
@ -82,6 +53,5 @@ public class OldSchool9394 extends Constructed {
restricted.add("Time Walk");
restricted.add("Timetwister");
restricted.add("Wheel of Fortune");
}
}

View file

@ -29,30 +29,6 @@ public class OldSchool9394CFB extends Constructed {
setCodes.add(mage.sets.TheDark.getInstance().getCode());
setCodes.add(mage.sets.FallenEmpires.getInstance().getCode());
// ante cards and conspiracies banned, with specifically mentioned ones called out.
banned.add("Advantageous Proclamation");
banned.add("Amulet of Quoz");
banned.add("Backup Plan");
banned.add("Brago's Favor");
banned.add("Bronze Tablet"); ///
banned.add("Contract from Below"); ///
banned.add("Darkpact"); ///
banned.add("Demonic Attorney"); ///
banned.add("Double Stroke");
banned.add("Immediate Action");
banned.add("Iterative Analysis");
banned.add("Jeweled Bird"); ///
banned.add("Muzzio's Preparations");
banned.add("Power Play");
banned.add("Rebirth"); ///
banned.add("Secret Summoning");
banned.add("Secrets of Paradise");
banned.add("Sentinel Dispatch");
banned.add("Tempest Efreet"); ///
banned.add("Timmerian Fiends");
banned.add("Unexpected Potential");
banned.add("Worldknit");
//Let Media Inserts Arena and Sewers of Estark being only cards playable
banned.add("Acquire");
banned.add("Aeronaut Tinkerer");

View file

@ -29,31 +29,6 @@ public class OldSchool9394EC extends Constructed {
setCodes.add(mage.sets.TheDark.getInstance().getCode());
setCodes.add(mage.sets.FallenEmpires.getInstance().getCode());
// ante cards and conspiracies banned, with specifically mentioned ones called out.
banned.add("Advantageous Proclamation");
banned.add("Amulet of Quoz");
banned.add("Backup Plan");
banned.add("Brago's Favor");
banned.add("Bronze Tablet"); ///
banned.add("Contract from Below"); ///
banned.add("Darkpact"); ///
banned.add("Demonic Attorney"); ///
banned.add("Double Stroke");
banned.add("Immediate Action");
banned.add("Iterative Analysis");
banned.add("Jeweled Bird"); ///
banned.add("Muzzio's Preparations");
banned.add("Power Play");
banned.add("Rebirth"); ///
banned.add("Secret Summoning");
banned.add("Secrets of Paradise");
banned.add("Sentinel Dispatch");
banned.add("Shahrazad");
banned.add("Tempest Efreet"); ///
banned.add("Timmerian Fiends");
banned.add("Unexpected Potential");
banned.add("Worldknit");
//Let Media Inserts Arena and Sewers of Estark being only cards playable
banned.add("Acquire");
banned.add("Aeronaut Tinkerer");
@ -262,5 +237,4 @@ public class OldSchool9394EC extends Constructed {
restricted.add("Timetwister");
restricted.add("Wheel of Fortune");
}
}

View file

@ -1,19 +1,15 @@
package mage.deck;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import mage.constants.SetType;
/**
* This class validates a deck for the Old School 93/94 format, specifically the
* EudoGames Rules.
*
* <p>
* This was originally made to follow the deck construction rules found at the
* Old School Mtg blog found at:
* http://oldschool-mtg.blogspot.com/p/banrestriction.html
*
* <p>
* There is no mana burn in this version of old school.
*
* @author jmharmon
@ -35,31 +31,6 @@ public class OldSchool9394EG extends Constructed {
setCodes.add(mage.sets.FallenEmpires.getInstance().getCode());
setCodes.add(mage.sets.Chronicles.getInstance().getCode());
// ante cards and conspiracies banned, with specifically mentioned ones called out.
banned.add("Advantageous Proclamation");
banned.add("Amulet of Quoz");
banned.add("Backup Plan");
banned.add("Brago's Favor");
banned.add("Bronze Tablet"); ///
banned.add("Contract from Below"); ///
banned.add("Darkpact"); ///
banned.add("Demonic Attorney"); ///
banned.add("Double Stroke");
banned.add("Immediate Action");
banned.add("Iterative Analysis");
banned.add("Jeweled Bird"); ///
banned.add("Muzzio's Preparations");
banned.add("Power Play");
banned.add("Rebirth"); ///
banned.add("Secret Summoning");
banned.add("Secrets of Paradise");
banned.add("Sentinel Dispatch");
banned.add("Shahrazad");
banned.add("Tempest Efreet"); ///
banned.add("Timmerian Fiends");
banned.add("Unexpected Potential");
banned.add("Worldknit");
restricted.add("Ancestral Recall");
restricted.add("Balance");
restricted.add("Black Lotus");
@ -88,5 +59,4 @@ public class OldSchool9394EG extends Constructed {
restricted.add("Timetwister");
restricted.add("Wheel of Fortune");
}
}

View file

@ -1,19 +1,16 @@
package mage.deck;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import mage.constants.SetType;
/**
* This class validates a deck for the Old School 93/94 format, specifically for
* the Italian Rules.
*
* <p>
* This was originally made to follow the deck construction rules found at the
* Old School Mtg blog found at:
* http://oldschool-mtg.blogspot.com/p/banrestriction.html
*
* <p>
* There is no mana burn in this version of old school
*
* @author jmharmon
@ -33,31 +30,6 @@ public class OldSchool9394Italian extends Constructed{
setCodes.add(mage.sets.TheDark.getInstance().getCode());
setCodes.add(mage.sets.RevisedEdition.getInstance().getCode());
// ante cards and conspiracies banned, with specifically mentioned ones called out.
banned.add("Advantageous Proclamation");
banned.add("Amulet of Quoz");
banned.add("Backup Plan");
banned.add("Brago's Favor");
banned.add("Bronze Tablet"); ///
banned.add("Contract from Below"); ///
banned.add("Darkpact"); ///
banned.add("Demonic Attorney"); ///
banned.add("Double Stroke");
banned.add("Immediate Action");
banned.add("Iterative Analysis");
banned.add("Jeweled Bird"); ///
banned.add("Muzzio's Preparations");
banned.add("Power Play");
banned.add("Rebirth"); ///
banned.add("Secret Summoning");
banned.add("Secrets of Paradise");
banned.add("Sentinel Dispatch");
banned.add("Shahrazad");
banned.add("Tempest Efreet"); ///
banned.add("Timmerian Fiends");
banned.add("Unexpected Potential");
banned.add("Worldknit");
restricted.add("Ancestral Recall");
restricted.add("Balance");
restricted.add("Black Lotus");
@ -82,6 +54,5 @@ public class OldSchool9394Italian extends Constructed{
restricted.add("Time Walk");
restricted.add("Timetwister");
restricted.add("Wheel of Fortune");
}
}

View file

@ -29,10 +29,11 @@ public class Pauper extends Constructed {
banned.add("Cloudpost");
banned.add("Cranial Plating");
banned.add("Daze");
banned.add("Disciple of the Vault");
banned.add("Empty the Warrens");
banned.add("Expedition Map");
banned.add("Fall from Favor");
banned.add("Frantic Search");
banned.add("Galvanic Relay");
banned.add("Gitaxian Probe");
banned.add("Grapeshot");
banned.add("Gush");

View file

@ -1,33 +1,22 @@
package mage.deck;
import mage.abilities.Ability;
import mage.abilities.common.CanBeYourCommanderAbility;
import mage.abilities.keyword.CompanionAbility;
import mage.abilities.keyword.PartnerAbility;
import mage.abilities.keyword.PartnerWithAbility;
import mage.cards.Card;
import mage.cards.ExpansionSet;
import mage.cards.Sets;
import mage.cards.decks.Constructed;
import mage.cards.decks.Deck;
import mage.cards.decks.DeckValidatorErrorType;
import mage.cards.decks.PennyDreadfulLegalityUtil;
import mage.constants.CardType;
import mage.filter.FilterMana;
import mage.util.ManaUtil;
import java.util.*;
import java.util.HashMap;
import java.util.Map;
/**
* @author spjspj
*/
public class PennyDreadfulCommander extends Constructed {
public class PennyDreadfulCommander extends AbstractCommander {
protected List<String> bannedCommander = new ArrayList<>();
private static final Map<String, Integer> pdAllowed = new HashMap<>();
public PennyDreadfulCommander() {
super("Penny Dreadful Commander", "Penny");
super("Penny Dreadful Commander");
for (ExpansionSet set : Sets.getInstance().values()) {
if (set.getSetType().isEternalLegal()) {
setCodes.add(set.getCode());
@ -36,168 +25,17 @@ public class PennyDreadfulCommander extends Constructed {
}
@Override
public int getDeckMinSize() {
return 98;
}
@Override
public int getSideboardMinSize() {
return 1;
}
@Override
public boolean validate(Deck deck) {
boolean valid = true;
errorsList.clear();
FilterMana colorIdentity = new FilterMana();
Set<Card> commanders = new HashSet<>();
Card companion = null;
if (deck.getSideboard().size() == 1) {
commanders.add(deck.getSideboard().iterator().next());
} else if (deck.getSideboard().size() == 2) {
Iterator<Card> iter = deck.getSideboard().iterator();
Card card1 = iter.next();
Card card2 = iter.next();
if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
companion = card1;
commanders.add(card2);
} else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
companion = card2;
commanders.add(card1);
} else {
commanders.add(card1);
commanders.add(card2);
}
} else if (deck.getSideboard().size() == 3) {
Iterator<Card> iter = deck.getSideboard().iterator();
Card card1 = iter.next();
Card card2 = iter.next();
Card card3 = iter.next();
if (card1.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
companion = card1;
commanders.add(card2);
commanders.add(card3);
} else if (card2.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
companion = card2;
commanders.add(card1);
commanders.add(card3);
} else if (card3.getAbilities().stream().anyMatch(ability -> ability instanceof CompanionAbility)) {
companion = card3;
commanders.add(card1);
commanders.add(card2);
} else {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion");
valid = false;
}
} else {
addError(DeckValidatorErrorType.PRIMARY, "Commander", "Sideboard must contain only the commander(s) and up to 1 companion");
valid = false;
}
if (companion != null && deck.getCards().size() + deck.getSideboard().size() != 101) {
addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 101 + " cards (companion doesn't count for deck size): has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
valid = false;
} else if (companion == null && deck.getCards().size() + deck.getSideboard().size() != 100) {
addError(DeckValidatorErrorType.DECK_SIZE, "Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards");
valid = false;
}
Map<String, Integer> counts = new HashMap<>();
countCards(counts, deck.getCards());
countCards(counts, deck.getSideboard());
valid = checkCounts(1, counts) && valid;
protected boolean checkBanned(Map<String, Integer> counts) {
if (pdAllowed.isEmpty()) {
pdAllowed.putAll(PennyDreadfulLegalityUtil.getLegalCardList());
}
boolean valid = true;
for (String wantedCard : counts.keySet()) {
if (!(pdAllowed.containsKey(wantedCard))) {
addError(DeckValidatorErrorType.BANNED, wantedCard, "Banned", true);
valid = false;
}
}
Set<String> commanderNames = new HashSet<>();
for (Card commander : commanders) {
commanderNames.add(commander.getName());
}
for (Card commander : commanders) {
if (bannedCommander.contains(commander.getName())) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander banned (" + commander.getName() + ')', true);
valid = false;
}
if ((!commander.hasCardTypeForDeckbuilding(CardType.CREATURE) || !commander.isLegendary())
&& !commander.getAbilities().contains(CanBeYourCommanderAbility.getInstance())) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander invalid (" + commander.getName() + ')', true);
valid = false;
}
if (commanders.size() == 2) {
if (!commander.getAbilities().contains(PartnerAbility.getInstance())) {
boolean partnersWith = commander.getAbilities()
.stream()
.filter(PartnerWithAbility.class::isInstance)
.map(PartnerWithAbility.class::cast)
.map(PartnerWithAbility::getPartnerName)
.anyMatch(commanderNames::contains);
if (!partnersWith) {
addError(DeckValidatorErrorType.PRIMARY, commander.getName(), "Commander without Partner (" + commander.getName() + ')', true);
valid = false;
}
}
}
ManaUtil.collectColorIdentity(colorIdentity, commander.getColorIdentity());
}
// no needs in cards check on wrong commanders
if (!valid) {
return false;
}
for (Card card : deck.getCards()) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false;
}
}
for (Card card : deck.getSideboard()) {
if (!ManaUtil.isColorIdentityCompatible(colorIdentity, card.getColorIdentity())) {
addError(DeckValidatorErrorType.OTHER, card.getName(), "Invalid color (" + colorIdentity.toString() + ')', true);
valid = false;
}
}
for (Card card : deck.getCards()) {
if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
valid = false;
}
}
}
for (Card card : deck.getSideboard()) {
if (!isSetAllowed(card.getExpansionSetCode())) {
if (!legalSets(card)) {
addError(DeckValidatorErrorType.WRONG_SET, card.getName(), "Not allowed Set: " + card.getExpansionSetCode(), true);
valid = false;
}
}
}
// Check for companion legality
if (companion != null) {
Set<Card> cards = new HashSet<>(deck.getCards());
cards.addAll(commanders);
for (Ability ability : companion.getAbilities()) {
if (ability instanceof CompanionAbility) {
CompanionAbility companionAbility = (CompanionAbility) ability;
if (!companionAbility.isLegal(cards, getDeckMinSize())) {
addError(DeckValidatorErrorType.PRIMARY, companion.getName(), "Commander Companion (deck invalid for companion)", true);
valid = false;
}
break;
}
}
}
return valid;
}
}

View file

@ -34,6 +34,7 @@ public class Pioneer extends Constructed {
banned.add("Inverter of Truth");
banned.add("Kethis, the Hidden Hand");
banned.add("Leyline of Abundance");
banned.add("Lurrus of the Dream-Den");
banned.add("Nexus of Fate");
banned.add("Oko, Thief of Crowns");
banned.add("Once Upon a Time");

View file

@ -3,7 +3,6 @@ package mage.deck;
import mage.cards.decks.Constructed;
/**
*
* @author jmharmon
*/
@ -44,10 +43,8 @@ public class Premodern extends Constructed {
setCodes.add(mage.sets.Scourge.getInstance().getCode());
// Ban List
banned.add("Amulet of Quoz");
banned.add("Balance");
banned.add("Brainstorm");
banned.add("Bronze Tablet");
banned.add("Channel");
banned.add("Demonic Consultation");
banned.add("Earthcraft");
@ -56,25 +53,21 @@ public class Premodern extends Constructed {
banned.add("Force of Will");
banned.add("Goblin Recruiter");
banned.add("Grim Monolith");
banned.add("Jeweled Bird");
banned.add("Mana Vault");
banned.add("Memory Jar");
banned.add("Mind Twist");
banned.add("Mind's Desire");
banned.add("Mind Twist");
banned.add("Mystical Tutor");
banned.add("Necropotence");
banned.add("Rebirth");
banned.add("Show and Tell");
banned.add("Strip Mine");
banned.add("Tempest Efreet");
banned.add("Tendrils of Agony");
banned.add("Time Spiral");
banned.add("Timmerian Fiends");
banned.add("Tolarian Academy");
banned.add("Vampiric Tutor");
banned.add("Windfall");
banned.add("Worldgorger Dragon");
banned.add("Yawgmoth's Will");
banned.add("Yawgmoth's Bargain");
banned.add("Yawgmoth's Will");
}
}

View file

@ -59,7 +59,6 @@ public class TinyLeaders extends Constructed {
banned.add("Mox Sapphire");
banned.add("Najeela, the Blade-Blossom");
banned.add("Necropotence");
banned.add("Shahrazad");
banned.add("Sisay, Weatherlight Captain");
banned.add("Skullclamp");
banned.add("Sol Ring");

View file

@ -16,39 +16,6 @@ public class Vintage extends Constructed {
setCodes.add(set.getCode());
}
}
banned.add("Advantageous Proclamation");
banned.add("Amulet of Quoz");
banned.add("Backup Plan");
banned.add("Brago's Favor");
banned.add("Bronze Tablet");
banned.add("Chaos Orb");
banned.add("Cleanse");
banned.add("Crusade");
banned.add("Contract from Below");
banned.add("Darkpact");
banned.add("Demonic Attorney");
banned.add("Double Stroke");
banned.add("Falling Star");
banned.add("Immediate Action");
banned.add("Imprison");
banned.add("Invoke Prejudice");
banned.add("Iterative Analysis");
banned.add("Jeweled Bird");
banned.add("Jihad");
banned.add("Muzzio's Preparations");
banned.add("Power Play");
banned.add("Pradesh Gypsies");
banned.add("Rebirth");
banned.add("Secret Summoning");
banned.add("Secrets of Paradise");
banned.add("Sentinel Dispatch");
banned.add("Shahrazad");
banned.add("Stone-Throwing Devils");
banned.add("Tempest Efreet");
banned.add("Timmerian Fiends");
banned.add("Unexpected Potential");
banned.add("Worldknit");
restricted.add("Ancestral Recall");
restricted.add("Balance");
restricted.add("Black Lotus");

View file

@ -13,7 +13,7 @@ import java.util.Map;
public class Limited extends DeckValidator {
public Limited() {
super("Limited");
super("Limited", null);
}
@Override

View file

@ -396,7 +396,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ {
&& stackObject.getControllerId().equals(playerId)) {
Target target = effect.getTarget();
if (!target.doneChosing()) {
for (UUID targetId : target.possibleTargets(stackObject.getSourceId(), stackObject.getControllerId(), game)) {
for (UUID targetId : target.possibleTargets(stackObject.getControllerId(), stackObject.getStackAbility(), game)) {
Game sim = game.copy();
StackAbility newAbility = (StackAbility) stackObject.copy();
SearchEffect newEffect = getSearchEffect(newAbility);

View file

@ -124,8 +124,7 @@ public class SimulatedPlayer2 extends ComputerPlayer {
// calculate the mana that can be used for the x part
int numAvailable = getAvailableManaProducers(game).size() - ability.getManaCosts().manaValue();
Card card = game.getCard(ability.getSourceId());
if (card != null && numAvailable > 0) {
if (numAvailable > 0) {
// check if variable mana costs is included and get the multiplier
VariableManaCost variableManaCost = null;
for (ManaCost cost : ability.getManaCostsToPay()) {
@ -159,7 +158,7 @@ public class SimulatedPlayer2 extends ComputerPlayer {
if (varCost != null) {
varCost.setPaid();
}
card.adjustTargets(newAbility, game);
newAbility.adjustTargets(game);
// add the different possible target option for the specific X value
if (!newAbility.getTargets().getUnchosen().isEmpty()) {
addTargetOptions(options, newAbility, targetNum, game);

View file

@ -122,12 +122,12 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
@Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) {
return choose(outcome, target, sourceId, game, null);
public boolean choose(Outcome outcome, Target target, Ability source, Game game) {
return choose(outcome, target, source, game, null);
}
@Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map<String, Serializable> options) {
public boolean choose(Outcome outcome, Target target, Ability source, Game game, Map<String, Serializable> options) {
if (log.isDebugEnabled()) {
log.debug("choose: " + outcome.toString() + ':' + target.toString());
@ -143,9 +143,10 @@ public class ComputerPlayer extends PlayerImpl implements Player {
&& target.getAbilityController() != null) {
abilityControllerId = target.getAbilityController();
}
UUID sourceId = source != null ? source.getSourceId() : null;
boolean required = target.isRequired(sourceId, game);
Set<UUID> possibleTargets = target.possibleTargets(sourceId, abilityControllerId, game);
Set<UUID> possibleTargets = target.possibleTargets(abilityControllerId, source, game);
if (possibleTargets.isEmpty() || target.getTargets().size() >= target.getNumberOfTargets()) {
required = false;
}
@ -160,7 +161,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
if (target.getOriginalTarget() instanceof TargetPlayer) {
return setTargetPlayer(outcome, target, null, sourceId, abilityControllerId, randomOpponentId, game, required);
return setTargetPlayer(outcome, target, null, abilityControllerId, randomOpponentId, game, required);
}
if (target.getOriginalTarget() instanceof TargetDiscard) {
@ -191,12 +192,12 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetControlledPermanent) {
List<Permanent> targets;
TargetControlledPermanent origTarget = (TargetControlledPermanent) target.getOriginalTarget();
targets = threats(abilityControllerId, sourceId, origTarget.getFilter(), game, target.getTargets());
targets = threats(abilityControllerId, source, origTarget.getFilter(), game, target.getTargets());
if (!outcome.isGood()) {
Collections.reverse(targets);
}
for (Permanent permanent : targets) {
if (origTarget.canTarget(abilityControllerId, permanent.getId(), sourceId, game, false) && !target.getTargets().contains(permanent.getId())) {
if (origTarget.canTarget(abilityControllerId, permanent.getId(), source, game, false) && !target.getTargets().contains(permanent.getId())) {
target.add(permanent.getId(), game);
return true;
}
@ -217,18 +218,18 @@ public class ComputerPlayer extends PlayerImpl implements Player {
List<Permanent> targets;
if (outcome.isCanTargetAll()) {
targets = threats(null, sourceId, filter, game, target.getTargets());
targets = threats(null, source, filter, game, target.getTargets());
} else {
if (outcome.isGood()) {
targets = threats(abilityControllerId, sourceId, filter, game, target.getTargets());
targets = threats(abilityControllerId, source, filter, game, target.getTargets());
} else {
targets = threats(randomOpponentId, sourceId, filter, game, target.getTargets());
targets = threats(randomOpponentId, source, filter, game, target.getTargets());
}
if (targets.isEmpty() && target.isRequired()) {
if (!outcome.isGood()) {
targets = threats(abilityControllerId, sourceId, filter, game, target.getTargets());
targets = threats(abilityControllerId, source, filter, game, target.getTargets());
} else {
targets = threats(randomOpponentId, sourceId, filter, game, target.getTargets());
targets = threats(randomOpponentId, source, filter, game, target.getTargets());
}
}
}
@ -257,7 +258,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetCardInHand
|| (target.getZone() == Zone.HAND && (target.getOriginalTarget() instanceof TargetCard))) {
List<Card> cards = new ArrayList<>();
for (UUID cardId : target.possibleTargets(sourceId, this.getId(), game)) {
for (UUID cardId : target.possibleTargets(this.getId(), source, game)) {
Card card = game.getCard(cardId);
if (card != null) {
cards.add(card);
@ -278,9 +279,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
List<Permanent> targets;
TargetAnyTarget origTarget = (TargetAnyTarget) target.getOriginalTarget();
if (outcome.isGood()) {
targets = threats(abilityControllerId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
targets = threats(abilityControllerId, source, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
} else {
targets = threats(randomOpponentId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
targets = threats(randomOpponentId, source, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
}
for (Permanent permanent : targets) {
List<UUID> alreadyTargetted = target.getTargets();
@ -309,9 +310,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
List<Permanent> targets;
TargetCreatureOrPlayer origTarget = (TargetCreatureOrPlayer) target.getOriginalTarget();
if (outcome.isGood()) {
targets = threats(abilityControllerId, sourceId, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
targets = threats(abilityControllerId, source, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
} else {
targets = threats(randomOpponentId, sourceId, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
targets = threats(randomOpponentId, source, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
}
for (Permanent permanent : targets) {
List<UUID> alreadyTargeted = target.getTargets();
@ -339,8 +340,8 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetPermanentOrPlayer) {
List<Permanent> targets;
TargetPermanentOrPlayer origTarget = (TargetPermanentOrPlayer) target.getOriginalTarget();
List<Permanent> ownedTargets = threats(abilityControllerId, sourceId, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
List<Permanent> opponentTargets = threats(randomOpponentId, sourceId, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
List<Permanent> ownedTargets = threats(abilityControllerId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
List<Permanent> opponentTargets = threats(randomOpponentId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
if (outcome.isGood()) {
targets = ownedTargets;
} else {
@ -463,7 +464,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetSource) {
Set<UUID> targets;
targets = target.possibleTargets(sourceId, abilityControllerId, game);
targets = target.possibleTargets(abilityControllerId, source, game);
for (UUID targetId : targets) {
MageObject targetObject = game.getObject(targetId);
if (targetObject != null) {
@ -517,7 +518,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
boolean required = target.isRequired(sourceId, game);
Set<UUID> possibleTargets = target.possibleTargets(sourceId, abilityControllerId, game);
Set<UUID> possibleTargets = target.possibleTargets(abilityControllerId, source, game);
if (possibleTargets.isEmpty() || target.getTargets().size() >= target.getNumberOfTargets()) {
required = false;
}
@ -537,11 +538,11 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
if (target.getOriginalTarget() instanceof TargetPlayer) {
return setTargetPlayer(outcome, target, source, sourceId, abilityControllerId, randomOpponentId, game, required);
return setTargetPlayer(outcome, target, source, abilityControllerId, randomOpponentId, game, required);
}
// Angel of Serenity trigger
if (target.getOriginalTarget() instanceof TargetCardInGraveyardOrBattlefield) {
if (target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack) {
Cards cards = new CardsImpl(possibleTargets);
List<Card> possibleCards = new ArrayList<>(cards.getCards(game));
for (Card card : possibleCards) {
@ -642,7 +643,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetControlledPermanent) {
TargetControlledPermanent origTarget = (TargetControlledPermanent) target.getOriginalTarget();
List<Permanent> targets;
targets = threats(abilityControllerId, sourceId, origTarget.getFilter(), game, target.getTargets());
targets = threats(abilityControllerId, source, origTarget.getFilter(), game, target.getTargets());
if (!outcome.isGood()) {
Collections.reverse(targets);
}
@ -671,7 +672,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
+ target.getOriginalTarget().getClass().getCanonicalName());
}
findBestPermanentTargets(outcome, abilityControllerId, sourceId, filter,
findBestPermanentTargets(outcome, abilityControllerId, sourceId, source, filter,
game, target, goodList, badList, allList);
// use good list all the time and add maximum targets
@ -700,9 +701,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
List<Permanent> targets;
TargetCreatureOrPlayer origTarget = ((TargetCreatureOrPlayer) target.getOriginalTarget());
if (outcome.isGood()) {
targets = threats(abilityControllerId, sourceId, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
targets = threats(abilityControllerId, source, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
} else {
targets = threats(randomOpponentId, sourceId, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
targets = threats(randomOpponentId, source, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets());
}
if (targets.isEmpty()) {
@ -742,9 +743,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
List<Permanent> targets;
TargetAnyTarget origTarget = ((TargetAnyTarget) target.getOriginalTarget());
if (outcome.isGood()) {
targets = threats(abilityControllerId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
targets = threats(abilityControllerId, source, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
} else {
targets = threats(randomOpponentId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
targets = threats(randomOpponentId, source, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
}
if (targets.isEmpty()) {
@ -785,9 +786,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
List<Permanent> targets;
TargetPermanentOrPlayer origTarget = ((TargetPermanentOrPlayer) target.getOriginalTarget());
if (outcome.isGood()) {
targets = threats(abilityControllerId, source.getSourceId(), ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
targets = threats(abilityControllerId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
} else {
targets = threats(randomOpponentId, source.getSourceId(), ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
targets = threats(randomOpponentId, source, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets());
}
if (targets.isEmpty()) {
@ -823,9 +824,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
// normal cycle (good for you, bad for opponents)
// possible good/bad permanents
if (outcome.isGood()) {
targets = threats(abilityControllerId, source.getSourceId(), ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets());
targets = threats(abilityControllerId, source, ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets());
} else {
targets = threats(randomOpponentId, source.getSourceId(), ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets());
targets = threats(randomOpponentId, source, ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets());
}
// possible good/bad players
@ -930,12 +931,12 @@ public class ComputerPlayer extends PlayerImpl implements Player {
List<Permanent> targets;
boolean outcomeTargets = true;
if (outcome.isGood()) {
targets = threats(abilityControllerId, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets());
targets = threats(abilityControllerId, source, origTarget.getPermanentFilter(), game, target.getTargets());
} else {
targets = threats(randomOpponentId, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets());
targets = threats(randomOpponentId, source, origTarget.getPermanentFilter(), game, target.getTargets());
}
if (targets.isEmpty() && required) {
targets = threats(null, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets());
targets = threats(null, source, origTarget.getPermanentFilter(), game, target.getTargets());
Collections.reverse(targets);
outcomeTargets = false;
}
@ -976,24 +977,8 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
if (target.getOriginalTarget() instanceof TargetDefender) {
// TODO: Improve, now planeswalker is always chosen if it exits
List<Permanent> targets;
targets = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_PLANESWALKER, randomOpponentId, game);
if (targets != null && !targets.isEmpty()) {
for (Permanent planeswalker : targets) {
if (target.canTarget(abilityControllerId, planeswalker.getId(), source, game)) {
target.addTarget(planeswalker.getId(), source, game);
}
if (target.isChosen()) {
return true;
}
}
}
if (!target.isChosen()) {
if (target.canTarget(abilityControllerId, randomOpponentId, source, game)) {
target.addTarget(randomOpponentId, source, game);
}
}
UUID randomDefender = RandomUtil.randomFromCollection(possibleTargets);
target.addTarget(randomDefender, source, game);
return target.isChosen();
}
@ -1024,7 +1009,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
List<Card> cards = new ArrayList<>();
for (UUID uuid : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) {
for (UUID uuid : target.possibleTargets(source.getControllerId(), source, game)) {
Card card = game.getCard(uuid);
if (card != null && game.getState().getZone(card.getId()) == Zone.EXILED) {
cards.add(card);
@ -1042,7 +1027,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
if (target.getOriginalTarget() instanceof TargetActivatedAbility) {
List<StackObject> stackObjects = new ArrayList<>();
for (UUID uuid : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) {
for (UUID uuid : target.possibleTargets(source.getControllerId(), source, game)) {
StackObject stackObject = game.getStack().getStackObject(uuid);
if (stackObject != null) {
stackObjects.add(stackObject);
@ -1058,7 +1043,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return target.isChosen();
}
if (target.getOriginalTarget() instanceof TargetCardInGraveyardOrBattlefield) {
if (target.getOriginalTarget() instanceof TargetCardInGraveyardBattlefieldOrStack) {
List<Card> cards = new ArrayList<>();
for (Player player : game.getPlayers().values()) {
cards.addAll(player.getGraveyard().getCards(game));
@ -1145,7 +1130,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
// permanents kill
for (UUID opponentId : opponents) {
targets = threats(opponentId, sourceId, StaticFilters.FILTER_PERMANENT_CREATURE_OR_PLANESWALKER_A, game, target.getTargets());
targets = threats(opponentId, source, StaticFilters.FILTER_PERMANENT_CREATURE_OR_PLANESWALKER_A, game, target.getTargets());
// planeswalker kill
for (Permanent permanent : targets) {
@ -1172,9 +1157,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
// own permanents will be checked multiple times... that's ok
for (UUID opponentId : opponents) {
if (outcome.isGood()) {
targets = threats(getId(), sourceId, StaticFilters.FILTER_PERMANENT, game, target.getTargets());
targets = threats(getId(), source, StaticFilters.FILTER_PERMANENT, game, target.getTargets());
} else {
targets = threats(opponentId, sourceId, StaticFilters.FILTER_PERMANENT, game, target.getTargets());
targets = threats(opponentId, source, StaticFilters.FILTER_PERMANENT, game, target.getTargets());
}
// planeswalkers
@ -1208,9 +1193,9 @@ public class ComputerPlayer extends PlayerImpl implements Player {
for (UUID opponentId : opponents) {
if (!outcome.isGood()) {
// bad on yourself, uses weakest targets
targets = threats(getId(), sourceId, StaticFilters.FILTER_PERMANENT, game, target.getTargets(), false);
targets = threats(getId(), source, StaticFilters.FILTER_PERMANENT, game, target.getTargets(), false);
} else {
targets = threats(opponentId, sourceId, StaticFilters.FILTER_PERMANENT, game, target.getTargets(), false);
targets = threats(opponentId, source, StaticFilters.FILTER_PERMANENT, game, target.getTargets(), false);
}
// creatures - non killable (TODO: add extra skill checks like undestructeable)
@ -1668,7 +1653,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
// pay phyrexian life costs
if (cost instanceof PhyrexianManaCost) {
if (cost.isPhyrexian()) {
return cost.pay(ability, game, ability, playerId, false, null) || approvingObject != null;
}
@ -2005,7 +1990,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
// we still use playerId when getting cards even if they don't control the search
List<Card> cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), source != null ? source.getSourceId() : null, playerId, game));
List<Card> cardChoices = new ArrayList<>(cards.getCards(target.getFilter(), playerId, source, game));
while (!target.doneChosing()) {
Card card = pickTarget(abilityControllerId, cardChoices, outcome, target, source, game);
if (card != null) {
@ -2125,7 +2110,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
continue AvailableMode;
}
}
if (mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and where targets are available
if (mode.getTargets().canChoose(source.getControllerId(), source, game)) { // and where targets are available
return mode;
}
}
@ -2710,7 +2695,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return worst;
}
protected void findBestPermanentTargets(Outcome outcome, UUID abilityControllerId, UUID sourceId, FilterPermanent filter, Game game, Target target,
protected void findBestPermanentTargets(Outcome outcome, UUID abilityControllerId, UUID sourceId, Ability source, FilterPermanent filter, Game game, Target target,
List<Permanent> goodList, List<Permanent> badList, List<Permanent> allList) {
// searching for most valuable/powerfull permanents
goodList.clear();
@ -2719,7 +2704,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
List<UUID> usedTargets = target.getTargets();
// search all
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, abilityControllerId, sourceId, game)) {
for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, abilityControllerId, source, game)) {
if (usedTargets.contains(permanent.getId())) {
continue;
}
@ -2767,19 +2752,19 @@ public class ComputerPlayer extends PlayerImpl implements Player {
}
}
protected List<Permanent> threats(UUID playerId, UUID sourceId, FilterPermanent filter, Game game, List<UUID> targets) {
return threats(playerId, sourceId, filter, game, targets, true);
protected List<Permanent> threats(UUID playerId, Ability source, FilterPermanent filter, Game game, List<UUID> targets) {
return threats(playerId, source, filter, game, targets, true);
}
protected List<Permanent> threats(UUID playerId, UUID sourceId, FilterPermanent filter, Game game, List<UUID> targets, boolean mostValueableGoFirst) {
protected List<Permanent> threats(UUID playerId, Ability source, FilterPermanent filter, Game game, List<UUID> targets, boolean mostValueableGoFirst) {
// most valuable/powerfull permanents goes at first
List<Permanent> threats;
if (playerId == null) {
threats = game.getBattlefield().getActivePermanents(filter, this.getId(), sourceId, game); // all permanents within the range of the player
threats = game.getBattlefield().getActivePermanents(filter, this.getId(), source, game); // all permanents within the range of the player
} else {
FilterPermanent filterCopy = filter.copy();
filterCopy.add(new ControllerIdPredicate(playerId));
threats = game.getBattlefield().getActivePermanents(filter, this.getId(), sourceId, game);
threats = game.getBattlefield().getActivePermanents(filter, this.getId(), source, game);
}
Iterator<Permanent> it = threats.iterator();
while (it.hasNext()) { // remove permanents already targeted
@ -2897,7 +2882,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
*
* @param source null on choose and non-null on chooseTarget
*/
private boolean setTargetPlayer(Outcome outcome, Target target, Ability source, UUID sourceId, UUID abilityControllerId, UUID randomOpponentId, Game game, boolean required) {
private boolean setTargetPlayer(Outcome outcome, Target target, Ability source, UUID abilityControllerId, UUID randomOpponentId, Game game, boolean required) {
Outcome affectedOutcome;
if (abilityControllerId == this.playerId) {
// selects for itself
@ -2931,6 +2916,7 @@ public class ComputerPlayer extends PlayerImpl implements Player {
return false;
}
UUID sourceId = source != null ? source.getSourceId() : null;
if (target.getOriginalTarget() instanceof TargetPlayer) {
if (affectedOutcome.isGood()) {
if (source == null) {
@ -2997,26 +2983,12 @@ public class ComputerPlayer extends PlayerImpl implements Player {
* @return
*/
private UUID getRandomOpponent(UUID abilityControllerId, Game game) {
UUID randomOpponentId = null;
Set<UUID> opponents = game.getOpponents(abilityControllerId);
if (opponents.size() > 1) {
int rand = RandomUtil.nextInt(opponents.size());
int count = 0;
for (UUID currentId : opponents) {
if (count == rand) {
randomOpponentId = currentId;
break;
}
}
} else if (opponents.size() == 1) {
randomOpponentId = game.getOpponents(abilityControllerId).iterator().next();
}
return randomOpponentId;
return RandomUtil.randomFromCollection(game.getOpponents(abilityControllerId));
}
@Override
public SpellAbility chooseAbilityForCast(Card card, Game game, boolean noMana) {
Map<UUID, ActivatedAbility> useable = PlayerImpl.getCastableSpellAbilities(game, this.getId(), card, game.getState().getZone(card.getId()), noMana);
Map<UUID, SpellAbility> useable = PlayerImpl.getCastableSpellAbilities(game, this.getId(), card, game.getState().getZone(card.getId()), noMana);
return (SpellAbility) useable.values().stream().findFirst().orElse(null);
}

View file

@ -221,7 +221,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer {
}
protected boolean chooseRandomTarget(Target target, Ability source, Game game) {
Set<UUID> possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), playerId, game);
Set<UUID> possibleTargets = target.possibleTargets(playerId, source, game);
if (possibleTargets.isEmpty()) {
return false;
}
@ -245,19 +245,19 @@ public class SimulatedPlayerMCTS extends MCTSPlayer {
}
@Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) {
public boolean choose(Outcome outcome, Target target, Ability source, Game game) {
if (this.isHuman()) {
return chooseRandom(target, game);
}
return super.choose(outcome, target, sourceId, game);
return super.choose(outcome, target, source, game);
}
@Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map<String, Serializable> options) {
public boolean choose(Outcome outcome, Target target, Ability source, Game game, Map<String, Serializable> options) {
if (this.isHuman()) {
return chooseRandom(target, game);
}
return super.choose(outcome, target, sourceId, game, options);
return super.choose(outcome, target, source, game, options);
}
@Override
@ -302,7 +302,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer {
@Override
public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) {
Set<UUID> possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), playerId, game);
Set<UUID> possibleTargets = target.possibleTargets(playerId, source, game);
if (possibleTargets.isEmpty()) {
return !target.isRequired(source);
}

View file

@ -235,7 +235,7 @@ public class ComputerPlayer2 extends ComputerPlayer implements Player {
if (effect != null && ability.getControllerId().equals(playerId)) {
Target target = effect.getTarget();
if (!target.doneChosing()) {
for (UUID targetId: target.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) {
for (UUID targetId: target.possibleTargets(ability.getControllerId(), ability.getStackAbility(), game)) {
Game sim = game.copy();
StackAbility newAbility = (StackAbility) ability.copy();
SearchEffect newEffect = getSearchEffect((StackAbility) newAbility);

View file

@ -498,12 +498,12 @@ public class HumanPlayer extends PlayerImpl {
}
@Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) {
return choose(outcome, target, sourceId, game, null);
public boolean choose(Outcome outcome, Target target, Ability source, Game game) {
return choose(outcome, target, source, game, null);
}
@Override
public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map<String, Serializable> options) {
public boolean choose(Outcome outcome, Target target, Ability source, Game game, Map<String, Serializable> options) {
if (gameInCheckPlayableState(game)) {
return true;
}
@ -519,12 +519,12 @@ public class HumanPlayer extends PlayerImpl {
}
while (canRespond()) {
Set<UUID> targetIds = target.possibleTargets(sourceId, abilityControllerId, game);
Set<UUID> targetIds = target.possibleTargets(abilityControllerId, source, game);
if (targetIds == null || targetIds.isEmpty()) {
return target.getTargets().size() >= target.getNumberOfTargets();
}
boolean required = target.isRequired(sourceId, game);
boolean required = target.isRequired(source != null ? source.getSourceId() : null, game);
if (target.getTargets().size() >= target.getNumberOfTargets()) {
required = false;
}
@ -535,7 +535,7 @@ public class HumanPlayer extends PlayerImpl {
updateGameStatePriority("choose(5)", game);
prepareForResponse(game);
if (!isExecutingMacro()) {
game.fireSelectTargetEvent(getId(), new MessageToClient(target.getMessage(), getRelatedObjectName(sourceId, game)), targetIds, required, getOptions(target, options));
game.fireSelectTargetEvent(getId(), new MessageToClient(target.getMessage(), getRelatedObjectName(source, game)), targetIds, required, getOptions(target, options));
}
waitForResponse(game);
@ -554,14 +554,14 @@ public class HumanPlayer extends PlayerImpl {
}
if (target instanceof TargetPermanent) {
if (((TargetPermanent) target).canTarget(abilityControllerId, responseId, sourceId, game, false)) {
if (((TargetPermanent) target).canTarget(abilityControllerId, responseId, source, game, false)) {
target.add(responseId, game);
if (target.doneChosing()) {
return true;
}
}
} else {
MageObject object = game.getObject(sourceId);
MageObject object = game.getObject(source);
if (object instanceof Ability) {
if (target.canTarget(responseId, (Ability) object, game)) {
if (target.getTargets().contains(responseId)) { // if already included remove it with
@ -617,7 +617,7 @@ public class HumanPlayer extends PlayerImpl {
Map<String, Serializable> options = new HashMap<>();
while (canRespond()) {
Set<UUID> possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), abilityControllerId, game);
Set<UUID> possibleTargets = target.possibleTargets(abilityControllerId, source, game);
boolean required = target.isRequired(source != null ? source.getSourceId() : null, game);
if (possibleTargets.isEmpty()
|| target.getTargets().size() >= target.getNumberOfTargets()) {
@ -845,7 +845,7 @@ public class HumanPlayer extends PlayerImpl {
// 1. Select targets
while (canRespond()) {
Set<UUID> possibleTargets = target.possibleTargets(source == null ? null : source.getSourceId(), abilityControllerId, game);
Set<UUID> possibleTargets = target.possibleTargets(abilityControllerId, source, game);
boolean required = target.isRequired(source != null ? source.getSourceId() : null, game);
if (possibleTargets.isEmpty()
|| target.getSize() >= target.getNumberOfTargets()) {
@ -979,7 +979,7 @@ public class HumanPlayer extends PlayerImpl {
FilterCreatureForCombatBlock filter = filterCreatureForCombatBlock.copy();
filter.add(new ControllerIdPredicate(playerId));
// stop skip on any/zero permanents available
int possibleBlockersCount = game.getBattlefield().count(filter, null, playerId, game);
int possibleBlockersCount = game.getBattlefield().count(filter, playerId, null, game);
boolean canStopOnAny = possibleBlockersCount != 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithAnyPermanents();
boolean canStopOnZero = possibleBlockersCount == 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithZeroPermanents();
quickStop = canStopOnAny || canStopOnZero;
@ -1482,7 +1482,7 @@ public class HumanPlayer extends PlayerImpl {
// can't see lands as playable and must know the reason (if they click on land then they get that message)
if (abilityToCast.getAbilityType() == AbilityType.SPELL) {
Spell spell = game.getStack().getSpell(abilityToCast.getSourceId());
boolean haveManaAbilities = object.getAbilities().stream().anyMatch(a -> a instanceof ManaAbility);
boolean haveManaAbilities = object.getAbilities().stream().anyMatch(ManaAbility.class::isInstance);
if (spell != null && !spell.isResolving() && haveManaAbilities) {
switch (spell.getCurrentActivatingManaAbilitiesStep()) {
// if you used special mana ability like convoke then normal mana abilities will be restricted to use, see Convoke for details
@ -1605,9 +1605,9 @@ public class HumanPlayer extends PlayerImpl {
} else if (responseId != null) {
Permanent attacker = game.getPermanent(responseId);
if (attacker != null) {
if (filterCreatureForCombat.match(attacker, null, playerId, game)) {
if (filterCreatureForCombat.match(attacker, playerId, null, game)) {
selectDefender(game.getCombat().getDefenders(), attacker.getId(), game);
} else if (filterAttack.match(attacker, null, playerId, game) && game.getStack().isEmpty()) {
} else if (filterAttack.match(attacker, playerId, null, game) && game.getStack().isEmpty()) {
removeAttackerIfPossible(game, attacker);
}
}
@ -1737,7 +1737,6 @@ public class HumanPlayer extends PlayerImpl {
return true;
} else {
TargetDefender target = new TargetDefender(possibleDefender, attackerId);
target.setNotTarget(true); // player or planswalker hexproof does not prevent attacking a player
if (forcedToAttack) {
StringBuilder sb = new StringBuilder(target.getTargetName());
Permanent attacker = game.getPermanent(attackerId);
@ -1757,7 +1756,6 @@ public class HumanPlayer extends PlayerImpl {
protected UUID selectDefenderForAllAttack(Set<UUID> defenders, Game game) {
TargetDefender target = new TargetDefender(defenders, null);
target.setNotTarget(true); // player or planswalker hexproof does not prevent attacking a player
if (chooseTarget(Outcome.Damage, target, null, game)) {
return getFixedResponseUUID(game);
}
@ -1774,7 +1772,7 @@ public class HumanPlayer extends PlayerImpl {
filter.add(new ControllerIdPredicate(defendingPlayerId));
// stop skip on any/zero permanents available
int possibleBlockersCount = game.getBattlefield().count(filter, null, playerId, game);
int possibleBlockersCount = game.getBattlefield().count(filter, playerId, source, game);
boolean canStopOnAny = possibleBlockersCount != 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithAnyPermanents();
boolean canStopOnZero = possibleBlockersCount == 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithZeroPermanents();
@ -1812,9 +1810,9 @@ public class HumanPlayer extends PlayerImpl {
if (blocker != null) {
boolean removeBlocker = false;
// does not block yet and can block or can block more attackers
if (filter.match(blocker, null, playerId, game)) {
if (filter.match(blocker, playerId, source, game)) {
selectCombatGroup(defendingPlayerId, blocker.getId(), game);
} else if (filterBlock.match(blocker, null, playerId, game)
} else if (filterBlock.match(blocker, playerId, source, game)
&& game.getStack().isEmpty()) {
removeBlocker = true;
}
@ -1894,7 +1892,7 @@ public class HumanPlayer extends PlayerImpl {
prepareForResponse(game);
if (!isExecutingMacro()) {
// possible attackers to block
Set<UUID> attackers = target.possibleTargets(null, playerId, game);
Set<UUID> attackers = target.possibleTargets(playerId, null, game);
Permanent blocker = game.getPermanent(blockerId);
Set<UUID> possibleTargets = new HashSet<>();
for (UUID attackerId : attackers) {
@ -1934,7 +1932,7 @@ public class HumanPlayer extends PlayerImpl {
if (singleTargetName != null) {
target.setTargetName(singleTargetName);
}
choose(Outcome.Damage, target, source.getSourceId(), game);
choose(Outcome.Damage, target, source, game);
if (targets.isEmpty() || targets.contains(target.getFirstTarget())) {
int damageAmount = getAmount(0, remainingDamage, "Select amount", game);
Permanent permanent = game.getPermanent(target.getFirstTarget());
@ -2187,10 +2185,10 @@ public class HumanPlayer extends PlayerImpl {
MageObject object = game.getObject(card.getId()); // must be object to find real abilities (example: commander)
if (object != null) {
String message = "Choose ability to cast" + (noMana ? " for FREE" : "") + "<br>" + object.getLogName();
LinkedHashMap<UUID, ActivatedAbility> useableAbilities = PlayerImpl.getCastableSpellAbilities(game, playerId, object, game.getState().getZone(object.getId()), noMana);
LinkedHashMap<UUID, SpellAbility> useableAbilities = PlayerImpl.getCastableSpellAbilities(game, playerId, object, game.getState().getZone(object.getId()), noMana);
if (useableAbilities != null
&& useableAbilities.size() == 1) {
return (SpellAbility) useableAbilities.values().iterator().next();
return useableAbilities.values().iterator().next();
} else if (useableAbilities != null
&& !useableAbilities.isEmpty()) {
@ -2204,7 +2202,7 @@ public class HumanPlayer extends PlayerImpl {
UUID responseId = getFixedResponseUUID(game);
if (responseId != null) {
if (useableAbilities.containsKey(responseId)) {
return (SpellAbility) useableAbilities.get(responseId);
return useableAbilities.get(responseId);
}
}
}
@ -2224,7 +2222,7 @@ public class HumanPlayer extends PlayerImpl {
if (modes.size() > 1) {
// done option for up to choices
boolean canEndChoice = modes.getSelectedModes().size() >= modes.getMinModes() || modes.isMayChooseNone();
MageObject obj = game.getObject(source.getSourceId());
MageObject obj = game.getObject(source);
Map<UUID, String> modeMap = new LinkedHashMap<>();
int modeIndex = 0;
AvailableModes:
@ -2244,7 +2242,7 @@ public class HumanPlayer extends PlayerImpl {
}
}
if (mode.getTargets().canChoose(source.getSourceId(), source.getControllerId(), game)) { // and needed targets have to be available
if (mode.getTargets().canChoose(source.getControllerId(), source, game)) { // and needed targets have to be available
String modeText = mode.getEffects().getText(mode);
if (obj != null) {
modeText = modeText.replace("{this}", obj.getName());

View file

@ -0,0 +1,512 @@
package mage.tournament.cubes;
import mage.game.draft.DraftCube;
/**
* @author TheBear132
* This cube is taken from this article https://magic.wizards.com/en/articles/archive/magic-online/khans-expanded-cube-2019-07-23
* If the cards are from any of the Tarkir sets, the preferred set will be set to that set
*/
public class KhansExpandedCube extends DraftCube {
public KhansExpandedCube() {
super("MTGO Khans Expanded Cube");
cubeCards.add(new DraftCube.CardIdentity("Herald of Anafenza", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Embodiment of Spring", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Bloodsoaked Champion", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Kolaghan Stormsinger", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Experiment One", ""));
cubeCards.add(new DraftCube.CardIdentity("Taigam, Ojutai Master", ""));
cubeCards.add(new DraftCube.CardIdentity("Chronomaton", ""));
cubeCards.add(new DraftCube.CardIdentity("Arid Mesa", ""));
cubeCards.add(new DraftCube.CardIdentity("Mardu Hateblade", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Enclave Cryptologist", ""));
cubeCards.add(new DraftCube.CardIdentity("Cruel Sadist", ""));
cubeCards.add(new DraftCube.CardIdentity("Monastery Swiftspear", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Gnarlwood Dryad", ""));
cubeCards.add(new DraftCube.CardIdentity("Ojutai, Soul of Winter", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Filigree Familiar", ""));
cubeCards.add(new DraftCube.CardIdentity("Ash Barrens", ""));
cubeCards.add(new DraftCube.CardIdentity("Mardu Woe-Reaper", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Deranged Assistant", ""));
cubeCards.add(new DraftCube.CardIdentity("Disowned Ancestor", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep", ""));
cubeCards.add(new DraftCube.CardIdentity("Patron of the Wild", ""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Silumgar", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Pilgrim's Eye", ""));
cubeCards.add(new DraftCube.CardIdentity("Battlefield Forge", ""));
cubeCards.add(new DraftCube.CardIdentity("Ainok Bond-Kin", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Elusive Spellfist", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Ruthless Ripper", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Firebrand Archer", ""));
cubeCards.add(new DraftCube.CardIdentity("Pelt Collector", ""));
cubeCards.add(new DraftCube.CardIdentity("Connive // Concoct", ""));
cubeCards.add(new DraftCube.CardIdentity("Skittering Surveyor", ""));
cubeCards.add(new DraftCube.CardIdentity("Blood Crypt", ""));
cubeCards.add(new DraftCube.CardIdentity("Daring Skyjek", ""));
cubeCards.add(new DraftCube.CardIdentity("Jeskai Elder", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Shambling Goblin", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Horde Ambusher", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Ainok Survivalist", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Dreadhorde Butcher", ""));
cubeCards.add(new DraftCube.CardIdentity("Awakened Amalgam", ""));
cubeCards.add(new DraftCube.CardIdentity("Bloodfell Caves", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Hidden Dragonslayer", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Jeskai Sage", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Battle Brawler", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Ire Shaman", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Broodhatch Nantuko", ""));
cubeCards.add(new DraftCube.CardIdentity("Dragonlord Kolaghan", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Peace Strider", ""));
cubeCards.add(new DraftCube.CardIdentity("Bloodstained Mire", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Master of Pearls", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Plaxmanta", ""));
cubeCards.add(new DraftCube.CardIdentity("Kitesail Freebooter", ""));
cubeCards.add(new DraftCube.CardIdentity("Jeering Instigator", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Deadly Recluse", ""));
cubeCards.add(new DraftCube.CardIdentity("Ghor-Clan Rampager", ""));
cubeCards.add(new DraftCube.CardIdentity("Rampaging Monument", ""));
cubeCards.add(new DraftCube.CardIdentity("Blooming Marsh", ""));
cubeCards.add(new DraftCube.CardIdentity("Remorseful Cleric", ""));
cubeCards.add(new DraftCube.CardIdentity("Qarsi Deceiver", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Mardu Skullhunter", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Kiln Fiend", ""));
cubeCards.add(new DraftCube.CardIdentity("Decorated Champion", ""));
cubeCards.add(new DraftCube.CardIdentity("Atarka, World Render", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Solemn Simulacrum", ""));
cubeCards.add(new DraftCube.CardIdentity("Blossoming Sands", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Seeker of the Way", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Spellweaver Eternal", ""));
cubeCards.add(new DraftCube.CardIdentity("Silumgar Assassin", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Mogg War Marshal", ""));
cubeCards.add(new DraftCube.CardIdentity("Den Protector", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Knight of Autumn", ""));
cubeCards.add(new DraftCube.CardIdentity("Chamber Sentry", ""));
cubeCards.add(new DraftCube.CardIdentity("Botanical Sanctum", ""));
cubeCards.add(new DraftCube.CardIdentity("Soulfire Grand Master", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Stratus Dancer", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Skinthinner", ""));
cubeCards.add(new DraftCube.CardIdentity("Nef-Crop Entangler", ""));
cubeCards.add(new DraftCube.CardIdentity("Glade Watcher", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Dromoka, the Eternal", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Duplicant", ""));
cubeCards.add(new DraftCube.CardIdentity("Breeding Pool", ""));
cubeCards.add(new DraftCube.CardIdentity("Steward of Solidarity", ""));
cubeCards.add(new DraftCube.CardIdentity("Willbender", ""));
cubeCards.add(new DraftCube.CardIdentity("Sultai Emissary", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Skirk Marauder", ""));
cubeCards.add(new DraftCube.CardIdentity("Heir of the Wilds", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Chief of the Edge", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Animation Module", ""));
cubeCards.add(new DraftCube.CardIdentity("Caves of Koilos", ""));
cubeCards.add(new DraftCube.CardIdentity("Tithe Taker", ""));
cubeCards.add(new DraftCube.CardIdentity("Echo Tracer", ""));
cubeCards.add(new DraftCube.CardIdentity("Aphetto Exterminator", ""));
cubeCards.add(new DraftCube.CardIdentity("Thermo-Alchemist", ""));
cubeCards.add(new DraftCube.CardIdentity("Obsessive Skinner", ""));
cubeCards.add(new DraftCube.CardIdentity("Chief of the Scale", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Ghostfire Blade", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Concealed Courtyard", ""));
cubeCards.add(new DraftCube.CardIdentity("Wall of Omens", ""));
cubeCards.add(new DraftCube.CardIdentity("Riptide Entrancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Blood-Chin Fanatic", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("War-Name Aspirant", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Rattleclaw Mystic", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Elenda, the Dusk Rose", ""));
cubeCards.add(new DraftCube.CardIdentity("Sylvok Lifestaff", ""));
cubeCards.add(new DraftCube.CardIdentity("Dismal Backwater", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Abzan Falconer", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Riptide Survivor", ""));
cubeCards.add(new DraftCube.CardIdentity("Graveblade Marauder", ""));
cubeCards.add(new DraftCube.CardIdentity("Crater Elemental", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Ilysian Caryatid", ""));
cubeCards.add(new DraftCube.CardIdentity("Mortify", ""));
cubeCards.add(new DraftCube.CardIdentity("Triangle of War", ""));
cubeCards.add(new DraftCube.CardIdentity("Evolving Wilds", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Arashin Foremost", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Aphetto Runecaster", ""));
cubeCards.add(new DraftCube.CardIdentity("Grim Haruspex", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Flamewake Phoenix", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Deathmist Raptor", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Start // Finish", ""));
cubeCards.add(new DraftCube.CardIdentity("Cranial Archive", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Flooded Strand", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Kor Sanctifiers", ""));
cubeCards.add(new DraftCube.CardIdentity("Gurmag Drowner", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Mardu Strike Leader", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Legion Warboss", ""));
cubeCards.add(new DraftCube.CardIdentity("Springbloom Druid", ""));
cubeCards.add(new DraftCube.CardIdentity("Utter End", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Dream Chisel", ""));
cubeCards.add(new DraftCube.CardIdentity("Frontier Bivouac", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Mardu Hordechief", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Kheru Spellsnatcher", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Necravolver", ""));
cubeCards.add(new DraftCube.CardIdentity("Bonecrusher Giant", ""));
cubeCards.add(new DraftCube.CardIdentity("Tuskguard Captain", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Castigate", ""));
cubeCards.add(new DraftCube.CardIdentity("Guild Globe", ""));
cubeCards.add(new DraftCube.CardIdentity("Godless Shrine", ""));
cubeCards.add(new DraftCube.CardIdentity("Monastery Mentor", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Master of the Veil", ""));
cubeCards.add(new DraftCube.CardIdentity("Bane of the Living", ""));
cubeCards.add(new DraftCube.CardIdentity("Reckless Bushwhacker", ""));
cubeCards.add(new DraftCube.CardIdentity("Anavolver", ""));
cubeCards.add(new DraftCube.CardIdentity("Obzedat's Aid", ""));
cubeCards.add(new DraftCube.CardIdentity("Leering Emblem", ""));
cubeCards.add(new DraftCube.CardIdentity("Grand Coliseum", ""));
cubeCards.add(new DraftCube.CardIdentity("Wingbeat Warrior", ""));
cubeCards.add(new DraftCube.CardIdentity("Mistfire Weaver", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Bellowing Saddlebrute", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Skirk Commando", ""));
cubeCards.add(new DraftCube.CardIdentity("Armorcraft Judge", ""));
cubeCards.add(new DraftCube.CardIdentity("Death Grasp", ""));
cubeCards.add(new DraftCube.CardIdentity("Prophetic Prism", ""));
cubeCards.add(new DraftCube.CardIdentity("Hallowed Fountain", ""));
cubeCards.add(new DraftCube.CardIdentity("Abzan Battle Priest", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Niblis of Frost", ""));
cubeCards.add(new DraftCube.CardIdentity("Gift of Doom", ""));
cubeCards.add(new DraftCube.CardIdentity("Smelt-Ward Minotaur", ""));
cubeCards.add(new DraftCube.CardIdentity("Goreclaw, Terror of Qal Sisma", ""));
cubeCards.add(new DraftCube.CardIdentity("Campaign of Vengeance", ""));
cubeCards.add(new DraftCube.CardIdentity("Stormrider Rig", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Hissing Quagmire", ""));
cubeCards.add(new DraftCube.CardIdentity("Aven Liberator", ""));
cubeCards.add(new DraftCube.CardIdentity("Talrand, Sky Summoner", ""));
cubeCards.add(new DraftCube.CardIdentity("Grinning Demon", ""));
cubeCards.add(new DraftCube.CardIdentity("Ashcloud Phoenix", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Nantuko Vigilante", ""));
cubeCards.add(new DraftCube.CardIdentity("Golgari Guildmage", ""));
cubeCards.add(new DraftCube.CardIdentity("Trip Noose", ""));
cubeCards.add(new DraftCube.CardIdentity("Inspiring Vantage", ""));
cubeCards.add(new DraftCube.CardIdentity("Daru Sanctifier", ""));
cubeCards.add(new DraftCube.CardIdentity("Chromeshell Crab", ""));
cubeCards.add(new DraftCube.CardIdentity("Haunted Cadaver", ""));
cubeCards.add(new DraftCube.CardIdentity("Atarka Efreet", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Serpentine Basilisk", ""));
cubeCards.add(new DraftCube.CardIdentity("Dreg Mangler", ""));
cubeCards.add(new DraftCube.CardIdentity("Arcane Encyclopedia", ""));
cubeCards.add(new DraftCube.CardIdentity("Jungle Hollow", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Dragonscale General", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Icefall Regent", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Haunted Dead", ""));
cubeCards.add(new DraftCube.CardIdentity("Battering Craghorn", ""));
cubeCards.add(new DraftCube.CardIdentity("Sultai Flayer", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Corpsejack Menace", ""));
cubeCards.add(new DraftCube.CardIdentity("Sickleslicer", ""));
cubeCards.add(new DraftCube.CardIdentity("Llanowar Wastes", ""));
cubeCards.add(new DraftCube.CardIdentity("High Sentinels of Arashin", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Ixidor, Reality Sculptor", ""));
cubeCards.add(new DraftCube.CardIdentity("Mer-Ek Nightblade", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Blistering Firecat", ""));
cubeCards.add(new DraftCube.CardIdentity("Surrak, the Hunt Caller", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Izoni, Thousand-Eyed", ""));
cubeCards.add(new DraftCube.CardIdentity("Bonehoard", ""));
cubeCards.add(new DraftCube.CardIdentity("Lumbering Falls", ""));
cubeCards.add(new DraftCube.CardIdentity("Ojutai Exemplars", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Ixidron", ""));
cubeCards.add(new DraftCube.CardIdentity("Thrasher Brute", ""));
cubeCards.add(new DraftCube.CardIdentity("Erratic Cyclops", ""));
cubeCards.add(new DraftCube.CardIdentity("Thelonite Hermit", ""));
cubeCards.add(new DraftCube.CardIdentity("Assassin's Trophy", ""));
cubeCards.add(new DraftCube.CardIdentity("Obelisk of Alara", ""));
cubeCards.add(new DraftCube.CardIdentity("Marsh Flats", ""));
cubeCards.add(new DraftCube.CardIdentity("Stonehorn Dignitary", ""));
cubeCards.add(new DraftCube.CardIdentity("Mischievous Quanar", ""));
cubeCards.add(new DraftCube.CardIdentity("Creakwood Ghoul", ""));
cubeCards.add(new DraftCube.CardIdentity("Goblin Heelcutter", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Challenger Troll", ""));
cubeCards.add(new DraftCube.CardIdentity("Grisly Salvage", ""));
cubeCards.add(new DraftCube.CardIdentity("Misty Rainforest", ""));
cubeCards.add(new DraftCube.CardIdentity("Elite Scaleguard", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Soulblade Djinn", ""));
cubeCards.add(new DraftCube.CardIdentity("Rakshasa Gravecaller", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Mardu Heart-Piercer", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Conclave Naturalists", ""));
cubeCards.add(new DraftCube.CardIdentity("Find // Finality", ""));
cubeCards.add(new DraftCube.CardIdentity("Mystic Monastery", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Giant Killer", ""));
cubeCards.add(new DraftCube.CardIdentity("Vesuvan Shapeshifter", ""));
cubeCards.add(new DraftCube.CardIdentity("Noosegraf Mob", ""));
cubeCards.add(new DraftCube.CardIdentity("Caldera Hellion", ""));
cubeCards.add(new DraftCube.CardIdentity("Gigapede", ""));
cubeCards.add(new DraftCube.CardIdentity("Death Frenzy", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Needle Spires", ""));
cubeCards.add(new DraftCube.CardIdentity("Patron of the Valiant", ""));
cubeCards.add(new DraftCube.CardIdentity("Brine Elemental", ""));
cubeCards.add(new DraftCube.CardIdentity("Silent Specter", ""));
cubeCards.add(new DraftCube.CardIdentity("Charging Monstrosaur", ""));
cubeCards.add(new DraftCube.CardIdentity("Hystrodon", ""));
cubeCards.add(new DraftCube.CardIdentity("Deadbridge Chant", ""));
cubeCards.add(new DraftCube.CardIdentity("Nomad Outpost", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Wingmate Roc", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Quicksilver Dragon", ""));
cubeCards.add(new DraftCube.CardIdentity("Gurmag Angler", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Dragon-Style Twins", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Kessig Cagebreakers", ""));
cubeCards.add(new DraftCube.CardIdentity("Nyx Weaver", ""));
cubeCards.add(new DraftCube.CardIdentity("Opulent Palace", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Daru Lancer", ""));
cubeCards.add(new DraftCube.CardIdentity("Thousand Winds", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Tombstalker", ""));
cubeCards.add(new DraftCube.CardIdentity("Flamerush Rider", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Pine Walker", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Coiling Oracle", ""));
cubeCards.add(new DraftCube.CardIdentity("Overgrown Tomb", ""));
cubeCards.add(new DraftCube.CardIdentity("Exalted Angel", ""));
cubeCards.add(new DraftCube.CardIdentity("Dive Down", ""));
cubeCards.add(new DraftCube.CardIdentity("Necropolis Fiend", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Quakefoot Cyclops", ""));
cubeCards.add(new DraftCube.CardIdentity("Primal Whisperer", ""));
cubeCards.add(new DraftCube.CardIdentity("Icefeather Aven", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Polluted Delta", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Linvala, the Preserver", ""));
cubeCards.add(new DraftCube.CardIdentity("Opt", ""));
cubeCards.add(new DraftCube.CardIdentity("Ghastly Demise", ""));
cubeCards.add(new DraftCube.CardIdentity("Skarrgan Hellkite", ""));
cubeCards.add(new DraftCube.CardIdentity("Hooting Mandrills", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Mystic Snake", ""));
cubeCards.add(new DraftCube.CardIdentity("Prismatic Vista", ""));
cubeCards.add(new DraftCube.CardIdentity("Harm's Way", ""));
cubeCards.add(new DraftCube.CardIdentity("Stubborn Denial", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Moment of Craving", ""));
cubeCards.add(new DraftCube.CardIdentity("Firemaw Kavu", ""));
cubeCards.add(new DraftCube.CardIdentity("Root Elemental", ""));
cubeCards.add(new DraftCube.CardIdentity("Sagu Mauler", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Rugged Highlands", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Path to Exile", ""));
cubeCards.add(new DraftCube.CardIdentity("Disdainful Stroke", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Vicious Offering", ""));
cubeCards.add(new DraftCube.CardIdentity("Rockshard Elemental", ""));
cubeCards.add(new DraftCube.CardIdentity("Temur War Shaman", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Applied Biomancy", ""));
cubeCards.add(new DraftCube.CardIdentity("Sacred Foundry", ""));
cubeCards.add(new DraftCube.CardIdentity("Sheltering Light", ""));
cubeCards.add(new DraftCube.CardIdentity("Force Away", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Expunge", ""));
cubeCards.add(new DraftCube.CardIdentity("Bedlam Reveler", ""));
cubeCards.add(new DraftCube.CardIdentity("Hooded Hydra", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Ethereal Ambush", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Sandsteppe Citadel", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Adamant Will", ""));
cubeCards.add(new DraftCube.CardIdentity("Impulse", ""));
cubeCards.add(new DraftCube.CardIdentity("Murder", ""));
cubeCards.add(new DraftCube.CardIdentity("Weapon Surge", ""));
cubeCards.add(new DraftCube.CardIdentity("Venomspout Brackus", ""));
cubeCards.add(new DraftCube.CardIdentity("Incubation // Incongruity", ""));
cubeCards.add(new DraftCube.CardIdentity("Scalding Tarn", ""));
cubeCards.add(new DraftCube.CardIdentity("Artful Maneuver", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Jilt", ""));
cubeCards.add(new DraftCube.CardIdentity("Foul Renewal", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Burning Oil", ""));
cubeCards.add(new DraftCube.CardIdentity("Earthbrawn", ""));
cubeCards.add(new DraftCube.CardIdentity("Urban Evolution", ""));
cubeCards.add(new DraftCube.CardIdentity("Scoured Barrens", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Disenchant", ""));
cubeCards.add(new DraftCube.CardIdentity("Reality Shift", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Price of Fame", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightning Strike", ""));
cubeCards.add(new DraftCube.CardIdentity("Grapple with the Past", ""));
cubeCards.add(new DraftCube.CardIdentity("Secret Plans", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Shambling Vent", ""));
cubeCards.add(new DraftCube.CardIdentity("Feat of Resistance", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Think Twice", ""));
cubeCards.add(new DraftCube.CardIdentity("Murderous Cut", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Temur Battle Rage", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Winds of Qal Sisma", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Yavimaya's Embrace", ""));
cubeCards.add(new DraftCube.CardIdentity("Shivan Reef", ""));
cubeCards.add(new DraftCube.CardIdentity("Feeling of Dread", ""));
cubeCards.add(new DraftCube.CardIdentity("Twisted Reflection", ""));
cubeCards.add(new DraftCube.CardIdentity("Reach of Shadows", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Omen of the Forge", ""));
cubeCards.add(new DraftCube.CardIdentity("Crushing Canopy", ""));
cubeCards.add(new DraftCube.CardIdentity("Stormchaser Mage", ""));
cubeCards.add(new DraftCube.CardIdentity("Spirebluff Canal", ""));
cubeCards.add(new DraftCube.CardIdentity("Phalanx Tactics", ""));
cubeCards.add(new DraftCube.CardIdentity("Winds of Rebuke", ""));
cubeCards.add(new DraftCube.CardIdentity("Death Wind", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Brimstone Volley", ""));
cubeCards.add(new DraftCube.CardIdentity("Gnaw to the Bone", ""));
cubeCards.add(new DraftCube.CardIdentity("Bloodwater Entity", ""));
cubeCards.add(new DraftCube.CardIdentity("Steam Vents", ""));
cubeCards.add(new DraftCube.CardIdentity("Valorous Stance", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Forbidden Alchemy", ""));
cubeCards.add(new DraftCube.CardIdentity("Duress", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Geistblast", ""));
cubeCards.add(new DraftCube.CardIdentity("Thornado", ""));
cubeCards.add(new DraftCube.CardIdentity("Wee Dragonauts", ""));
cubeCards.add(new DraftCube.CardIdentity("Stomping Ground", ""));
cubeCards.add(new DraftCube.CardIdentity("Generous Gift", ""));
cubeCards.add(new DraftCube.CardIdentity("Phantasmal Form", ""));
cubeCards.add(new DraftCube.CardIdentity("Chainer's Edict", ""));
cubeCards.add(new DraftCube.CardIdentity("Risk Factor", ""));
cubeCards.add(new DraftCube.CardIdentity("Wild Hunger", ""));
cubeCards.add(new DraftCube.CardIdentity("Crackling Drake", ""));
cubeCards.add(new DraftCube.CardIdentity("Swiftwater Cliffs", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Radiant's Judgment", ""));
cubeCards.add(new DraftCube.CardIdentity("Repulse", ""));
cubeCards.add(new DraftCube.CardIdentity("Agonizing Remorse", ""));
cubeCards.add(new DraftCube.CardIdentity("Bolt Bend", ""));
cubeCards.add(new DraftCube.CardIdentity("Become Immense", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Hypersonic Dragon", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple Garden", ""));
cubeCards.add(new DraftCube.CardIdentity("Rally the Peasants", ""));
cubeCards.add(new DraftCube.CardIdentity("Sinister Sabotage", ""));
cubeCards.add(new DraftCube.CardIdentity("Morgue Theft", ""));
cubeCards.add(new DraftCube.CardIdentity("Burn Away", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Savage Swipe", ""));
cubeCards.add(new DraftCube.CardIdentity("Izzet Charm", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Abandon", ""));
cubeCards.add(new DraftCube.CardIdentity("Miraculous Recovery", ""));
cubeCards.add(new DraftCube.CardIdentity("Chemister's Insight", ""));
cubeCards.add(new DraftCube.CardIdentity("Mire Triton", ""));
cubeCards.add(new DraftCube.CardIdentity("Deem Worthy", ""));
cubeCards.add(new DraftCube.CardIdentity("Epic Confrontation", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Electrolyze", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Deceit", ""));
cubeCards.add(new DraftCube.CardIdentity("Oust", ""));
cubeCards.add(new DraftCube.CardIdentity("Commit // Memory", ""));
cubeCards.add(new DraftCube.CardIdentity("Doomfall", ""));
cubeCards.add(new DraftCube.CardIdentity("Flames of the Raze-Boar", ""));
cubeCards.add(new DraftCube.CardIdentity("Savage Punch", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Sonic Assault", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Enlightenment", ""));
cubeCards.add(new DraftCube.CardIdentity("Collective Effort", ""));
cubeCards.add(new DraftCube.CardIdentity("Icy Blast", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Heartless Pillage", ""));
cubeCards.add(new DraftCube.CardIdentity("Faithless Looting", ""));
cubeCards.add(new DraftCube.CardIdentity("Tracker's Instincts", ""));
cubeCards.add(new DraftCube.CardIdentity("Winterflame", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Temple of Epiphany", ""));
cubeCards.add(new DraftCube.CardIdentity("Slaughter the Strong", ""));
cubeCards.add(new DraftCube.CardIdentity("Dig Through Time", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Infest", ""));
cubeCards.add(new DraftCube.CardIdentity("Flame Slash", ""));
cubeCards.add(new DraftCube.CardIdentity("Winding Way", ""));
cubeCards.add(new DraftCube.CardIdentity("Prophetic Bolt", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Malady", ""));
cubeCards.add(new DraftCube.CardIdentity("End Hostilities", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Callous Dismissal", ""));
cubeCards.add(new DraftCube.CardIdentity("Parting Thoughts", ""));
cubeCards.add(new DraftCube.CardIdentity("Reckless Charge", ""));
cubeCards.add(new DraftCube.CardIdentity("Map the Wastes", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Honored Crop-Captain", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Malice", ""));
cubeCards.add(new DraftCube.CardIdentity("Fell the Mighty", ""));
cubeCards.add(new DraftCube.CardIdentity("Chart a Course", ""));
cubeCards.add(new DraftCube.CardIdentity("Wander in Death", ""));
cubeCards.add(new DraftCube.CardIdentity("Nightbird's Clutches", ""));
cubeCards.add(new DraftCube.CardIdentity("Voracious Hydra", ""));
cubeCards.add(new DraftCube.CardIdentity("Sunhome Guildmage", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Mystery", ""));
cubeCards.add(new DraftCube.CardIdentity("Myth Realized", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Strategic Planning", ""));
cubeCards.add(new DraftCube.CardIdentity("Moan of the Unhallowed", ""));
cubeCards.add(new DraftCube.CardIdentity("Roast", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Nissa's Judgment", ""));
cubeCards.add(new DraftCube.CardIdentity("Viashino Firstblade", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Plenty", ""));
cubeCards.add(new DraftCube.CardIdentity("Mastery of the Unseen", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Write into Being", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Smiting Helix", ""));
cubeCards.add(new DraftCube.CardIdentity("Tormenting Voice", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Spider Spawning", ""));
cubeCards.add(new DraftCube.CardIdentity("Firemane Avenger", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Silence", ""));
cubeCards.add(new DraftCube.CardIdentity("Silkwrap", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Set Adrift", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Vigor Mortis", ""));
cubeCards.add(new DraftCube.CardIdentity("Arc Lightning", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("See the Unwritten", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Foundry Champion", ""));
cubeCards.add(new DraftCube.CardIdentity("Temple of Triumph", ""));
cubeCards.add(new DraftCube.CardIdentity("Suspension Field", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Treasure Cruise", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Crux of Fate", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Collective Defiance", ""));
cubeCards.add(new DraftCube.CardIdentity("Hardened Scales", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Integrity // Intervention", ""));
cubeCards.add(new DraftCube.CardIdentity("Fabled Passage", ""));
cubeCards.add(new DraftCube.CardIdentity("Lightform", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Spontaneous Mutation", ""));
cubeCards.add(new DraftCube.CardIdentity("Dead Drop", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Repeating Barrage", ""));
cubeCards.add(new DraftCube.CardIdentity("Obscuring Aether", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Response // Resurgence", ""));
cubeCards.add(new DraftCube.CardIdentity("Thornwood Falls", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Stasis Snare", ""));
cubeCards.add(new DraftCube.CardIdentity("Riddleform", ""));
cubeCards.add(new DraftCube.CardIdentity("Debilitating Injury", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Rolling Temblor", ""));
cubeCards.add(new DraftCube.CardIdentity("Durable Handicraft", ""));
cubeCards.add(new DraftCube.CardIdentity("Ride Down", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Tranquil Cove", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Cast Out", ""));
cubeCards.add(new DraftCube.CardIdentity("Cloudform", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Raiders' Spoils", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Crater's Claws", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Trail of Mystery", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("War Flare", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Verdant Catacombs", ""));
cubeCards.add(new DraftCube.CardIdentity("Righteous Cause", ""));
cubeCards.add(new DraftCube.CardIdentity("Skywise Teachings", "Dragons of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Raiders' Wake", ""));
cubeCards.add(new DraftCube.CardIdentity("Rageform", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Colossal Majesty", ""));
cubeCards.add(new DraftCube.CardIdentity("Warleader's Helix", ""));
cubeCards.add(new DraftCube.CardIdentity("Wandering Fumarole", ""));
cubeCards.add(new DraftCube.CardIdentity("Mantis Rider", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Watery Grave", ""));
cubeCards.add(new DraftCube.CardIdentity("Shu Yun, the Silent Tempest", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Wind-Scarred Crag", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Elsha of the Infinite", ""));
cubeCards.add(new DraftCube.CardIdentity("Windswept Heath", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Warden of the Eye", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Wooded Foothills", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Efreet Weaponmaster", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Yavimaya Coast", ""));
cubeCards.add(new DraftCube.CardIdentity("Kykar, Wind's Fury", ""));
cubeCards.add(new DraftCube.CardIdentity("Jeskai Charm", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Flying Crane Technique", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Jeskai Ascendancy", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Alesha, Who Smiles at Death", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Butcher of the Horde", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Ankle Shanker", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Zurgo Helmsmasher", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Ponyback Brigade", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Crackling Doom", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Mardu Charm", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Mardu Ascendancy", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Fervent Charge", ""));
cubeCards.add(new DraftCube.CardIdentity("Anafenza, the Foremost", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Siege Rhino", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Armament Corps", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Ivorytusk Fortress", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Abzan Guide", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Abzan Charm", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Ready // Willing", ""));
cubeCards.add(new DraftCube.CardIdentity("Duneblast", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Abzan Ascendancy", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Sidisi, Brood Tyrant", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Rakshasa Vizier", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Sultai Soothsayer", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Abomination of Gudul", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Muldrotha, the Gravetide", ""));
cubeCards.add(new DraftCube.CardIdentity("Tasigur, the Golden Fang", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Sultai Charm", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Villainous Wealth", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Sultai Ascendancy", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Savage Knuckleblade", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Yasova Dragonclaw", "Fate Reforged"));
cubeCards.add(new DraftCube.CardIdentity("Avalanche Tusker", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Bear's Companion", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Surrak Dragonclaw", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Intet, the Dreamer", ""));
cubeCards.add(new DraftCube.CardIdentity("Snowhorn Rider", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Temur Charm", "Khans of Tarkir"));
cubeCards.add(new DraftCube.CardIdentity("Temur Ascendancy", "Khans of Tarkir"));
}
}

View file

@ -0,0 +1,552 @@
package mage.tournament.cubes;
import mage.game.draft.DraftCube;
public class VintageCubeFebruary2022 extends DraftCube {
public VintageCubeFebruary2022() {
super("MTGO Vintage Cube Februrary 2022");
cubeCards.add(new CardIdentity("Abbot of Keral Keep", ""));
cubeCards.add(new CardIdentity("Abrade", ""));
cubeCards.add(new CardIdentity("Academy Ruins", ""));
cubeCards.add(new CardIdentity("Acidic Slime", ""));
cubeCards.add(new CardIdentity("Adanto Vanguard", ""));
cubeCards.add(new CardIdentity("Adeline, Resplendent Cathar", ""));
cubeCards.add(new CardIdentity("Ancestral Recall", ""));
cubeCards.add(new CardIdentity("Ancestral Vision", ""));
cubeCards.add(new CardIdentity("Ancient Tomb", ""));
cubeCards.add(new CardIdentity("Animate Dead", ""));
cubeCards.add(new CardIdentity("Arbor Elf", ""));
cubeCards.add(new CardIdentity("Archangel Avacyn", ""));
cubeCards.add(new CardIdentity("Archon of Cruelty", ""));
cubeCards.add(new CardIdentity("Archon of Valor's Reach", ""));
cubeCards.add(new CardIdentity("Arid Mesa", ""));
cubeCards.add(new CardIdentity("Armageddon", ""));
cubeCards.add(new CardIdentity("Ashen Rider", ""));
cubeCards.add(new CardIdentity("Ashiok, Nightmare Weaver", ""));
cubeCards.add(new CardIdentity("Assassin's Trophy", ""));
cubeCards.add(new CardIdentity("Augur of Autumn", ""));
cubeCards.add(new CardIdentity("Avalanche Riders", ""));
cubeCards.add(new CardIdentity("Avenger of Zendikar", ""));
cubeCards.add(new CardIdentity("Azorius Signet", ""));
cubeCards.add(new CardIdentity("Badlands", ""));
cubeCards.add(new CardIdentity("Balance", ""));
cubeCards.add(new CardIdentity("Baleful Strix", ""));
cubeCards.add(new CardIdentity("Baneslayer Angel", ""));
cubeCards.add(new CardIdentity("Banishing Light", ""));
cubeCards.add(new CardIdentity("Baral, Chief of Compliance", ""));
cubeCards.add(new CardIdentity("Basalt Monolith", ""));
cubeCards.add(new CardIdentity("Batterskull", ""));
cubeCards.add(new CardIdentity("Bayou", ""));
cubeCards.add(new CardIdentity("Bazaar of Baghdad", ""));
cubeCards.add(new CardIdentity("Birds of Paradise", ""));
cubeCards.add(new CardIdentity("Birgi, God of Storytelling", ""));
cubeCards.add(new CardIdentity("Birthing Pod", ""));
cubeCards.add(new CardIdentity("Bitterblossom", ""));
cubeCards.add(new CardIdentity("Black Lotus", ""));
cubeCards.add(new CardIdentity("Blackcleave Cliffs", ""));
cubeCards.add(new CardIdentity("Blade Splicer", ""));
cubeCards.add(new CardIdentity("Blightsteel Colossus", ""));
cubeCards.add(new CardIdentity("Blood Crypt", ""));
cubeCards.add(new CardIdentity("Bloodchief's Thirst", ""));
cubeCards.add(new CardIdentity("Bloodghast", ""));
cubeCards.add(new CardIdentity("Bloodstained Mire", ""));
cubeCards.add(new CardIdentity("Bloodthirsty Adversary", ""));
cubeCards.add(new CardIdentity("Bloodtithe Harvester", ""));
cubeCards.add(new CardIdentity("Blooming Marsh", ""));
cubeCards.add(new CardIdentity("Bolas's Citadel", ""));
cubeCards.add(new CardIdentity("Bomat Courier", ""));
cubeCards.add(new CardIdentity("Bone Shredder", ""));
cubeCards.add(new CardIdentity("Bonecrusher Giant", ""));
cubeCards.add(new CardIdentity("Boros Signet", ""));
cubeCards.add(new CardIdentity("Boseiju, Who Endures", ""));
cubeCards.add(new CardIdentity("Botanical Sanctum", ""));
cubeCards.add(new CardIdentity("Braids, Cabal Minion", ""));
cubeCards.add(new CardIdentity("Brain Freeze", ""));
cubeCards.add(new CardIdentity("Brainstorm", ""));
cubeCards.add(new CardIdentity("Brazen Borrower", ""));
cubeCards.add(new CardIdentity("Breeding Pool", ""));
cubeCards.add(new CardIdentity("Bribery", ""));
cubeCards.add(new CardIdentity("Burst Lightning", ""));
cubeCards.add(new CardIdentity("Cabal Ritual", ""));
cubeCards.add(new CardIdentity("Cathar Commando", ""));
cubeCards.add(new CardIdentity("Celestial Colonnade", ""));
cubeCards.add(new CardIdentity("Chain Lightning", ""));
cubeCards.add(new CardIdentity("Chandra, Torch of Defiance", ""));
cubeCards.add(new CardIdentity("Channel", ""));
cubeCards.add(new CardIdentity("Char", ""));
cubeCards.add(new CardIdentity("Chart a Course", ""));
cubeCards.add(new CardIdentity("Chrome Mox", ""));
cubeCards.add(new CardIdentity("Circle of Dreams Druid", ""));
cubeCards.add(new CardIdentity("Coalition Relic", ""));
cubeCards.add(new CardIdentity("Coercive Portal", ""));
cubeCards.add(new CardIdentity("Collective Brutality", ""));
cubeCards.add(new CardIdentity("Concealed Courtyard", ""));
cubeCards.add(new CardIdentity("Condemn", ""));
cubeCards.add(new CardIdentity("Consecrated Sphinx", ""));
cubeCards.add(new CardIdentity("Containment Priest", ""));
cubeCards.add(new CardIdentity("Copperline Gorge", ""));
cubeCards.add(new CardIdentity("Council's Judgment", ""));
cubeCards.add(new CardIdentity("Counterspell", ""));
cubeCards.add(new CardIdentity("Courser of Kruphix", ""));
cubeCards.add(new CardIdentity("Craterhoof Behemoth", ""));
cubeCards.add(new CardIdentity("Creeping Tar Pit", ""));
cubeCards.add(new CardIdentity("Crop Rotation", ""));
cubeCards.add(new CardIdentity("Crucible of Worlds", ""));
cubeCards.add(new CardIdentity("Cryptbreaker", ""));
cubeCards.add(new CardIdentity("Cryptic Command", ""));
cubeCards.add(new CardIdentity("Cultivate", ""));
cubeCards.add(new CardIdentity("Custodi Lich", ""));
cubeCards.add(new CardIdentity("Dack Fayden", ""));
cubeCards.add(new CardIdentity("Damn", ""));
cubeCards.add(new CardIdentity("Damnation", ""));
cubeCards.add(new CardIdentity("Daretti, Ingenious Iconoclast", ""));
cubeCards.add(new CardIdentity("Daretti, Scrap Savant", ""));
cubeCards.add(new CardIdentity("Dark Confidant", ""));
cubeCards.add(new CardIdentity("Dark Depths", ""));
cubeCards.add(new CardIdentity("Dark Ritual", ""));
cubeCards.add(new CardIdentity("Darkslick Shores", ""));
cubeCards.add(new CardIdentity("Dauthi Voidwalker", ""));
cubeCards.add(new CardIdentity("Daze", ""));
cubeCards.add(new CardIdentity("Deathcap Glade", ""));
cubeCards.add(new CardIdentity("Deceiver Exarch", ""));
cubeCards.add(new CardIdentity("Demonic Tutor", ""));
cubeCards.add(new CardIdentity("Deranged Hermit", ""));
cubeCards.add(new CardIdentity("Deserted Beach", ""));
cubeCards.add(new CardIdentity("Desperate Ritual", ""));
cubeCards.add(new CardIdentity("Destructive Force", ""));
cubeCards.add(new CardIdentity("Devoted Druid", ""));
cubeCards.add(new CardIdentity("Dig Through Time", ""));
cubeCards.add(new CardIdentity("Dimir Signet", ""));
cubeCards.add(new CardIdentity("Dire Fleet Daredevil", ""));
cubeCards.add(new CardIdentity("Disenchant", ""));
cubeCards.add(new CardIdentity("Dismember", ""));
cubeCards.add(new CardIdentity("Dockside Extortionist", ""));
cubeCards.add(new CardIdentity("Dragon's Rage Channeler", ""));
cubeCards.add(new CardIdentity("Dreamroot Cascade", ""));
cubeCards.add(new CardIdentity("Duress", ""));
cubeCards.add(new CardIdentity("Eater of Virtue", ""));
cubeCards.add(new CardIdentity("Echo of Eons", ""));
cubeCards.add(new CardIdentity("Edric, Spymaster of Trest", ""));
cubeCards.add(new CardIdentity("Eidolon of the Great Revel", ""));
cubeCards.add(new CardIdentity("Elder Gargaroth", ""));
cubeCards.add(new CardIdentity("Elesh Norn, Grand Cenobite", ""));
cubeCards.add(new CardIdentity("Elite Spellbinder", ""));
cubeCards.add(new CardIdentity("Elspeth Conquers Death", ""));
cubeCards.add(new CardIdentity("Elspeth, Knight-Errant", ""));
cubeCards.add(new CardIdentity("Elspeth, Sun's Champion", ""));
cubeCards.add(new CardIdentity("Elvish Mystic", ""));
cubeCards.add(new CardIdentity("Elvish Reclaimer", ""));
cubeCards.add(new CardIdentity("Embereth Shieldbreaker", ""));
cubeCards.add(new CardIdentity("Empty the Warrens", ""));
cubeCards.add(new CardIdentity("Emrakul, the Aeons Torn", ""));
cubeCards.add(new CardIdentity("Emrakul, the Promised End", ""));
cubeCards.add(new CardIdentity("Emry, Lurker of the Loch", ""));
cubeCards.add(new CardIdentity("Endurance", ""));
cubeCards.add(new CardIdentity("Entomb", ""));
cubeCards.add(new CardIdentity("Ephemerate", ""));
cubeCards.add(new CardIdentity("Escape to the Wilds", ""));
cubeCards.add(new CardIdentity("Esper Sentinel", ""));
cubeCards.add(new CardIdentity("Eternal Witness", ""));
cubeCards.add(new CardIdentity("Eureka", ""));
cubeCards.add(new CardIdentity("Everflowing Chalice", ""));
cubeCards.add(new CardIdentity("Exhume", ""));
cubeCards.add(new CardIdentity("Expansion // Explosion", ""));
cubeCards.add(new CardIdentity("Expressive Iteration", ""));
cubeCards.add(new CardIdentity("Fable of the Mirror-Breaker", ""));
cubeCards.add(new CardIdentity("Fact or Fiction", ""));
cubeCards.add(new CardIdentity("Faithless Looting", ""));
cubeCards.add(new CardIdentity("Fallen Shinobi", ""));
cubeCards.add(new CardIdentity("Fastbond", ""));
cubeCards.add(new CardIdentity("Fatal Push", ""));
cubeCards.add(new CardIdentity("Fauna Shaman", ""));
cubeCards.add(new CardIdentity("Field of the Dead", ""));
cubeCards.add(new CardIdentity("Fiery Islet", ""));
cubeCards.add(new CardIdentity("Figure of Destiny", ""));
cubeCards.add(new CardIdentity("Finale of Devastation", ""));
cubeCards.add(new CardIdentity("Fireblast", ""));
cubeCards.add(new CardIdentity("Firebolt", ""));
cubeCards.add(new CardIdentity("Flickerwisp", ""));
cubeCards.add(new CardIdentity("Flooded Strand", ""));
cubeCards.add(new CardIdentity("Force of Negation", ""));
cubeCards.add(new CardIdentity("Force of Will", ""));
cubeCards.add(new CardIdentity("Fractured Identity", ""));
cubeCards.add(new CardIdentity("Frantic Search", ""));
cubeCards.add(new CardIdentity("Fury", ""));
cubeCards.add(new CardIdentity("Fyndhorn Elves", ""));
cubeCards.add(new CardIdentity("Gaea's Cradle", ""));
cubeCards.add(new CardIdentity("Garruk Relentless", ""));
cubeCards.add(new CardIdentity("Garruk Wildspeaker", ""));
cubeCards.add(new CardIdentity("Geist of Saint Traft", ""));
cubeCards.add(new CardIdentity("Gideon Blackblade", ""));
cubeCards.add(new CardIdentity("Gideon Jura", ""));
cubeCards.add(new CardIdentity("Gideon, Ally of Zendikar", ""));
cubeCards.add(new CardIdentity("Gilded Drake", ""));
cubeCards.add(new CardIdentity("Gilded Lotus", ""));
cubeCards.add(new CardIdentity("Gitaxian Probe", ""));
cubeCards.add(new CardIdentity("Giver of Runes", ""));
cubeCards.add(new CardIdentity("Glen Elendra Archmage", ""));
cubeCards.add(new CardIdentity("Goblin Bombardment", ""));
cubeCards.add(new CardIdentity("Goblin Electromancer", ""));
cubeCards.add(new CardIdentity("Goblin Guide", ""));
cubeCards.add(new CardIdentity("Goblin Rabblemaster", ""));
cubeCards.add(new CardIdentity("Goblin Welder", ""));
cubeCards.add(new CardIdentity("Godless Shrine", ""));
cubeCards.add(new CardIdentity("Goldspan Dragon", ""));
cubeCards.add(new CardIdentity("Golgari Signet", ""));
cubeCards.add(new CardIdentity("Golos, Tireless Pilgrim", ""));
cubeCards.add(new CardIdentity("Gonti, Lord of Luxury", ""));
cubeCards.add(new CardIdentity("Grave Titan", ""));
cubeCards.add(new CardIdentity("Green Sun's Zenith", ""));
cubeCards.add(new CardIdentity("Grief", ""));
cubeCards.add(new CardIdentity("Grim Lavamancer", ""));
cubeCards.add(new CardIdentity("Grim Monolith", ""));
cubeCards.add(new CardIdentity("Griselbrand", ""));
cubeCards.add(new CardIdentity("Grist, the Hunger Tide", ""));
cubeCards.add(new CardIdentity("Gruul Signet", ""));
cubeCards.add(new CardIdentity("Gush", ""));
cubeCards.add(new CardIdentity("Halana and Alena, Partners", ""));
cubeCards.add(new CardIdentity("Hallowed Fountain", ""));
cubeCards.add(new CardIdentity("Hangarback Walker", ""));
cubeCards.add(new CardIdentity("Haunted Ridge", ""));
cubeCards.add(new CardIdentity("Hazoret the Fervent", ""));
cubeCards.add(new CardIdentity("Heartbeat of Spring", ""));
cubeCards.add(new CardIdentity("Hellrider", ""));
cubeCards.add(new CardIdentity("Hero of Bladehold", ""));
cubeCards.add(new CardIdentity("Hero's Downfall", ""));
cubeCards.add(new CardIdentity("Hexdrinker", ""));
cubeCards.add(new CardIdentity("High Tide", ""));
cubeCards.add(new CardIdentity("Horizon Canopy", ""));
cubeCards.add(new CardIdentity("Hornet Queen", ""));
cubeCards.add(new CardIdentity("Hullbreaker Horror", ""));
cubeCards.add(new CardIdentity("Huntmaster of the Fells", ""));
cubeCards.add(new CardIdentity("Hydroid Krasis", ""));
cubeCards.add(new CardIdentity("Hymn to Tourach", ""));
cubeCards.add(new CardIdentity("Ignoble Hierarch", ""));
cubeCards.add(new CardIdentity("Imperial Recruiter", ""));
cubeCards.add(new CardIdentity("Imperial Seal", ""));
cubeCards.add(new CardIdentity("Incinerate", ""));
cubeCards.add(new CardIdentity("Infernal Grasp", ""));
cubeCards.add(new CardIdentity("Inferno Titan", ""));
cubeCards.add(new CardIdentity("Inkwell Leviathan", ""));
cubeCards.add(new CardIdentity("Inquisition of Kozilek", ""));
cubeCards.add(new CardIdentity("Inspiring Vantage", ""));
cubeCards.add(new CardIdentity("Intrepid Adversary", ""));
cubeCards.add(new CardIdentity("Iona, Shield of Emeria", ""));
cubeCards.add(new CardIdentity("Izzet Signet", ""));
cubeCards.add(new CardIdentity("Jace, the Mind Sculptor", ""));
cubeCards.add(new CardIdentity("Jace, Vryn's Prodigy", ""));
cubeCards.add(new CardIdentity("Jin-Gitaxias, Progress Tyrant", ""));
cubeCards.add(new CardIdentity("Jokulhaups", ""));
cubeCards.add(new CardIdentity("Joraga Treespeaker", ""));
cubeCards.add(new CardIdentity("Karakas", ""));
cubeCards.add(new CardIdentity("Karmic Guide", ""));
cubeCards.add(new CardIdentity("Karn Liberated", ""));
cubeCards.add(new CardIdentity("Karn, Scion of Urza", ""));
cubeCards.add(new CardIdentity("Kiki-Jiki, Mirror Breaker", ""));
cubeCards.add(new CardIdentity("Kitchen Finks", ""));
cubeCards.add(new CardIdentity("Knight of Autumn", ""));
cubeCards.add(new CardIdentity("Knight of the Reliquary", ""));
cubeCards.add(new CardIdentity("Kogla, the Titan Ape", ""));
cubeCards.add(new CardIdentity("Kolaghan's Command", ""));
cubeCards.add(new CardIdentity("Koth of the Hammer", ""));
cubeCards.add(new CardIdentity("Kroxa, Titan of Death's Hunger", ""));
cubeCards.add(new CardIdentity("Kuldotha Forgemaster", ""));
cubeCards.add(new CardIdentity("Laelia, the Blade Reforged", ""));
cubeCards.add(new CardIdentity("Land Tax", ""));
cubeCards.add(new CardIdentity("Lavaclaw Reaches", ""));
cubeCards.add(new CardIdentity("Leonin Relic-Warder", ""));
cubeCards.add(new CardIdentity("Leovold, Emissary of Trest", ""));
cubeCards.add(new CardIdentity("Library of Alexandria", ""));
cubeCards.add(new CardIdentity("Life from the Loam", ""));
cubeCards.add(new CardIdentity("Light Up the Stage", ""));
cubeCards.add(new CardIdentity("Lightning Bolt", ""));
cubeCards.add(new CardIdentity("Lightning Helix", ""));
cubeCards.add(new CardIdentity("Liliana of the Veil", ""));
cubeCards.add(new CardIdentity("Liliana, the Last Hope", ""));
cubeCards.add(new CardIdentity("Lion Sash", ""));
cubeCards.add(new CardIdentity("Lion's Eye Diamond", ""));
cubeCards.add(new CardIdentity("Living Death", ""));
cubeCards.add(new CardIdentity("Llanowar Elves", ""));
cubeCards.add(new CardIdentity("Lodestone Golem", ""));
cubeCards.add(new CardIdentity("Lotus Bloom", ""));
cubeCards.add(new CardIdentity("Lotus Petal", ""));
cubeCards.add(new CardIdentity("Lurrus of the Dream-Den", ""));
cubeCards.add(new CardIdentity("Lyra Dawnbringer", ""));
cubeCards.add(new CardIdentity("Maelstrom Pulse", ""));
cubeCards.add(new CardIdentity("Magus of the Order", ""));
cubeCards.add(new CardIdentity("Makeshift Mannequin", ""));
cubeCards.add(new CardIdentity("Mana Crypt", ""));
cubeCards.add(new CardIdentity("Mana Drain", ""));
cubeCards.add(new CardIdentity("Mana Flare", ""));
cubeCards.add(new CardIdentity("Mana Leak", ""));
cubeCards.add(new CardIdentity("Mana Tithe", ""));
cubeCards.add(new CardIdentity("Mana Vault", ""));
cubeCards.add(new CardIdentity("Manamorphose", ""));
cubeCards.add(new CardIdentity("Marsh Flats", ""));
cubeCards.add(new CardIdentity("Massacre Wurm", ""));
cubeCards.add(new CardIdentity("Memory Deluge", ""));
cubeCards.add(new CardIdentity("Memory Jar", ""));
cubeCards.add(new CardIdentity("Mesmeric Fiend", ""));
cubeCards.add(new CardIdentity("Metalworker", ""));
cubeCards.add(new CardIdentity("Mind Twist", ""));
cubeCards.add(new CardIdentity("Mind's Desire", ""));
cubeCards.add(new CardIdentity("Mindslaver", ""));
cubeCards.add(new CardIdentity("Mirari's Wake", ""));
cubeCards.add(new CardIdentity("Miscalculation", ""));
cubeCards.add(new CardIdentity("Mishra's Factory", ""));
cubeCards.add(new CardIdentity("Mishra's Workshop", ""));
cubeCards.add(new CardIdentity("Misty Rainforest", ""));
cubeCards.add(new CardIdentity("Monastery Mentor", ""));
cubeCards.add(new CardIdentity("Monastery Swiftspear", ""));
cubeCards.add(new CardIdentity("Mother of Runes", ""));
cubeCards.add(new CardIdentity("Mox Diamond", ""));
cubeCards.add(new CardIdentity("Mox Emerald", ""));
cubeCards.add(new CardIdentity("Mox Jet", ""));
cubeCards.add(new CardIdentity("Mox Pearl", ""));
cubeCards.add(new CardIdentity("Mox Ruby", ""));
cubeCards.add(new CardIdentity("Mox Sapphire", ""));
cubeCards.add(new CardIdentity("Mulldrifter", ""));
cubeCards.add(new CardIdentity("Murderous Rider", ""));
cubeCards.add(new CardIdentity("Murktide Regent", ""));
cubeCards.add(new CardIdentity("Mutavault", ""));
cubeCards.add(new CardIdentity("Myr Battlesphere", ""));
cubeCards.add(new CardIdentity("Mystic Confluence", ""));
cubeCards.add(new CardIdentity("Mystical Tutor", ""));
cubeCards.add(new CardIdentity("Nahiri, the Harbinger", ""));
cubeCards.add(new CardIdentity("Narset, Parter of Veils", ""));
cubeCards.add(new CardIdentity("Nashi, Moon Sage's Scion", ""));
cubeCards.add(new CardIdentity("Natural Order", ""));
cubeCards.add(new CardIdentity("Necromancy", ""));
cubeCards.add(new CardIdentity("Night's Whisper", ""));
cubeCards.add(new CardIdentity("Nighthawk Scavenger", ""));
cubeCards.add(new CardIdentity("Nissa, Vastwood Seer", ""));
cubeCards.add(new CardIdentity("Nissa, Who Shakes the World", ""));
cubeCards.add(new CardIdentity("Niv-Mizzet Reborn", ""));
cubeCards.add(new CardIdentity("Noble Hierarch", ""));
cubeCards.add(new CardIdentity("Nurturing Peatland", ""));
cubeCards.add(new CardIdentity("Oath of Druids", ""));
cubeCards.add(new CardIdentity("Oblivion Stone", ""));
cubeCards.add(new CardIdentity("Oko, Thief of Crowns", ""));
cubeCards.add(new CardIdentity("Olivia, Crimson Bride", ""));
cubeCards.add(new CardIdentity("Omnath, Locus of Creation", ""));
cubeCards.add(new CardIdentity("Oona's Prowler", ""));
cubeCards.add(new CardIdentity("Ophiomancer", ""));
cubeCards.add(new CardIdentity("Opposition", ""));
cubeCards.add(new CardIdentity("Oracle of Mul Daya", ""));
cubeCards.add(new CardIdentity("Orzhov Signet", ""));
cubeCards.add(new CardIdentity("Oust", ""));
cubeCards.add(new CardIdentity("Overgrown Farmland", ""));
cubeCards.add(new CardIdentity("Overgrown Tomb", ""));
cubeCards.add(new CardIdentity("Pack Rat", ""));
cubeCards.add(new CardIdentity("Palace Jailer", ""));
cubeCards.add(new CardIdentity("Palinchron", ""));
cubeCards.add(new CardIdentity("Parallax Wave", ""));
cubeCards.add(new CardIdentity("Past in Flames", ""));
cubeCards.add(new CardIdentity("Path to Exile", ""));
cubeCards.add(new CardIdentity("Pest Infestation", ""));
cubeCards.add(new CardIdentity("Pestermite", ""));
cubeCards.add(new CardIdentity("Phantasmal Image", ""));
cubeCards.add(new CardIdentity("Phyrexian Metamorph", ""));
cubeCards.add(new CardIdentity("Phyrexian Revoker", ""));
cubeCards.add(new CardIdentity("Pia and Kiran Nalaar", ""));
cubeCards.add(new CardIdentity("Plateau", ""));
cubeCards.add(new CardIdentity("Plow Under", ""));
cubeCards.add(new CardIdentity("Polluted Delta", ""));
cubeCards.add(new CardIdentity("Polukranos, World Eater", ""));
cubeCards.add(new CardIdentity("Ponder", ""));
cubeCards.add(new CardIdentity("Porcelain Legionnaire", ""));
cubeCards.add(new CardIdentity("Portent", ""));
cubeCards.add(new CardIdentity("Preordain", ""));
cubeCards.add(new CardIdentity("Primeval Titan", ""));
cubeCards.add(new CardIdentity("Prismatic Vista", ""));
cubeCards.add(new CardIdentity("Progenitus", ""));
cubeCards.add(new CardIdentity("Putrid Imp", ""));
cubeCards.add(new CardIdentity("Pyretic Ritual", ""));
cubeCards.add(new CardIdentity("Questing Beast", ""));
cubeCards.add(new CardIdentity("Ragavan, Nimble Pilferer", ""));
cubeCards.add(new CardIdentity("Raging Ravine", ""));
cubeCards.add(new CardIdentity("Rakdos Signet", ""));
cubeCards.add(new CardIdentity("Ramunap Excavator", ""));
cubeCards.add(new CardIdentity("Ravages of War", ""));
cubeCards.add(new CardIdentity("Ravenous Chupacabra", ""));
cubeCards.add(new CardIdentity("Razorverge Thicket", ""));
cubeCards.add(new CardIdentity("Reanimate", ""));
cubeCards.add(new CardIdentity("Reclamation Sage", ""));
cubeCards.add(new CardIdentity("Recruiter of the Guard", ""));
cubeCards.add(new CardIdentity("Recurring Nightmare", ""));
cubeCards.add(new CardIdentity("Red Elemental Blast", ""));
cubeCards.add(new CardIdentity("Regrowth", ""));
cubeCards.add(new CardIdentity("Relic of Progenitus", ""));
cubeCards.add(new CardIdentity("Remand", ""));
cubeCards.add(new CardIdentity("Repeal", ""));
cubeCards.add(new CardIdentity("Restoration Angel", ""));
cubeCards.add(new CardIdentity("Retrofitter Foundry", ""));
cubeCards.add(new CardIdentity("Rishadan Port", ""));
cubeCards.add(new CardIdentity("Rockfall Vale", ""));
cubeCards.add(new CardIdentity("Rofellos, Llanowar Emissary", ""));
cubeCards.add(new CardIdentity("Rotting Regisaur", ""));
cubeCards.add(new CardIdentity("Runaway Steam-Kin", ""));
cubeCards.add(new CardIdentity("Sacred Foundry", ""));
cubeCards.add(new CardIdentity("Sakura-Tribe Elder", ""));
cubeCards.add(new CardIdentity("Satoru Umezawa", ""));
cubeCards.add(new CardIdentity("Savannah", ""));
cubeCards.add(new CardIdentity("Scalding Tarn", ""));
cubeCards.add(new CardIdentity("Scavenging Ooze", ""));
cubeCards.add(new CardIdentity("Scrapheap Scrounger", ""));
cubeCards.add(new CardIdentity("Scrubland", ""));
cubeCards.add(new CardIdentity("Sea Gate Stormcaller", ""));
cubeCards.add(new CardIdentity("Seachrome Coast", ""));
cubeCards.add(new CardIdentity("Seasoned Pyromancer", ""));
cubeCards.add(new CardIdentity("Sedgemoor Witch", ""));
cubeCards.add(new CardIdentity("Seething Song", ""));
cubeCards.add(new CardIdentity("Selesnya Signet", ""));
cubeCards.add(new CardIdentity("Selfless Spirit", ""));
cubeCards.add(new CardIdentity("Sensei's Divining Top", ""));
cubeCards.add(new CardIdentity("Shallow Grave", ""));
cubeCards.add(new CardIdentity("Shark Typhoon", ""));
cubeCards.add(new CardIdentity("Shattered Sanctum", ""));
cubeCards.add(new CardIdentity("Shelldock Isle", ""));
cubeCards.add(new CardIdentity("Shipwreck Marsh", ""));
cubeCards.add(new CardIdentity("Show and Tell", ""));
cubeCards.add(new CardIdentity("Showdown of the Skalds", ""));
cubeCards.add(new CardIdentity("Shriekmaw", ""));
cubeCards.add(new CardIdentity("Silent Clearing", ""));
cubeCards.add(new CardIdentity("Silverblade Paladin", ""));
cubeCards.add(new CardIdentity("Simic Signet", ""));
cubeCards.add(new CardIdentity("Skullclamp", ""));
cubeCards.add(new CardIdentity("Skyclave Apparition", ""));
cubeCards.add(new CardIdentity("Skyclave Shade", ""));
cubeCards.add(new CardIdentity("Smokestack", ""));
cubeCards.add(new CardIdentity("Smuggler's Copter", ""));
cubeCards.add(new CardIdentity("Snapcaster Mage", ""));
cubeCards.add(new CardIdentity("Sneak Attack", ""));
cubeCards.add(new CardIdentity("Snuff Out", ""));
cubeCards.add(new CardIdentity("Sol Ring", ""));
cubeCards.add(new CardIdentity("Solitude", ""));
cubeCards.add(new CardIdentity("Soulfire Grand Master", ""));
cubeCards.add(new CardIdentity("Sower of Temptation", ""));
cubeCards.add(new CardIdentity("Spear of Heliod", ""));
cubeCards.add(new CardIdentity("Spectral Procession", ""));
cubeCards.add(new CardIdentity("Spell Pierce", ""));
cubeCards.add(new CardIdentity("Spellseeker", ""));
cubeCards.add(new CardIdentity("Sphinx of the Steel Wind", ""));
cubeCards.add(new CardIdentity("Spirebluff Canal", ""));
cubeCards.add(new CardIdentity("Spirit-Sister's Call", ""));
cubeCards.add(new CardIdentity("Splinter Twin", ""));
cubeCards.add(new CardIdentity("Steam Vents", ""));
cubeCards.add(new CardIdentity("Stomping Ground", ""));
cubeCards.add(new CardIdentity("Stoneforge Mystic", ""));
cubeCards.add(new CardIdentity("Stormcarved Coast", ""));
cubeCards.add(new CardIdentity("Strip Mine", ""));
cubeCards.add(new CardIdentity("Student of Warfare", ""));
cubeCards.add(new CardIdentity("Sulfuric Vortex", ""));
cubeCards.add(new CardIdentity("Sun Titan", ""));
cubeCards.add(new CardIdentity("Sunbaked Canyon", ""));
cubeCards.add(new CardIdentity("Sundering Titan", ""));
cubeCards.add(new CardIdentity("Sundown Pass", ""));
cubeCards.add(new CardIdentity("Survival of the Fittest", ""));
cubeCards.add(new CardIdentity("Suspicious Stowaway", ""));
cubeCards.add(new CardIdentity("Sword of Body and Mind", ""));
cubeCards.add(new CardIdentity("Sword of Feast and Famine", ""));
cubeCards.add(new CardIdentity("Sword of Fire and Ice", ""));
cubeCards.add(new CardIdentity("Swords to Plowshares", ""));
cubeCards.add(new CardIdentity("Sylvan Caryatid", ""));
cubeCards.add(new CardIdentity("Sylvan Library", ""));
cubeCards.add(new CardIdentity("Taiga", ""));
cubeCards.add(new CardIdentity("Tamiyo, Compleated Sage", ""));
cubeCards.add(new CardIdentity("Tangle Wire", ""));
cubeCards.add(new CardIdentity("Teferi, Hero of Dominaria", ""));
cubeCards.add(new CardIdentity("Teferi, Time Raveler", ""));
cubeCards.add(new CardIdentity("Temple Garden", ""));
cubeCards.add(new CardIdentity("Tendrils of Agony", ""));
cubeCards.add(new CardIdentity("Terastodon", ""));
cubeCards.add(new CardIdentity("Tezzeret the Seeker", ""));
cubeCards.add(new CardIdentity("Thalia, Guardian of Thraben", ""));
cubeCards.add(new CardIdentity("Thassa's Oracle", ""));
cubeCards.add(new CardIdentity("The Gitrog Monster", ""));
cubeCards.add(new CardIdentity("The Restoration of Eiganjo", ""));
cubeCards.add(new CardIdentity("The Scarab God", ""));
cubeCards.add(new CardIdentity("The Wandering Emperor", ""));
cubeCards.add(new CardIdentity("Thespian's Stage", ""));
cubeCards.add(new CardIdentity("Thieving Skydiver", ""));
cubeCards.add(new CardIdentity("Thirst for Discovery", ""));
cubeCards.add(new CardIdentity("Thoughtseize", ""));
cubeCards.add(new CardIdentity("Thousand-Year Storm", ""));
cubeCards.add(new CardIdentity("Thraben Inspector", ""));
cubeCards.add(new CardIdentity("Thragtusk", ""));
cubeCards.add(new CardIdentity("Thran Dynamo", ""));
cubeCards.add(new CardIdentity("Through the Breach", ""));
cubeCards.add(new CardIdentity("Thundermaw Hellkite", ""));
cubeCards.add(new CardIdentity("Tidehollow Sculler", ""));
cubeCards.add(new CardIdentity("Time Spiral", ""));
cubeCards.add(new CardIdentity("Time Walk", ""));
cubeCards.add(new CardIdentity("Time Warp", ""));
cubeCards.add(new CardIdentity("Timetwister", ""));
cubeCards.add(new CardIdentity("Tinker", ""));
cubeCards.add(new CardIdentity("Tireless Tracker", ""));
cubeCards.add(new CardIdentity("Tolarian Academy", ""));
cubeCards.add(new CardIdentity("Toski, Bearer of Secrets", ""));
cubeCards.add(new CardIdentity("Tovolar's Huntmaster", ""));
cubeCards.add(new CardIdentity("Toxic Deluge", ""));
cubeCards.add(new CardIdentity("Treachery", ""));
cubeCards.add(new CardIdentity("Treasure Cruise", ""));
cubeCards.add(new CardIdentity("Trinket Mage", ""));
cubeCards.add(new CardIdentity("Tropical Island", ""));
cubeCards.add(new CardIdentity("Tundra", ""));
cubeCards.add(new CardIdentity("Turnabout", ""));
cubeCards.add(new CardIdentity("Ugin, the Spirit Dragon", ""));
cubeCards.add(new CardIdentity("Ulamog, the Ceaseless Hunger", ""));
cubeCards.add(new CardIdentity("Ulamog, the Infinite Gyre", ""));
cubeCards.add(new CardIdentity("Umezawa's Jitte", ""));
cubeCards.add(new CardIdentity("Unburial Rites", ""));
cubeCards.add(new CardIdentity("Underground Sea", ""));
cubeCards.add(new CardIdentity("Underworld Breach", ""));
cubeCards.add(new CardIdentity("Unholy Heat", ""));
cubeCards.add(new CardIdentity("Upheaval", ""));
cubeCards.add(new CardIdentity("Uro, Titan of Nature's Wrath", ""));
cubeCards.add(new CardIdentity("Urza's Saga", ""));
cubeCards.add(new CardIdentity("Urza, Lord High Artificer", ""));
cubeCards.add(new CardIdentity("Usher of the Fallen", ""));
cubeCards.add(new CardIdentity("Utopia Sprawl", ""));
cubeCards.add(new CardIdentity("Vampire Hexmage", ""));
cubeCards.add(new CardIdentity("Vampiric Tutor", ""));
cubeCards.add(new CardIdentity("Vendilion Clique", ""));
cubeCards.add(new CardIdentity("Venser, Shaper Savant", ""));
cubeCards.add(new CardIdentity("Verdant Catacombs", ""));
cubeCards.add(new CardIdentity("Vindicate", ""));
cubeCards.add(new CardIdentity("Volcanic Island", ""));
cubeCards.add(new CardIdentity("Volrath's Stronghold", ""));
cubeCards.add(new CardIdentity("Voltaic Visionary", ""));
cubeCards.add(new CardIdentity("Vraska, Golgari Queen", ""));
cubeCards.add(new CardIdentity("Vryn Wingmare", ""));
cubeCards.add(new CardIdentity("Walking Ballista", ""));
cubeCards.add(new CardIdentity("Wall of Omens", ""));
cubeCards.add(new CardIdentity("Wall of Roots", ""));
cubeCards.add(new CardIdentity("Wasteland", ""));
cubeCards.add(new CardIdentity("Waterlogged Grove", ""));
cubeCards.add(new CardIdentity("Watery Grave", ""));
cubeCards.add(new CardIdentity("Wear // Tear", ""));
cubeCards.add(new CardIdentity("Wheel of Fortune", ""));
cubeCards.add(new CardIdentity("Wheel of Misfortune", ""));
cubeCards.add(new CardIdentity("Whisperwood Elemental", ""));
cubeCards.add(new CardIdentity("Windswept Heath", ""));
cubeCards.add(new CardIdentity("Winter Orb", ""));
cubeCards.add(new CardIdentity("Wishclaw Talisman", ""));
cubeCards.add(new CardIdentity("Woe Strider", ""));
cubeCards.add(new CardIdentity("Wooded Foothills", ""));
cubeCards.add(new CardIdentity("Woodfall Primus", ""));
cubeCards.add(new CardIdentity("Worldly Tutor", ""));
cubeCards.add(new CardIdentity("Worn Powerstone", ""));
cubeCards.add(new CardIdentity("Wrath of God", ""));
cubeCards.add(new CardIdentity("Wrenn and Six", ""));
cubeCards.add(new CardIdentity("Wurmcoil Engine", ""));
cubeCards.add(new CardIdentity("Yawgmoth's Bargain", ""));
cubeCards.add(new CardIdentity("Yawgmoth's Will", ""));
cubeCards.add(new CardIdentity("Yorion, Sky Nomad", ""));
cubeCards.add(new CardIdentity("Young Pyromancer", ""));
cubeCards.add(new CardIdentity("Zealous Conscripts", ""));
}
}

View file

@ -123,6 +123,7 @@
<draftCube name="Sam Black's No Search Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.SamBlacksCube"/>
<draftCube name="Timothee Simonot's Twisted Color Pie Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.TimotheeSimonotsTwistedColorPieCube"/>
<draftCube name="MTGA Cube 2020 April" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGACube2020April"/>
<draftCube name="MTGO Khans Expanded Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.KhansExpandedCube"/>
<draftCube name="MTGO Cube March 2014" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGOMarchCube2014"/>
<draftCube name="MTGO Legacy Cube" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCube"/>
<draftCube name="MTGO Legacy Cube 2015 March" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
@ -153,6 +154,7 @@
<draftCube name="MTGO Vintage Cube July 2020" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeJuly2020"/>
<draftCube name="MTGO Vintage Cube December 2020" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeDecember2020"/>
<draftCube name="MTGO Vintage Cube July 2021" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeJuly2021"/>
<draftCube name="MTGO Vintage Cube February 2022" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.VintageCubeFebruary2022"/>
<draftCube name="SCG Con Cube 2018 December" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.ScgConCube2018December"/>
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft.jar" className="mage.tournament.cubes.MTGCube"/>

View file

@ -115,6 +115,7 @@
<draftCube name="Sam Black's No Search Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.SamBlacksCube"/>
<draftCube name="Timothee Simonot's Twisted Color Pie Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.TimotheeSimonotsTwistedColorPieCube"/>
<draftCube name="MTGA Cube 2020 April" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGACube2020April"/>
<draftCube name="MTGO Khans Expanded Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.KhansExpandedCube"/>
<draftCube name="MTGO Cube March 2014" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGOMarchCube2014"/>
<draftCube name="MTGO Legacy Cube" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCube"/>
<draftCube name="MTGO Legacy Cube 2015 March" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.LegacyCubeMarch2015"/>
@ -145,6 +146,7 @@
<draftCube name="MTGO Vintage Cube July 2020" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJuly2020"/>
<draftCube name="MTGO Vintage Cube December 2020" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeDecember2020"/>
<draftCube name="MTGO Vintage Cube July 2021" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeJuly2021"/>
<draftCube name="MTGO Vintage Cube February 2022" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.VintageCubeFebruary2022"/>
<draftCube name="SCG Con Cube 2018 December" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.ScgConCube2018December"/>
<draftCube name="The Peasant's Toolbox" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.PeasantsToolboxCube"/>
<draftCube name="www.MTGCube.com" jar="mage-tournament-booster-draft-${project.version}.jar" className="mage.tournament.cubes.MTGCube"/>

View file

@ -0,0 +1,35 @@
package mage.cards.a;
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards;
import mage.abilities.keyword.CasualtyAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class ALittleChat extends CardImpl {
public ALittleChat(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}");
// Casualty 1
this.addAbility(new CasualtyAbility(this, 1));
// Look at the top two cards of your library. Put one of them into your hand and the other on the bottom of your library.
this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(2, 1, PutCards.HAND, PutCards.BOTTOM_ANY));
}
private ALittleChat(final ALittleChat card) {
super(card);
}
@Override
public ALittleChat copy() {
return new ALittleChat(this);
}
}

View file

@ -12,6 +12,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.target.common.TargetCreaturePermanent;
/**
@ -25,6 +26,7 @@ public final class AbandonReason extends CardImpl {
// Up to two target creatures each get +1/+0 and gain first strike until end of turn.
Effect effect = new BoostTargetEffect(1, 0, Duration.EndOfTurn);
effect.setOutcome(Outcome.Benefit);
effect.setText("Up to two target creatures each get +1/+0");
this.getSpellAbility().addEffect(effect);
effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, "and gain first strike until end of turn");
@ -32,7 +34,7 @@ public final class AbandonReason extends CardImpl {
this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2));
// Madness {1}{R}
this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{R}")));
this.addAbility(new MadnessAbility(new ManaCostsImpl<>("{1}{R}")));
}
private AbandonReason(final AbandonReason card) {

View file

@ -3,6 +3,7 @@ package mage.cards.a;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ReplacementEffectImpl;
@ -25,13 +26,17 @@ import mage.watchers.Watcher;
*/
public final class AbandonedSarcophagus extends CardImpl {
private static final FilterCard filter = new FilterCard("nonland cards with cycling");
static {
filter.add(Predicates.not(CardType.LAND.getPredicate()));
filter.add(new AbilityPredicate(CyclingAbility.class));
}
public AbandonedSarcophagus(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
// You may cast nonland cards with cycling from your graveyard.
FilterCard filter = new FilterCard("nonland cards with cycling");
filter.add(Predicates.not(CardType.LAND.getPredicate()));
filter.add(new AbilityPredicate(CyclingAbility.class));
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new PlayFromNotOwnHandZoneAllEffect(filter,
Zone.GRAVEYARD, true, TargetController.YOU, Duration.WhileOnBattlefield)
@ -77,16 +82,20 @@ class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl {
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
if (controller == null) {
return false;
}
Permanent permanent = game.getPermanent(event.getTargetId());
if (permanent != null) {
return controller.moveCards(permanent, Zone.EXILED, source, game);
}
Card card = game.getCard(event.getTargetId());
if (card != null) {
return controller.moveCards(card, Zone.EXILED, source, game);
}
}
return false;
}
@ -97,32 +106,46 @@ class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl {
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
boolean cardWasCycledThisTurn = false;
boolean cardHasCycling = false;
if (!(((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD)) {
return false;
}
Player controller = game.getPlayer(source.getControllerId());
AbandonedSarcophagusWatcher watcher = game.getState().getWatcher(AbandonedSarcophagusWatcher.class);
Card card = game.getCard(event.getTargetId());
if (card == null
|| controller == null
|| watcher == null
|| !card.isOwnedBy(controller.getId())) {
if (controller == null) {
return false;
}
Card card = game.getCard(event.getTargetId());
if (card == null) {
return false;
}
if (!card.isOwnedBy(controller.getId())) {
return false;
}
AbandonedSarcophagusWatcher watcher = game.getState().getWatcher(AbandonedSarcophagusWatcher.class);
if (watcher == null) {
return false;
}
boolean cardHasCycling = false;
for (Ability ability : card.getAbilities(game)) {
if (ability instanceof CyclingAbility) {
cardHasCycling = true;
break;
}
}
Cards cards = watcher.getCardsCycledThisTurn(controller.getId());
for (Card c : cards.getCards(game)) {
if (c == card) {
boolean cardWasCycledThisTurn = false;
for (Card cardCycledThisTurn : cards.getCards(game)) {
if (cardCycledThisTurn == card) {
cardWasCycledThisTurn = true;
watcher.getCardsCycledThisTurn(controller.getId()).remove(card); //remove reference to the card as it is no longer needed
}
}
return !cardWasCycledThisTurn && cardHasCycling;
}
}
@ -137,18 +160,27 @@ class AbandonedSarcophagusWatcher extends Watcher {
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() == GameEvent.EventType.CYCLE_CARD) {
if (event.getType() != GameEvent.EventType.CYCLE_CARD) {
return;
}
Card card = game.getCard(event.getSourceId());
if (card == null) {
return;
}
Player controller = game.getPlayer(event.getPlayerId());
if (card != null
&& controller != null
&& card.isOwnedBy(controller.getId())) {
if (controller == null) {
return;
}
if (!card.isOwnedBy(controller.getId())) {
return;
}
Cards c = getCardsCycledThisTurn(event.getPlayerId());
c.add(card);
cycledCardsThisTurn.put(event.getPlayerId(), c);
}
}
}
public Cards getCardsCycledThisTurn(UUID playerId) {
return cycledCardsThisTurn.getOrDefault(playerId, new CardsImpl());

View file

@ -68,7 +68,7 @@ class AbeyanceEffect extends ContinuousRuleModifyingEffectImpl {
@Override
public String getInfoMessage(Ability source, GameEvent event, Game game) {
MageObject mageObject = game.getObject(source.getSourceId());
MageObject mageObject = game.getObject(source);
if (mageObject != null) {
return "You can't cast instant or sorcery spells or activate abilities "
+ "that aren't mana abilities this turn (" + mageObject.getIdName() + ").";

View file

@ -14,7 +14,7 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.filter.StaticFilters;
import mage.game.permanent.token.TokenImpl;
import mage.game.permanent.token.HarpyToken;
import java.util.UUID;
@ -34,7 +34,7 @@ public final class AbhorrentOverlord extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When Abhorrent Overlord enters the battlefield, create a number of 1/1 black Harpy creature tokens with flying equal to your devotion to black.
Effect effect = new CreateTokenEffect(new AbhorrentOverlordHarpyToken(), DevotionCount.B);
Effect effect = new CreateTokenEffect(new HarpyToken(), DevotionCount.B);
effect.setText("create a number of 1/1 black Harpy creature tokens with flying equal to your devotion to black. <i>(Each {B} in the mana costs of permanents you control counts toward your devotion to black.)</i>");
this.addAbility(new EntersBattlefieldTriggeredAbility(effect).addHint(DevotionCount.B.getHint()));
@ -51,25 +51,3 @@ public final class AbhorrentOverlord extends CardImpl {
return new AbhorrentOverlord(this);
}
}
class AbhorrentOverlordHarpyToken extends TokenImpl {
AbhorrentOverlordHarpyToken() {
super("Harpy", "1/1 black Harpy creature tokens with flying");
cardType.add(CardType.CREATURE);
color.setBlack(true);
subtype.add(SubType.HARPY);
power = new MageInt(1);
toughness = new MageInt(1);
this.addAbility(FlyingAbility.getInstance());
}
private AbhorrentOverlordHarpyToken(final AbhorrentOverlordHarpyToken token) {
super(token);
}
public AbhorrentOverlordHarpyToken copy() {
return new AbhorrentOverlordHarpyToken(this);
}
}

View file

@ -35,7 +35,7 @@ public final class AbominationOfGudul extends CardImpl {
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(effect, true));
// Morph 2BGU
this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{B}{G}{U}")));
this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{B}{G}{U}")));
}
private AbominationOfGudul(final AbominationOfGudul card) {

View file

@ -25,8 +25,7 @@ public final class Abrade extends CardImpl {
getSpellAbility().addTarget(new TargetCreaturePermanent());
// Destroy target artifact.
Mode mode = new Mode();
mode.addEffect(new DestroyTargetEffect());
Mode mode = new Mode(new DestroyTargetEffect());
mode.addTarget(new TargetArtifactPermanent());
this.getSpellAbility().addMode(mode);
}

View file

@ -1,7 +1,5 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.DiesSourceTriggeredAbility;
import mage.abilities.effects.common.DestroyAllEffect;
@ -9,27 +7,30 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.permanent.BlockedByIdPredicate;
import mage.filter.predicate.permanent.BlockingAttackerIdPredicate;
import mage.filter.predicate.permanent.BlockingOrBlockedBySourcePredicate;
import java.util.UUID;
/**
*
* @author MarcoMarin
*/
public final class AbuJafar extends CardImpl {
private static final FilterPermanent filter
= new FilterCreaturePermanent("creatures blocking or blocked by it");
static {
filter.add(BlockingOrBlockedBySourcePredicate.EITHER);
}
public AbuJafar(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}");
this.subtype.add(SubType.HUMAN);
this.power = new MageInt(0);
this.toughness = new MageInt(1);
FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures blocking or blocked by it");
filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()),
new BlockingAttackerIdPredicate(this.getId())));
// When Abu Ja'far dies, destroy all creatures blocking or blocked by it. They can't be regenerated.
this.addAbility(new DiesSourceTriggeredAbility(new DestroyAllEffect(filter, true), false));
}

View file

@ -28,8 +28,7 @@ public final class AbunasChant extends CardImpl {
//You gain 5 life;
this.getSpellAbility().addEffect(new GainLifeEffect(5));
//or prevent the next 5 damage that would be dealt to target creature this turn.
Mode mode = new Mode();
mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 5));
Mode mode = new Mode(new PreventDamageToTargetEffect(Duration.EndOfTurn, 5));
mode.addTarget(new TargetCreaturePermanent());
this.getSpellAbility().getModes().addMode(mode);
// Entwine {2}

View file

@ -64,7 +64,7 @@ class AbundanceReplacementEffect extends ReplacementEffectImpl {
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(event.getPlayerId());
MageObject sourceObject = game.getObject(source.getSourceId());
MageObject sourceObject = game.getObject(source);
if (controller != null && sourceObject != null) {
FilterCard filter = new FilterCard();
if (controller.chooseUse(Outcome.Detriment, "Choose card type:",
@ -79,7 +79,7 @@ class AbundanceReplacementEffect extends ReplacementEffectImpl {
Card selectedCard = null;
for (Card card : controller.getLibrary().getCards(game)) {
toReveal.add(card);
if (filter.match(card, source.getSourceId(), source.getControllerId(), game)) {
if (filter.match(card, source.getControllerId(), source, game)) {
selectedCard = card;
break;
}

View file

@ -38,14 +38,12 @@ public final class AbzanCharm extends CardImpl {
this.getSpellAbility().addEffect(new ExileTargetEffect());
// *You draw two cards and you lose 2 life
Mode mode = new Mode();
mode.addEffect(new DrawCardSourceControllerEffect(2));
Mode mode = new Mode(new DrawCardSourceControllerEffect(2));
mode.addEffect(new LoseLifeSourceControllerEffect(2));
this.getSpellAbility().addMode(mode);
// *Distribute two +1/+1 counters among one or two target creatures.
mode = new Mode();
mode.addEffect(new DistributeCountersEffect(CounterType.P1P1, 2, false, "one or two target creatures"));
mode = new Mode(new DistributeCountersEffect(CounterType.P1P1, 2, false, "one or two target creatures"));
mode.addTarget(new TargetCreaturePermanentAmount(2));
this.getSpellAbility().addMode(mode);

View file

@ -28,7 +28,7 @@ public final class AbzanGuide extends CardImpl {
// Lifelink
this.addAbility(LifelinkAbility.getInstance());
// Morph {2}{W}{B}{G}
this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{W}{B}{G}")));
this.addAbility(new MorphAbility(new ManaCostsImpl("{2}{W}{B}{G}")));
}
private AbzanGuide(final AbzanGuide card) {

View file

@ -37,8 +37,7 @@ public final class AcademicProbation extends CardImpl {
this.getSpellAbility().addEffect(new OpponentsCantCastChosenUntilNextTurnEffect().setText("opponents can't cast spells with the chosen name until your next turn"));
// Choose target nonland permanent. Until your next turn, it can't attack or block, and its activated abilities can't be activated.
Mode restrictMode = new Mode();
restrictMode.addEffect(new AcademicProbationRestrictionEffect());
Mode restrictMode = new Mode(new AcademicProbationRestrictionEffect());
restrictMode.addTarget(new TargetNonlandPermanent());
this.getSpellAbility().addMode(restrictMode);
}

View file

@ -73,7 +73,7 @@ class AcademyResearchersEffect extends OneShotEffect {
if (controller != null && academyResearchers != null) {
filterCardInHand.add(new AuraCardCanAttachToPermanentId(academyResearchers.getId()));
TargetCardInHand target = new TargetCardInHand(0, 1, filterCardInHand);
if (controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) {
if (controller.choose(Outcome.PutCardInPlay, target, source, game)) {
Card auraInHand = game.getCard(target.getFirstTarget());
if (auraInHand != null) {
game.getState().setValue("attachTo:" + auraInHand.getId(), academyResearchers);

View file

@ -1,7 +1,5 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
@ -13,11 +11,12 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.common.FilterArtifactCard;
import mage.filter.StaticFilters;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/**
*
* @author Plopman
*/
public final class AcademyRuins extends CardImpl {
@ -31,7 +30,7 @@ public final class AcademyRuins extends CardImpl {
// {1}{U}, {T}: Put target artifact card from your graveyard on top of your library.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOnLibraryTargetEffect(true), new ManaCostsImpl("{1}{U}"));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard")));
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_ARTIFACT_FROM_YOUR_GRAVEYARD));
this.addAbility(ability);
}

View file

@ -0,0 +1,65 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.permanent.token.ThopterColorlessToken;
import mage.game.stack.StackObject;
import mage.target.TargetSpell;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AccessDenied extends CardImpl {
public AccessDenied(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}{U}");
// Counter target spell. Create X 1/1 colorless Thopter artifact creature tokens with flying, where X is that spell's mana value.
this.getSpellAbility().addEffect(new AccessDeniedEffect());
this.getSpellAbility().addTarget(new TargetSpell());
}
private AccessDenied(final AccessDenied card) {
super(card);
}
@Override
public AccessDenied copy() {
return new AccessDenied(this);
}
}
class AccessDeniedEffect extends OneShotEffect {
AccessDeniedEffect() {
super(Outcome.Benefit);
staticText = "counter target spell. Create X 1/1 colorless Thopter " +
"artifact creature tokens with flying, where X is that spell's mana value";
}
private AccessDeniedEffect(final AccessDeniedEffect effect) {
super(effect);
}
@Override
public AccessDeniedEffect copy() {
return new AccessDeniedEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
StackObject stackObject = game.getStack().getStackObject(targetPointer.getFirst(game, source));
if (stackObject != null) {
game.getStack().counter(source.getFirstTarget(), source, game);
return new ThopterColorlessToken().putOntoBattlefield(stackObject.getManaValue(), game, source);
}
return false;
}
}

View file

@ -5,14 +5,13 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
@ -56,9 +55,8 @@ public final class AcclaimedContender extends CardImpl {
// When Acclaimed Contender enters the battlefield, if you control another Knight, look at the top five cards of your library. You may reveal a Knight, Aura, Equipment, or legendary artifact card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.
this.addAbility(new ConditionalInterveningIfTriggeredAbility(
new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect(
StaticValue.get(5), false, StaticValue.get(1), filter2, Zone.LIBRARY, false,
true, false, Zone.HAND, true, false, false
).setBackInRandomOrder(true)), condition, "When {this} enters the battlefield, " +
5, 1, filter2, PutCards.HAND, PutCards.BOTTOM_RANDOM
)), condition, "When {this} enters the battlefield, " +
"if you control another Knight, look at the top five cards of your library. " +
"You may reveal a Knight, Aura, Equipment, or legendary artifact card from among them " +
"and put it into your hand. Put the rest on the bottom of your library in a random order."

View file

@ -84,8 +84,7 @@ class AccursedWitchReturnTransformedEffect extends OneShotEffect {
}
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE);
UUID secondFaceId = card.getSecondCardFace().getId();
game.getState().setValue("attachTo:" + secondFaceId, attachTo.getId());
game.getState().setValue("attachTo:" + source.getSourceId(), attachTo.getId());
if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) {
attachTo.addAttachment(card.getId(), source, game);
}

View file

@ -103,7 +103,7 @@ class AcererakTheArchlichEffect extends OneShotEffect {
}
TargetPermanent target = new TargetControlledCreaturePermanent(0, 1);
target.setNotTarget(true);
player.choose(Outcome.Sacrifice, target, source.getSourceId(), game);
player.choose(Outcome.Sacrifice, target, source, game);
Permanent permanent = game.getPermanent(target.getFirstTarget());
if (permanent != null && permanent.sacrifice(source, game)) {
tokens--;

View file

@ -78,7 +78,7 @@ class AchHansRunEffect extends OneShotEffect {
if (!controller.searchLibrary(target, source, game)) {
return false;
}
Card card = controller.getLibrary().remove(target.getFirstTarget(), game);
Card card = controller.getLibrary().getCard(target.getFirstTarget(), game);
if (card == null || !controller.moveCards(card, Zone.BATTLEFIELD, source, game)) {
return false;
}

View file

@ -43,7 +43,7 @@ public final class AcidSpewerDragon extends CardImpl {
this.addAbility(DeathtouchAbility.getInstance());
// Megamorph {5}{B}{B}
this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{B}{B}"), true));
this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{B}{B}"), true));
// When Acid-Spewer Dragon is turned face up, put a +1/+1 counter on each other Dragon creature you control.
this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), false, false));

View file

@ -38,7 +38,7 @@ public final class AcidicSliver extends CardImpl {
ability.addTarget(new TargetAnyTarget());
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD,
new GainAbilityAllEffect(ability,
Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE_SLIVERS,
Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_ALL_SLIVERS,
"All Slivers have \"{2}, Sacrifice this permanent: This permanent deals 2 damage to any target.\"")));
}

View file

@ -50,7 +50,7 @@ class AcidicSoilEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
List<Permanent> permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source.getSourceId(), game);
List<Permanent> permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, source.getControllerId(), source, game);
for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) {
Player player = game.getPlayer(playerId);
if (player != null) {

View file

@ -73,7 +73,7 @@ class AcolyteOfAfflictionEffect extends OneShotEffect {
}
player.moveCards(player.getLibrary().getTopCards(game, 2), Zone.GRAVEYARD, source, game);
TargetCard target = new TargetCardInYourGraveyard(0, 1, filter, true);
if (!player.choose(Outcome.ReturnToHand, target, source.getSourceId(), game)) {
if (!player.choose(Outcome.ReturnToHand, target, source, game)) {
return true;
}
Card card = game.getCard(target.getFirstTarget());

View file

@ -80,6 +80,6 @@ class AcquisitionOctopusTriggeredAbility extends TriggeredAbilityImpl {
@Override
public String getRule() {
return "When {this} or equipped creature deals combat damage to a player, draw a card.";
return "Whenever {this} or equipped creature deals combat damage to a player, draw a card.";
}
}

View file

@ -22,10 +22,10 @@ public final class AcrobaticManeuver extends CardImpl {
// Exile target creature you control, then return that card to the battlefield under its owner's control.
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent());
this.getSpellAbility().addEffect(new ExileTargetForSourceEffect());
this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false));
this.getSpellAbility().addEffect(new ReturnToBattlefieldUnderOwnerControlTargetEffect(false, false).concatBy(","));
// Draw a card.
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1));
this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("<br>"));
}
private AcrobaticManeuver(final AcrobaticManeuver card) {

View file

@ -54,7 +54,7 @@ class ActOfAuthorityEffect extends OneShotEffect {
this.staticText = "you may exile target artifact or enchantment. If you do, its controller gains control of {this}";
}
public ActOfAuthorityEffect(final ActOfAuthorityEffect effect) {
private ActOfAuthorityEffect(final ActOfAuthorityEffect effect) {
super(effect);
}
@ -66,29 +66,32 @@ class ActOfAuthorityEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (targetPermanent != null && new ExileTargetEffect().apply(game, source)) {
if (targetPermanent == null) { return false; }
ExileTargetEffect exileTargetEffect = new ExileTargetEffect();
if (!exileTargetEffect.apply(game, source)) { return false; }
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
if (sourcePermanent != null) {
if (sourcePermanent == null) { return true; }
ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId());
effect.setTargetPointer(new FixedTarget(sourcePermanent, game));
game.addEffect(effect, source);
}
return true;
}
return false;
}
}
// TODO: These and it's duplicates can probably be replaced by a gain control of effect
class ActOfAuthorityGainControlEffect extends ContinuousEffectImpl {
UUID controller;
private final UUID controller;
public ActOfAuthorityGainControlEffect(Duration duration, UUID controller) {
super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl);
this.controller = controller;
}
public ActOfAuthorityGainControlEffect(final ActOfAuthorityGainControlEffect effect) {
private ActOfAuthorityGainControlEffect(final ActOfAuthorityGainControlEffect effect) {
super(effect);
this.controller = effect.controller;
}
@ -100,15 +103,17 @@ class ActOfAuthorityGainControlEffect extends ContinuousEffectImpl {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (targetPointer != null) {
Permanent permanent;
if (targetPointer == null) {
permanent = game.getPermanent(source.getFirstTarget());
} else {
permanent = game.getPermanent(targetPointer.getFirst(game, source));
}
if (permanent != null) {
if (permanent == null) { return false; }
return permanent.changeControllerId(controller, game, source);
}
return false;
}
@Override
public String getText(Mode mode) {

View file

@ -36,8 +36,7 @@ public final class ActiveVolcano extends CardImpl {
this.getSpellAbility().addTarget(new TargetPermanent(filterBlue));
// or return target Island to its owner's hand.
Mode mode = new Mode();
mode.addEffect(new ReturnToHandTargetEffect());
Mode mode = new Mode(new ReturnToHandTargetEffect());
mode.addTarget(new TargetPermanent(filterIsland));
this.getSpellAbility().addMode(mode);
}

View file

@ -84,18 +84,17 @@ class AdarkarValkyrieEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source));
if (permanent != null) {
if (permanent == null) { return false; }
DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new MageObjectReference(permanent, game));
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
return false;
}
}
class AdarkarValkyrieDelayedTriggeredAbility extends DelayedTriggeredAbility {
protected MageObjectReference mor;
private final MageObjectReference mor;
public AdarkarValkyrieDelayedTriggeredAbility(MageObjectReference mor) {
super(new ReturnToBattlefieldUnderYourControlTargetEffect(), Duration.EndOfTurn);
@ -119,14 +118,17 @@ class AdarkarValkyrieDelayedTriggeredAbility extends DelayedTriggeredAbility {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
if (((ZoneChangeEvent) event).isDiesEvent()
&& mor.refersTo(((ZoneChangeEvent) event).getTarget(), game)
&& game.getState().getZone(event.getTargetId()) == Zone.GRAVEYARD) { // must be in the graveyard
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
return true;
if (!((ZoneChangeEvent) event).isDiesEvent()) { return false; }
}
return false;
if (!mor.refersTo(((ZoneChangeEvent) event).getTarget(), game)) { return false; }
// TODO: Must it? Why?
// Must be in the graveyard
if (game.getState().getZone(event.getTargetId()) != Zone.GRAVEYARD) { return false; }
getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game));
return true;
}
@Override

View file

@ -91,7 +91,7 @@ class DamagedByPiratesWatcher extends Watcher {
}
public boolean damagedByEnoughPirates(UUID sourceId) {
return damageSourceIds.keySet().contains(sourceId) && damageSourceIds.get(sourceId).size() > 2;
return damageSourceIds.containsKey(sourceId) && damageSourceIds.get(sourceId).size() > 2;
}
@Override

View file

@ -1,24 +1,22 @@
package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/**
*
* @author shieldal
*/
public final class AdunOakenshield extends CardImpl {
@ -33,7 +31,7 @@ public final class AdunOakenshield extends CardImpl {
this.toughness = new MageInt(2);
//{B}{R}{G}, {T}: Return target creature card from your graveyard to your hand.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{B}{R}{G}"));
Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl("{B}{R}{G}"));
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
ability.addCost(new TapSourceCost());
this.addAbility(ability);

View file

@ -1,16 +1,14 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.Mode;
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
@ -22,7 +20,8 @@ public final class AdventureAwaits extends CardImpl {
public AdventureAwaits(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}");
// Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. If you don't put a card into your hand this way, draw a card.
// Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand.
// Put the rest on the bottom of your library in a random order. If you don't put a card into your hand this way, draw a card.
this.getSpellAbility().addEffect(new AdventureAwaitsEffect());
}
@ -36,14 +35,10 @@ public final class AdventureAwaits extends CardImpl {
}
}
class AdventureAwaitsEffect extends OneShotEffect {
class AdventureAwaitsEffect extends LookLibraryAndPickControllerEffect {
AdventureAwaitsEffect() {
super(Outcome.Benefit);
staticText = "Look at the top five cards of your library. " +
"You may reveal a creature card from among them and put it into your hand. " +
"Put the rest on the bottom of your library in a random order. " +
"If you didn't put a card into your hand this way, draw a card.";
super(5, 1, StaticFilters.FILTER_CARD_CREATURE_A, PutCards.HAND, PutCards.BOTTOM_RANDOM);
}
private AdventureAwaitsEffect(final AdventureAwaitsEffect effect) {
@ -56,25 +51,16 @@ class AdventureAwaitsEffect extends OneShotEffect {
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 5));
TargetCard target = new TargetCardInLibrary(0, 1, StaticFilters.FILTER_CARD_CREATURE);
player.choose(outcome, cards, target, game);
Card card = game.getCard(target.getFirstTarget());
if (card != null && player.chooseUse(outcome, "Put " + card.getName() + " into your hand?",
"Otherwise draw a card", "Put into hand", "Draw a card", source, game
)) {
player.moveCards(card, Zone.HAND, source, game);
cards.remove(card);
player.putCardsOnBottomOfLibrary(cards, game, source, false);
} else {
player.putCardsOnBottomOfLibrary(cards, game, source, false);
public boolean actionWithPickedCards(Game game, Ability source, Player player, Cards pickedCards, Cards otherCards) {
super.actionWithPickedCards(game, source, player, pickedCards, otherCards);
if (pickedCards.isEmpty()) {
player.drawCards(1, source, game);
}
return true;
}
@Override
public String getText(Mode mode) {
return super.getText(mode).concat(". If you didn't put a card into your hand this way, draw a card");
}
}

View file

@ -1,14 +1,12 @@
package mage.cards.a;
import java.util.UUID;
import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.filter.FilterCard;
import mage.filter.predicate.Predicates;
import mage.filter.StaticFilters;
/**
*
@ -16,18 +14,14 @@ import mage.filter.predicate.Predicates;
*/
public final class AdventurousImpulse extends CardImpl {
private static final FilterCard filter = new FilterCard("a creature or land card");
static {
filter.add(Predicates.or(CardType.CREATURE.getPredicate(), CardType.LAND.getPredicate()));
}
public AdventurousImpulse(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{G}");
//Look at the top three cards of your library. You may reveal a creature or land card from among them and put it into your hand. Put the rest on the bottom of your library in any order.
this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(StaticValue.get(3), false, StaticValue.get(1), filter, false));
// Look at the top three cards of your library.
// You may reveal a creature or land card from among them and put it into your hand.
// Put the rest on the bottom of your library in any order.
this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(
3, 1, StaticFilters.FILTER_CARD_CREATURE_OR_LAND, PutCards.HAND, PutCards.BOTTOM_ANY));
}
private AdventurousImpulse(final AdventurousImpulse card) {

View file

@ -1,37 +1,36 @@
package mage.cards.a;
import java.util.Objects;
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.condition.Condition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.LookLibraryAndPickControllerEffect;
import mage.abilities.effects.common.LookLibraryControllerEffect.PutCards;
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.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.ControllerIdPredicate;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.TargetCard;
/**
*
* @author jeffwadsworth
* @author awjackson
*/
public final class AdviceFromTheFae extends CardImpl {
public AdviceFromTheFae(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2/U}{2/U}{2/U}");
// <i>({2U} can be paid with any two mana or with {U}. This card's converted mana cost is 6.)</i>
// Look at the top five cards of your library. If you control more creatures than each other player, put two of those cards into your hand. Otherwise, put one of them into your hand. Then put the rest on the bottom of your library in any order.
this.getSpellAbility().addEffect(new AdviceFromTheFaeEffect());
// Look at the top five cards of your library. If you control more creatures than each other player,
// put two of those cards into your hand. Otherwise, put one of them into your hand.
// Then put the rest on the bottom of your library in any order.
this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new LookLibraryAndPickControllerEffect(5, 2, PutCards.HAND, PutCards.BOTTOM_ANY),
new LookLibraryAndPickControllerEffect(5, 1, PutCards.HAND, PutCards.BOTTOM_ANY),
AdviceFromTheFaeCondition.instance, "Look at the top five cards of your library. " +
"If you control more creatures than each other player, put two of those cards into your hand. " +
"Otherwise, put one of them into your hand. Then put the rest on the bottom of your library in any order."
));
}
private AdviceFromTheFae(final AdviceFromTheFae card) {
@ -44,52 +43,23 @@ public final class AdviceFromTheFae extends CardImpl {
}
}
class AdviceFromTheFaeEffect extends OneShotEffect {
public AdviceFromTheFaeEffect() {
super(Outcome.DrawCard);
this.staticText = "Look at the top five cards of your library. If you control more creatures than each other player, put two of those cards into your hand. Otherwise, put one of them into your hand. Then put the rest on the bottom of your library in any order";
}
public AdviceFromTheFaeEffect(final AdviceFromTheFaeEffect effect) {
super(effect);
}
@Override
public AdviceFromTheFaeEffect copy() {
return new AdviceFromTheFaeEffect(this);
}
enum AdviceFromTheFaeCondition implements Condition {
instance;
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject mageObject = game.getObject(source.getSourceId());
if (controller != null && mageObject != null) {
Set<Card> topCards = controller.getLibrary().getTopCards(game, 5);
Cards cardsFromLibrary = new CardsImpl();
for (Card card : topCards) {
cardsFromLibrary.add(card);
}
controller.lookAtCards(mageObject.getIdName(), cardsFromLibrary, game);
int max = 0;
for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) {
FilterCreaturePermanent filter = new FilterCreaturePermanent();
filter.add(new ControllerIdPredicate(playerId));
if (!Objects.equals(playerId, controller.getId())) {
if (max < game.getBattlefield().countAll(filter, playerId, game)) {
max = game.getBattlefield().countAll(filter, playerId, game);
UUID controllerId = source.getControllerId();
for (UUID playerId : game.getState().getPlayersInRange(controllerId, game)) {
if (!playerId.equals(controllerId)) {
max = Math.max(max, game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game));
}
}
return game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, controllerId, game) > max;
}
boolean moreCreatures = game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), controller.getId(), game) > max;
TargetCard target = new TargetCard(moreCreatures ? 2 : 1, Zone.LIBRARY, new FilterCard());
if (controller.choose(Outcome.DrawCard, cardsFromLibrary, target, game)) {
cardsFromLibrary.removeAll(target.getTargets());
controller.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game);
}
controller.putCardsOnBottomOfLibrary(cardsFromLibrary, game, source, true);
return true;
}
return false;
@Override
public String toString() {
return "you control more creatures than each other player";
}
}

View file

@ -24,7 +24,7 @@ import mage.target.TargetPermanent;
*/
public final class AerialModification extends CardImpl {
private static final FilterPermanent filter = new FilterPermanent("creature or vehicle");
private static final FilterPermanent filter = new FilterPermanent("creature or Vehicle");
static {
filter.add(Predicates.or(CardType.CREATURE.getPredicate(),

View file

@ -0,0 +1,115 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.common.LandsYouControlHint;
import mage.abilities.keyword.CrewAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicLandCard;
import mage.filter.common.FilterLandPermanent;
import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate;
import mage.game.Controllable;
import mage.game.Game;
import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author TheElk801
*/
public final class AerialSurveyor extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard(SubType.PLAINS);
public AerialSurveyor(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}");
this.subtype.add(SubType.VEHICLE);
this.power = new MageInt(3);
this.toughness = new MageInt(4);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Whenever Aerial Surveyor attacks, if defending player controls more lands than you, search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle.
this.addAbility(new ConditionalInterveningIfTriggeredAbility(
new AttacksTriggeredAbility(
new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true)
), AerialSurveyorCondition.instance, "Whenever {this} attacks, if defending player " +
"controls more lands than you, search your library for a basic Plains card, " +
"put it onto the battlefield tapped, then shuffle."
).addHint(LandsYouControlHint.instance).addHint(AerialSurveyorHint.instance));
// Crew 2
this.addAbility(new CrewAbility(2));
}
private AerialSurveyor(final AerialSurveyor card) {
super(card);
}
@Override
public AerialSurveyor copy() {
return new AerialSurveyor(this);
}
}
enum AerialSurveyorCondition implements Condition {
instance;
private static final FilterPermanent filter = new FilterLandPermanent();
static {
filter.add(DefendingPlayerControlsPredicate.instance);
}
@Override
public boolean apply(Game game, Ability source) {
return game.getBattlefield().count(
filter, source.getControllerId(), source, game
) > game.getBattlefield().count(
StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND,
source.getControllerId(), source, game
);
}
}
enum AerialSurveyorHint implements Hint {
instance;
@Override
public String getText(Game game, Ability ability) {
return game.getBattlefield()
.getActivePermanents(
StaticFilters.FILTER_LAND,
ability.getControllerId(),
ability, game
).stream()
.map(Controllable::getControllerId)
.filter(game.getOpponents(ability.getControllerId())::contains)
.collect(Collectors.toMap(Function.identity(), u -> 1, Integer::sum))
.entrySet()
.stream()
.filter(entry -> game.getPlayer(entry.getKey()) != null)
.map(entry -> "Lands " + game.getPlayer(entry.getKey()).getName() + " controls: " + entry.getValue())
.collect(Collectors.joining("<br>"));
}
@Override
public AerialSurveyorHint copy() {
return instance;
}
}

View file

@ -28,7 +28,7 @@ public final class AerieBowmasters extends CardImpl {
this.addAbility(ReachAbility.getInstance());
// Megamorph {5}{G} <i>(You may cast this card face down as a 2/2 creature for {3}. Turn it face up at any time for its megamorph cost and put a +1/+1 counter on it.)</i>)
this.addAbility(new MorphAbility(this, new ManaCostsImpl("{5}{G}"), true));
this.addAbility(new MorphAbility(new ManaCostsImpl("{5}{G}"), true));
}

View file

@ -36,8 +36,7 @@ public final class AetherChaser extends CardImpl {
this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2)));
// Whenever Aether Chaser attacks, you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token.
this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)), false,
"Whenever {this} attacks you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token."));
this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2))));
}
private AetherChaser(final AetherChaser card) {

View file

@ -37,7 +37,7 @@ public final class AetherFigment extends CardImpl {
Ability ability = new EntersBattlefieldAbility(
new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)),
KickedCondition.instance,
"If {this} was kicked, it enters the battlefield with two +1/+1 counters on it",
"If {this} was kicked, it enters the battlefield with two +1/+1 counters on it.",
"");
this.addAbility(ability);
}

View file

@ -1,19 +1,15 @@
package mage.cards.a;
import mage.MageObject;
import mage.ObjectColor;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.PutOnLibraryTargetEffect;
import mage.abilities.effects.common.PutOnTopOrBottomLibraryTargetEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.filter.common.FilterSpellOrPermanent;
import mage.filter.predicate.Predicate;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetSpellOrPermanent;
import java.util.UUID;
@ -25,7 +21,7 @@ public final class AetherGust extends CardImpl {
private static final FilterSpellOrPermanent filter
= new FilterSpellOrPermanent("spell or permanent that's red or green");
private static final Predicate predicate = Predicates.or(
private static final Predicate<MageObject> predicate = Predicates.or(
new ColorPredicate(ObjectColor.RED),
new ColorPredicate(ObjectColor.GREEN)
);
@ -39,8 +35,11 @@ public final class AetherGust extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}");
// Choose target spell or permanent that's red or green. Its owner puts it on the top or bottom of their library.
this.getSpellAbility().addEffect(new AetherGustEffect());
this.getSpellAbility().addTarget(new TargetSpellOrPermanent(1, 1, filter, false));
this.getSpellAbility().addEffect(new PutOnTopOrBottomLibraryTargetEffect(
"choose target spell or permanent that's red or green. " +
"Its owner puts it on the top or bottom of their library"
));
this.getSpellAbility().addTarget(new TargetSpellOrPermanent(filter));
}
private AetherGust(final AetherGust card) {
@ -52,34 +51,3 @@ public final class AetherGust extends CardImpl {
return new AetherGust(this);
}
}
class AetherGustEffect extends OneShotEffect {
AetherGustEffect() {
super(Outcome.Removal);
staticText = "Choose target spell or permanent that's red or green. " +
"Its owner puts it on the top or bottom of their library.";
}
private AetherGustEffect(final AetherGustEffect effect) {
super(effect);
}
@Override
public AetherGustEffect copy() {
return new AetherGustEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(game.getOwnerId(source.getFirstTarget()));
if (player == null) {
return false;
}
if (player.chooseUse(Outcome.Detriment, "Put the targeted object on the top or bottom of your library?",
"", "Top", "Bottom", source, game)) {
return new PutOnLibraryTargetEffect(true).apply(game, source);
}
return new PutOnLibraryTargetEffect(false).apply(game, source);
}
}

View file

@ -34,8 +34,7 @@ public final class AetherHerder extends CardImpl {
this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2)));
// Whenever Aether Herder attacks, you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token.
this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)), false,
"Whenever {this} attacks you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token."));
this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2))));
}
private AetherHerder(final AetherHerder card) {

View file

@ -36,8 +36,7 @@ public final class AetherInspector extends CardImpl {
this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2)));
// Whenever Aether Inspector attacks, you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token.
this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)), false,
"Whenever {this} attacks you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token."));
this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2))));
}
private AetherInspector(final AetherInspector card) {

View file

@ -3,9 +3,8 @@ package mage.cards.a;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.BlocksSourceTriggeredAbility;
import mage.abilities.common.BlocksCreatureTriggeredAbility;
import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.ReturnToHandTargetEffect;
import mage.abilities.keyword.DefenderAbility;
@ -34,9 +33,11 @@ public final class AetherMembrane extends CardImpl {
this.addAbility(ReachAbility.getInstance());
// Whenever Aether Membrane blocks a creature, return that creature to its owner's hand at end of combat.
Effect effect = new ReturnToHandTargetEffect();
effect.setText("return that creature to its owner's hand at end of combat");
this.addAbility(new BlocksSourceTriggeredAbility(new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(effect)), false, true));
this.addAbility(new BlocksCreatureTriggeredAbility(
new CreateDelayedTriggeredAbilityEffect(
new AtTheEndOfCombatDelayedTriggeredAbility(new ReturnToHandTargetEffect())
).setText("return that creature to its owner's hand at end of combat")
));
}
private AetherMembrane(final AetherMembrane card) {

View file

@ -31,8 +31,7 @@ public final class AetherShockwave extends CardImpl {
// Choose one - Tap all Spirits; or tap all non-Spirit creatures.
this.getSpellAbility().addEffect(new TapAllEffect(filterSpirit));
Mode mode = new Mode();
mode.addEffect(new TapAllEffect(filterNonSpirit));
Mode mode = new Mode(new TapAllEffect(filterNonSpirit));
this.getSpellAbility().addMode(mode);
}

View file

@ -37,8 +37,7 @@ public final class AetherSwooper extends CardImpl {
this.addAbility(new EntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(2)));
// Whenever Aether Swooper attacks, you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token.
this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2)), false,
"Whenever {this} attacks you may pay {E}{E}. If you do, create a 1/1 colorless Servo artifact creature token."));
this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid(new CreateTokenEffect(new ServoToken()), new PayEnergyCost(2))));
}
private AetherSwooper(final AetherSwooper card) {

View file

@ -90,7 +90,7 @@ class AetherVialEffect extends OneShotEffect {
}
TargetCardInHand target = new TargetCardInHand(filter);
if (controller.choose(this.outcome, target, source.getSourceId(), game)) {
if (controller.choose(this.outcome, target, source, game)) {
Card card = game.getCard(target.getFirstTarget());
if (card != null) {
return controller.moveCards(card, Zone.BATTLEFIELD, source, game);

View file

@ -1,27 +1,25 @@
package mage.cards.a;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.EnchantAbility;
import mage.abilities.keyword.FlashAbility;
import mage.abilities.keyword.ReachAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
import mage.abilities.StaticAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.common.continuous.BoostEnchantedEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
import mage.abilities.keyword.ReachAbility;
import mage.constants.*;
import mage.abilities.keyword.FlashAbility;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCreaturePermanent;
import mage.abilities.Ability;
import mage.abilities.effects.common.AttachEffect;
import mage.target.TargetPermanent;
import mage.abilities.keyword.EnchantAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
/**
*
* @author noahg
*/
public final class AetherWeb extends CardImpl {
@ -38,15 +36,15 @@ public final class AetherWeb extends CardImpl {
TargetPermanent auraTarget = new TargetCreaturePermanent();
this.getSpellAbility().addTarget(auraTarget);
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
Ability ability = new EnchantAbility(auraTarget.getTargetName());
this.addAbility(ability);
this.addAbility(new EnchantAbility(auraTarget.getTargetName()));
// Enchanted creature gets +1/+1, has reach, and can block creatures with shadow as though they didn't have shadow.
StaticAbility staticAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1)
.setText("Enchanted creature gets +1/+1, has reach, and can block creatures with shadow as though they didn't have shadow."));
staticAbility.addEffect(new GainAbilityAttachedEffect(ReachAbility.getInstance(), AttachmentType.AURA).setText(""));
staticAbility.addEffect(new AetherWebEffect());
this.addAbility(staticAbility);
Ability ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 1));
ability.addEffect(new GainAbilityAttachedEffect(
ReachAbility.getInstance(), AttachmentType.AURA
).setText(", has reach"));
ability.addEffect(new AetherWebEffect());
this.addAbility(ability);
}
private AetherWeb(final AetherWeb card) {
@ -63,7 +61,7 @@ class AetherWebEffect extends AsThoughEffectImpl {
public AetherWebEffect() {
super(AsThoughEffectType.BLOCK_SHADOW, Duration.WhileOnBattlefield, Outcome.Benefit);
staticText = "";
staticText = ", and can block creatures with shadow as though they didn't have shadow";
}
public AetherWebEffect(final AetherWebEffect effect) {

View file

@ -78,12 +78,12 @@ class AetherbornMarauderEffect extends OneShotEffect {
filter.add(AnotherPredicate.instance);
filter.add(CounterType.P1P1.getPredicate());
boolean firstRun = true;
while (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) {
while (game.getBattlefield().count(filter, source.getControllerId(), source, game) > 0) {
if (controller.chooseUse(outcome, "Move " + (firstRun ? "any" : "more") + " +1/+1 counters from other permanents you control to " + sourceObject.getLogName() + '?', source, game)) {
firstRun = false;
TargetControlledPermanent target = new TargetControlledPermanent(filter);
target.setNotTarget(true);
if (target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), game)) {
if (target.choose(Outcome.Neutral, source.getControllerId(), source.getSourceId(), source, game)) {
Permanent fromPermanent = game.getPermanent(target.getFirstTarget());
if (fromPermanent != null) {
int numberOfCounters = fromPermanent.getCounters(game).getCount(CounterType.P1P1);

Some files were not shown because too many files have changed in this diff Show more