From b9473367d8bcf4b610a1c61492d88f4f6558110f Mon Sep 17 00:00:00 2001 From: Sloth Date: Fri, 1 Mar 2013 20:44:38 +0000 Subject: [PATCH 01/48] - Removed deprecated targetPlayer variable from SpellAbility. - Cleanup. --- .../cardfactory/CardFactoryArtifacts.java | 8 +- .../forge/card/spellability/SpellAbility.java | 85 ++----------------- .../forge/card/trigger/WrappedAbility.java | 10 --- src/main/java/forge/game/ai/ComputerUtil.java | 13 --- src/main/java/forge/game/zone/MagicStack.java | 9 +- .../game/zone/PlayerZoneBattlefield.java | 24 ------ 6 files changed, 12 insertions(+), 137 deletions(-) diff --git a/src/main/java/forge/card/cardfactory/CardFactoryArtifacts.java b/src/main/java/forge/card/cardfactory/CardFactoryArtifacts.java index 5f846c66748..3851f04a5a1 100644 --- a/src/main/java/forge/card/cardfactory/CardFactoryArtifacts.java +++ b/src/main/java/forge/card/cardfactory/CardFactoryArtifacts.java @@ -11,7 +11,6 @@ import forge.card.spellability.AbilityActivated; import forge.card.spellability.Target; import forge.control.input.Input; import forge.control.input.InputSelectManyCards; -import forge.game.ai.ComputerUtil; import forge.game.player.Player; import forge.game.zone.PlayerZone; import forge.game.zone.Zone; @@ -54,8 +53,10 @@ class CardFactoryArtifacts { @Override public boolean canPlayAI() { this.getTarget().resetTargets(); - final List libList = getActivatingPlayer().getOpponent().getCardsIn(ZoneType.Library); - return !libList.isEmpty() && ComputerUtil.targetHumanAI(this); + Player human = getActivatingPlayer().getOpponent(); + final List libList = human.getCardsIn(ZoneType.Library); + this.getTarget().addTarget(human); + return !libList.isEmpty() && canTarget(human); } @Override @@ -98,6 +99,7 @@ class CardFactoryArtifacts { sb.append("Put the top two cards of target player's library into that player's graveyard. "); sb.append("If both cards share a color, repeat this process."); ab1.setDescription(sb.toString()); + ab1.setStackDescription(sb.toString()); card.addSpellAbility(ab1); } // *************** END ************ END ************************** diff --git a/src/main/java/forge/card/spellability/SpellAbility.java b/src/main/java/forge/card/spellability/SpellAbility.java index 70d586e8991..655fe32f10c 100644 --- a/src/main/java/forge/card/spellability/SpellAbility.java +++ b/src/main/java/forge/card/spellability/SpellAbility.java @@ -51,7 +51,6 @@ public abstract class SpellAbility implements ISpellAbility { // choices for constructor isPermanent argument private String description = ""; - private Player targetPlayer = null; private String stackDescription = ""; private ManaCost manaCost = null; private ManaCost multiKickerManaCost = null; @@ -1111,7 +1110,6 @@ public abstract class SpellAbility implements ISpellAbility { if (tgt != null) { tgt.addTarget(card); } else { - this.targetPlayer = null; // reset setTargetPlayer() this.targetCard = card; } String desc = ""; @@ -1124,74 +1122,6 @@ public abstract class SpellAbility implements ISpellAbility { this.setStackDescription(desc); } -// /** -// *

-// * Getter for the field targetList. -// *

-// * -// * @return a {@link forge.CardList} object. -// */ -// public List getTargetList() { -// return this.targetList; -// } - -// /** -// *

-// * Setter for the field targetList. -// *

-// * -// * @param list -// * a {@link forge.CardList} object. -// */ -// public void setTargetList(final List list) { -// // The line below started to create a null error at -// // forge.CardFactoryUtil.canBeTargetedBy(CardFactoryUtil.java:3329) -// // after ForgeSVN r2699. I hope that commenting out the line below will -// // not result in other bugs. :) -// // targetPlayer = null;//reset setTargetPlayer() -// -// this.targetList = list; -// final StringBuilder sb = new StringBuilder(); -// sb.append(this.getSourceCard().getName()).append(" - targeting "); -// for (int i = 0; i < this.targetList.size(); i++) { -// -// if (!this.targetList.get(i).isFaceDown()) { -// sb.append(this.targetList.get(i)); -// } else { -// sb.append("Morph(").append(this.targetList.get(i).getUniqueNumber()).append(")"); -// } -// -// if (i < (this.targetList.size() - 1)) { -// sb.append(", "); -// } -// } -// this.setStackDescription(sb.toString()); -// } - - /** - *

- * Setter for the field targetPlayer. - *

- * - * @param p - * a {@link forge.game.player.Player} object. - */ - public void setTargetPlayer(final Player p) { - if (p == null) { - throw new RuntimeException("SpellAbility : setTargetPlayer() error, argument is " + p + " source card is " - + this.getSourceCard()); - } - - final Target tgt = this.getTarget(); - if (tgt != null) { - tgt.addTarget(p); - } else { - this.targetCard = null; // reset setTargetCard() - this.targetPlayer = p; - } - this.setStackDescription(this.getSourceCard().getName() + " - targeting " + p); - } - /** *

* Getter for the field targetPlayer. @@ -1200,18 +1130,15 @@ public abstract class SpellAbility implements ISpellAbility { * @return a {@link forge.game.player.Player} object. */ public Player getTargetPlayer() { - if (this.targetPlayer == null) { - final Target tgt = this.getTarget(); - if (tgt != null) { - final ArrayList list = tgt.getTargetPlayers(); + final Target tgt = this.getTarget(); + if (tgt != null) { + final ArrayList list = tgt.getTargetPlayers(); - if (!list.isEmpty()) { - return list.get(0); - } + if (!list.isEmpty()) { + return list.get(0); } - return null; } - return this.targetPlayer; + return null; } /** diff --git a/src/main/java/forge/card/trigger/WrappedAbility.java b/src/main/java/forge/card/trigger/WrappedAbility.java index 35a5f6127bf..cf2b05b8bfa 100644 --- a/src/main/java/forge/card/trigger/WrappedAbility.java +++ b/src/main/java/forge/card/trigger/WrappedAbility.java @@ -340,16 +340,6 @@ public class WrappedAbility extends Ability implements ISpellAbility { sa.setTargetCard(card); } -// @Override -// public void setTargetList(final List list) { -// sa.setTargetList(list); -// } - - @Override - public void setTargetPlayer(final Player p) { - sa.setTargetPlayer(p); - } - @Override public void setType(final String s) { sa.setType(s); diff --git a/src/main/java/forge/game/ai/ComputerUtil.java b/src/main/java/forge/game/ai/ComputerUtil.java index b9227e63be3..ed0074b056a 100644 --- a/src/main/java/forge/game/ai/ComputerUtil.java +++ b/src/main/java/forge/game/ai/ComputerUtil.java @@ -945,19 +945,6 @@ public class ComputerUtil { return false; } - - public static boolean targetHumanAI(final SpellAbility sa) { - if (sa == null || sa.getActivatingPlayer() == null) { - return false; - } - Player human = sa.getActivatingPlayer().getOpponent(); - if (!sa.canTarget(human)) { - return false; - } - sa.setTargetPlayer(human); - return true; - } - // returns true if it's better to wait until blockers are declared /** *

diff --git a/src/main/java/forge/game/zone/MagicStack.java b/src/main/java/forge/game/zone/MagicStack.java index ae0f536a52c..c71aa4108f8 100644 --- a/src/main/java/forge/game/zone/MagicStack.java +++ b/src/main/java/forge/game/zone/MagicStack.java @@ -680,7 +680,7 @@ public class MagicStack extends MyObservable { // Create a new object, since the triggers aren't happening right away runParams = new HashMap(); runParams.put("SourceSA", sp); - if (chosenTargets.size() > 0) { + if (!chosenTargets.isEmpty()) { HashSet distinctObjects = new HashSet(); for (final TargetChoices tc : chosenTargets) { if ((tc != null) && (tc.getTargetCards() != null)) { @@ -704,10 +704,6 @@ public class MagicStack extends MyObservable { else if (sp.getTargetCard() != null) { runParams.put("Target", sp.getTargetCard()); - game.getTriggerHandler().runTrigger(TriggerType.BecomesTarget, runParams, false); - } else if (sp.getTargetPlayer() != null) { - runParams.put("Target", sp.getTargetPlayer()); - game.getTriggerHandler().runTrigger(TriggerType.BecomesTarget, runParams, false); } } @@ -1075,9 +1071,6 @@ public class MagicStack extends MyObservable { else if (sa.getTargetCard() != null) { fizzle = !CardFactoryUtil.isTargetStillValid(sa, sa.getTargetCard()); } - else if (sa.getTargetPlayer() != null) { - fizzle = !sa.getTargetPlayer().canBeTargetedBy(sa); - } else { // Set fizzle to the same as the parent if there's no target info fizzle = parentFizzled; diff --git a/src/main/java/forge/game/zone/PlayerZoneBattlefield.java b/src/main/java/forge/game/zone/PlayerZoneBattlefield.java index dc4108ae337..7c1a36341ba 100644 --- a/src/main/java/forge/game/zone/PlayerZoneBattlefield.java +++ b/src/main/java/forge/game/zone/PlayerZoneBattlefield.java @@ -244,30 +244,6 @@ public class PlayerZoneBattlefield extends PlayerZone { } } - /** - *

- * Setter for the field trigger. - *

- * - * @param b - * a boolean. - */ - public final void setTrigger(final boolean b) { - this.trigger = b; - } - - /** - *

- * Setter for the field leavesTrigger. - *

- * - * @param b - * a boolean. - */ - public final void setLeavesTrigger(final boolean b) { - this.leavesTrigger = b; - } - /** *

* setTriggers. From ec2721e73bc1e12929c0c71ed645b446d3bfd4f1 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Fri, 1 Mar 2013 22:35:58 +0000 Subject: [PATCH 02/48] Remove UI class since most methods are never called, the rest may be moved to classes that use them --- .gitattributes | 1 - .../forge/gui/toolbox/CardFaceSymbols.java | 5 +- .../java/forge/view/arcane/CardPanel.java | 2 +- .../forge/view/arcane/CardPanelContainer.java | 28 +- .../forge/view/arcane/util/Animation.java | 33 +- src/main/java/forge/view/arcane/util/UI.java | 326 ------------------ 6 files changed, 48 insertions(+), 347 deletions(-) delete mode 100644 src/main/java/forge/view/arcane/util/UI.java diff --git a/.gitattributes b/.gitattributes index 5f19988d661..8cdf4fd3192 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14530,7 +14530,6 @@ src/main/java/forge/view/arcane/package-info.java svneol=native#text/plain src/main/java/forge/view/arcane/util/Animation.java svneol=native#text/plain src/main/java/forge/view/arcane/util/CardPanelMouseListener.java svneol=native#text/plain src/main/java/forge/view/arcane/util/GlowText.java svneol=native#text/plain -src/main/java/forge/view/arcane/util/UI.java svneol=native#text/plain src/main/java/forge/view/arcane/util/package-info.java svneol=native#text/plain src/main/java/forge/view/package-info.java svneol=native#text/plain src/main/resources/proxy-template.ftl -text diff --git a/src/main/java/forge/gui/toolbox/CardFaceSymbols.java b/src/main/java/forge/gui/toolbox/CardFaceSymbols.java index fa4ba43a539..a2e05e06e9f 100644 --- a/src/main/java/forge/gui/toolbox/CardFaceSymbols.java +++ b/src/main/java/forge/gui/toolbox/CardFaceSymbols.java @@ -29,7 +29,6 @@ import com.esotericsoftware.minlog.Log; import forge.card.mana.ManaCostShard; import forge.card.mana.ManaCost; -import forge.view.arcane.util.UI; /** *

@@ -167,11 +166,11 @@ public class CardFaceSymbols { * @param w an int * @param h and int */ - public static void draw(final Graphics g, String s, int x, final int y, final int w, final int h) { + public static void drawOther(final Graphics g, String s, int x, final int y, final int w, final int h) { if (s.length() == 0) { return; } - s = UI.getDisplayManaCost(s); + StringTokenizer tok = new StringTokenizer(s, " "); while (tok.hasMoreTokens()) { String symbol = tok.nextToken(); diff --git a/src/main/java/forge/view/arcane/CardPanel.java b/src/main/java/forge/view/arcane/CardPanel.java index 83e6c53fcad..cbbbe3dcb32 100644 --- a/src/main/java/forge/view/arcane/CardPanel.java +++ b/src/main/java/forge/view/arcane/CardPanel.java @@ -415,7 +415,7 @@ public class CardPanel extends JPanel implements CardContainer { if (this.getCard() != null && this.getGameCard().getFoil() > 0) { final String fl = String.format("foil%02d", this.getCard().getFoil()); final int z = Math.round(this.cardWidth * CardPanel.BLACK_BORDER_SIZE); - CardFaceSymbols.draw(g, fl, this.cardXOffset + z, this.cardYOffset + z, this.cardWidth - (2 * z), + CardFaceSymbols.drawOther(g, fl, this.cardXOffset + z, this.cardYOffset + z, this.cardWidth - (2 * z), this.cardHeight - (2 * z)); } } diff --git a/src/main/java/forge/view/arcane/CardPanelContainer.java b/src/main/java/forge/view/arcane/CardPanelContainer.java index f08d46d8c34..340ee24c277 100644 --- a/src/main/java/forge/view/arcane/CardPanelContainer.java +++ b/src/main/java/forge/view/arcane/CardPanelContainer.java @@ -18,10 +18,12 @@ package forge.view.arcane; import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.Rectangle; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionListener; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; @@ -33,7 +35,6 @@ import forge.Card; import forge.Constant; import forge.gui.match.CMatchUI; import forge.view.arcane.util.CardPanelMouseListener; -import forge.view.arcane.util.UI; /** * Manages mouse events and common functionality for CardPanel containing @@ -296,7 +297,7 @@ public abstract class CardPanelContainer extends JPanel { * a {@link forge.view.arcane.CardPanel} object. */ public final void removeCardPanel(final CardPanel fromPanel) { - UI.invokeAndWait(new Runnable() { + CardPanelContainer.invokeAndWait(new Runnable() { @Override public void run() { if (CardPanelContainer.this.getMouseDragPanel() != null) { @@ -321,7 +322,7 @@ public abstract class CardPanelContainer extends JPanel { *

*/ public final void clear() { - UI.invokeAndWait(new Runnable() { + CardPanelContainer.invokeAndWait(new Runnable() { @Override public void run() { CardPanelContainer.this.getCardPanels().clear(); @@ -623,4 +624,25 @@ public abstract class CardPanelContainer extends JPanel { public void setMouseDragPanel(final CardPanel mouseDragPanel0) { this.mouseDragPanel = mouseDragPanel0; } + + /** + *

+ * invokeAndWait. + *

+ * + * @param runnable + * a {@link java.lang.Runnable} object. + */ + public static void invokeAndWait(final Runnable runnable) { + if (EventQueue.isDispatchThread()) { + runnable.run(); + return; + } + try { + EventQueue.invokeAndWait(runnable); + } catch (InterruptedException ex) { + } catch (InvocationTargetException ex) { + throw new RuntimeException(ex); + } + } } diff --git a/src/main/java/forge/view/arcane/util/Animation.java b/src/main/java/forge/view/arcane/util/Animation.java index 933c50f5b46..75a28688315 100644 --- a/src/main/java/forge/view/arcane/util/Animation.java +++ b/src/main/java/forge/view/arcane/util/Animation.java @@ -140,6 +140,18 @@ public abstract class Animation { protected void end() { } + /** + *

+ * invokeLater. + *

+ * + * @param runnable + * a {@link java.lang.Runnable} object. + */ + public static void invokeLater(final Runnable runnable) { + EventQueue.invokeLater(runnable); + } + /** * Uses averaging of the time between the past few frames to provide smooth * animation. @@ -248,7 +260,7 @@ public abstract class Animation { public static void moveCardToPlay(final int startX, final int startY, final int startWidth, final int endX, final int endY, final int endWidth, final CardPanel animationPanel, final CardPanel placeholder, final JLayeredPane layeredPane, final int speed) { - UI.invokeLater(new Runnable() { + Animation.invokeLater(new Runnable() { @Override public void run() { final int startHeight = Math.round(startWidth * CardPanel.ASPECT_RATIO); @@ -343,7 +355,7 @@ public abstract class Animation { public static void moveCard(final int startX, final int startY, final int startWidth, final int endX, final int endY, final int endWidth, final CardPanel animationPanel, final CardPanel placeholder, final JLayeredPane layeredPane, final int speed) { - UI.invokeLater(new Runnable() { + Animation.invokeLater(new Runnable() { @Override public void run() { final int startHeight = Math.round(startWidth * CardPanel.ASPECT_RATIO); @@ -397,19 +409,14 @@ public abstract class Animation { * a {@link forge.view.arcane.CardPanel} object. */ public static void moveCard(final CardPanel placeholder) { - UI.invokeLater(new Runnable() { + Animation.invokeLater(new Runnable() { @Override public void run() { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - if (placeholder != null) { - placeholder.setDisplayEnabled(true); - // placeholder.setImage(imagePanel); - placeholder.setCard(placeholder.getGameCard()); - } - } - }); + if (placeholder != null) { + placeholder.setDisplayEnabled(true); + // placeholder.setImage(imagePanel); + placeholder.setCard(placeholder.getGameCard()); + } } }); } diff --git a/src/main/java/forge/view/arcane/util/UI.java b/src/main/java/forge/view/arcane/util/UI.java deleted file mode 100644 index 83c01378127..00000000000 --- a/src/main/java/forge/view/arcane/util/UI.java +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Forge: Play Magic: the Gathering. - * Copyright (C) 2011 Nate - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package forge.view.arcane.util; - -import java.awt.Component; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.EventQueue; -import java.awt.Font; -import java.awt.Image; -import java.awt.Insets; -import java.awt.Point; -import java.awt.Toolkit; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.util.Collections; -import java.util.concurrent.ConcurrentMap; - -import javax.swing.BorderFactory; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JEditorPane; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JToggleButton; -import javax.swing.JViewport; -import javax.swing.ScrollPaneConstants; -import javax.swing.UIManager; -import javax.swing.ViewportLayout; -import javax.swing.border.Border; -import javax.swing.border.TitledBorder; -import javax.swing.text.Element; -import javax.swing.text.StyleConstants; -import javax.swing.text.View; -import javax.swing.text.ViewFactory; -import javax.swing.text.html.HTML; -import javax.swing.text.html.HTMLEditorKit; -import javax.swing.text.html.ImageView; - -import com.google.common.collect.MapMaker; - -/** - * UI utility functions. - * - * @author Forge - * @version $Id$ - */ -public class UI { - /** Constant imageCache. */ - private static ConcurrentMap imageCache = new MapMaker().softValues().makeMap(); - - /** - *

- * getToggleButton. - *

- * - * @return a {@link javax.swing.JToggleButton} object. - */ - public static JToggleButton getToggleButton() { - JToggleButton button = new JToggleButton(); - button.setMargin(new Insets(2, 4, 2, 4)); - return button; - } - - /** - *

- * getButton. - *

- * - * @return a {@link javax.swing.JButton} object. - */ - public static JButton getButton() { - JButton button = new JButton(); - button.setMargin(new Insets(2, 4, 2, 4)); - return button; - } - - /** - *

- * setTitle. - *

- * - * @param panel - * a {@link javax.swing.JPanel} object. - * @param title - * a {@link java.lang.String} object. - */ - public static void setTitle(final JPanel panel, final String title) { - Border border = panel.getBorder(); - if (border instanceof TitledBorder) { - ((TitledBorder) panel.getBorder()).setTitle(title); - panel.repaint(); - } else { - panel.setBorder(BorderFactory.createTitledBorder(title)); - } - } - - /** - *

- * getFileURL. - *

- * - * @param path - * a {@link java.lang.String} object. - * @return a {@link java.net.URL} object. - */ - public static URL getFileURL(final String path) { - File file = new File(path); - if (file.exists()) { - try { - return file.toURI().toURL(); - } catch (MalformedURLException ignored) { - } - } - return UI.class.getResource(path); - } - - /** - *

- * getImageIcon. - *

- * - * @param path - * a {@link java.lang.String} object. - * @return a {@link javax.swing.ImageIcon} object. - */ - public static ImageIcon getImageIcon(final String path) { - InputStream stream = null; - try { - try { - stream = UI.class.getResourceAsStream(path); - if (stream == null && new File(path).exists()) { - stream = new FileInputStream(path); - } - if (stream == null) { - throw new RuntimeException("Image not found: " + path); - } - byte[] data = new byte[stream.available()]; - stream.read(data); - return new ImageIcon(data); - } finally { - if (stream != null) { - stream.close(); - } - } - } catch (IOException ex) { - throw new RuntimeException("Error reading image: " + path); - } - } - - /** - *

- * setHTMLEditorKit. - *

- * - * @param editorPane - * a {@link javax.swing.JEditorPane} object. - */ - public static void setHTMLEditorKit(final JEditorPane editorPane) { - editorPane.getDocument().putProperty("imageCache", imageCache); // Read - // internally - // by - // ImageView, - // but - // never - // written. - // Extend all this shit to cache images. - editorPane.setEditorKit(new HTMLEditorKit() { - private static final long serialVersionUID = -562969765076450440L; - - @Override - public ViewFactory getViewFactory() { - return new HTMLFactory() { - @Override - public View create(final Element elem) { - Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute); - if (o instanceof HTML.Tag) { - HTML.Tag kind = (HTML.Tag) o; - if (kind == HTML.Tag.IMG) { - return new ImageView(elem) { - @Override - public URL getImageURL() { - URL url = super.getImageURL(); - // Put an image into the cache to be - // read by other ImageView methods. - if (url != null && imageCache.get(url) == null) { - try { - imageCache.put(url.toURI(), Toolkit.getDefaultToolkit() - .createImage(url)); - } catch (URISyntaxException e) { - } - } - return url; - } - }; - } - } - return super.create(elem); - } - }; - } - }); - } - - /** - *

- * setVerticalScrollingView. - *

- * - * @param scrollPane - * a {@link javax.swing.JScrollPane} object. - * @param view - * a {@link java.awt.Component} object. - */ - public static void setVerticalScrollingView(final JScrollPane scrollPane, final Component view) { - final JViewport viewport = new JViewport(); - viewport.setLayout(new ViewportLayout() { - private static final long serialVersionUID = -4436977380450713628L; - - @Override - public void layoutContainer(final Container parent) { - viewport.setViewPosition(new Point(0, 0)); - Dimension viewportSize = viewport.getSize(); - int width = viewportSize.width; - int height = Math.max(view.getPreferredSize().height, viewportSize.height); - viewport.setViewSize(new Dimension(width, height)); - } - }); - viewport.setView(view); - scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); - scrollPane.setViewport(viewport); - } - - /** - *

- * getDisplayManaCost. - *

- * - * @param manaCost - * a {@link java.lang.String} object. - * @return a {@link java.lang.String} object. - */ - public static String getDisplayManaCost(String manaCost) { - manaCost = manaCost.replace("/", ""); - manaCost = manaCost.replace("X 0", "X"); - // A pipe in the cost means - // "process left of the pipe as the card color, but display right of the pipe as the cost". - int pipePosition = manaCost.indexOf("{|}"); - if (pipePosition != -1) { - manaCost = manaCost.substring(pipePosition + 3); - } - return manaCost; - } - - /** - *

- * invokeLater. - *

- * - * @param runnable - * a {@link java.lang.Runnable} object. - */ - public static void invokeLater(final Runnable runnable) { - EventQueue.invokeLater(runnable); - } - - /** - *

- * invokeAndWait. - *

- * - * @param runnable - * a {@link java.lang.Runnable} object. - */ - public static void invokeAndWait(final Runnable runnable) { - if (EventQueue.isDispatchThread()) { - runnable.run(); - return; - } - try { - EventQueue.invokeAndWait(runnable); - } catch (InterruptedException ex) { - } catch (InvocationTargetException ex) { - throw new RuntimeException(ex); - } - } - - /** - *

- * setDefaultFont. - *

- * - * @param font - * a {@link java.awt.Font} object. - */ - public static void setDefaultFont(final Font font) { - for (Object key : Collections.list(UIManager.getDefaults().keys())) { - Object value = UIManager.get(key); - if (value instanceof javax.swing.plaf.FontUIResource) { - UIManager.put(key, font); - } - } - } -} From 84d64ef8ebf63ea701dee7b0e1d4eb1d5ed52acf Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Fri, 1 Mar 2013 22:40:50 +0000 Subject: [PATCH 03/48] IZone - adjusted parameter type or remove method thrown away get/setUpdate methods battlefield.getCards(false) will return R/O list of cards - might lead to exceptions if callers attempt to modify the method's result. --- src/main/java/forge/game/zone/IZone.java | 20 +------------ .../game/zone/PlayerZoneBattlefield.java | 5 ++-- src/main/java/forge/game/zone/Zone.java | 28 +++---------------- 3 files changed, 7 insertions(+), 46 deletions(-) diff --git a/src/main/java/forge/game/zone/IZone.java b/src/main/java/forge/game/zone/IZone.java index efc7ea554dd..4f5252416fd 100644 --- a/src/main/java/forge/game/zone/IZone.java +++ b/src/main/java/forge/game/zone/IZone.java @@ -30,24 +30,6 @@ import forge.Card; * @version $Id$ */ interface IZone { - /** - *

- * setUpdate. - *

- * - * @param b - * a boolean. - */ - void setUpdate(boolean b); - - /** - *

- * getUpdate. - *

- * - * @return a boolean. - */ - boolean getUpdate(); /** *

@@ -101,7 +83,7 @@ interface IZone { * @param o * a {@link java.lang.Object} object. */ - void remove(Object o); + void remove(Card o); /** *

diff --git a/src/main/java/forge/game/zone/PlayerZoneBattlefield.java b/src/main/java/forge/game/zone/PlayerZoneBattlefield.java index 7c1a36341ba..b863a8bd342 100644 --- a/src/main/java/forge/game/zone/PlayerZoneBattlefield.java +++ b/src/main/java/forge/game/zone/PlayerZoneBattlefield.java @@ -17,7 +17,6 @@ */ package forge.game.zone; -import java.util.ArrayList; import java.util.List; import com.google.common.base.Predicate; @@ -181,7 +180,7 @@ public class PlayerZoneBattlefield extends PlayerZone { /** {@inheritDoc} */ @Override - public final void remove(final Object o) { + public final void remove(final Card o) { super.remove(o); @@ -276,7 +275,7 @@ public class PlayerZoneBattlefield extends PlayerZone { // getCards(false) to get Phased Out cards if (!filter) { - return new ArrayList(cardList); + return super.getCards(false); } return Lists.newArrayList(Iterables.filter(cardList, isNotPhased)); diff --git a/src/main/java/forge/game/zone/Zone.java b/src/main/java/forge/game/zone/Zone.java index 6b2c30a0418..1e790beeb98 100644 --- a/src/main/java/forge/game/zone/Zone.java +++ b/src/main/java/forge/game/zone/Zone.java @@ -66,6 +66,8 @@ public class Zone extends MyObservable implements IZone, Observer, java.io.Seria public Zone(final ZoneType zone) { this.zoneName = zone; this.roCardList = Collections.unmodifiableList(cardList); + + //System.out.println(zoneName + " (ct) " + Integer.toHexString(System.identityHashCode(roCardList))); } // ************ BEGIN - these methods fire updateObservers() ************* @@ -191,7 +193,7 @@ public class Zone extends MyObservable implements IZone, Observer, java.io.Seria * an Object */ @Override - public void remove(final Object c) { + public void remove(final Card c) { this.cardList.remove(c); this.update(); } @@ -287,6 +289,7 @@ public class Zone extends MyObservable implements IZone, Observer, java.io.Seria */ @Override public final List getCards() { + //System.out.println(zoneName + ": " + Integer.toHexString(System.identityHashCode(roCardList))); return this.getCards(true); } @@ -322,29 +325,6 @@ public class Zone extends MyObservable implements IZone, Observer, java.io.Seria } } - /** - * Sets the update. - * - * @param b - * a boolean. - */ - @Override - public final void setUpdate(final boolean b) { - this.update = b; - } - - /** - *

- * Getter for the field update. - *

- * - * @return a boolean. - */ - @Override - public final boolean getUpdate() { - return this.update; - } - /** *

* toString. From 200754719089248b222f15e14c87c0180b40a8bc Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Fri, 1 Mar 2013 22:43:12 +0000 Subject: [PATCH 04/48] (minor) wrote a simple javadoc class description, because that TODO has been there for about a year already --- src/main/java/forge/deck/io/DeckSerializer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/forge/deck/io/DeckSerializer.java b/src/main/java/forge/deck/io/DeckSerializer.java index acee3a48715..cf0ea4e49b9 100644 --- a/src/main/java/forge/deck/io/DeckSerializer.java +++ b/src/main/java/forge/deck/io/DeckSerializer.java @@ -46,7 +46,7 @@ import freemarker.template.Template; import freemarker.template.TemplateException; /** - * TODO: Write javadoc for this type. + * This class knows how to make a file out of a deck object and vice versa. * */ public class DeckSerializer extends StorageReaderFolder implements IItemSerializer { From 3c906ae532a427ed93b2a49368f20e5aaa8edd08 Mon Sep 17 00:00:00 2001 From: Sol Date: Fri, 1 Mar 2013 23:41:31 +0000 Subject: [PATCH 05/48] - Adding two Planes Feeding Grounds and Horizon Boughs --- .gitattributes | 2 ++ res/cardsfolder/f/feeding_grounds.txt | 13 +++++++++++++ res/cardsfolder/h/horizon_boughs.txt | 11 +++++++++++ 3 files changed, 26 insertions(+) create mode 100644 res/cardsfolder/f/feeding_grounds.txt create mode 100644 res/cardsfolder/h/horizon_boughs.txt diff --git a/.gitattributes b/.gitattributes index 8cdf4fd3192..31a53af4a04 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3491,6 +3491,7 @@ res/cardsfolder/f/feed_the_pack.txt -text res/cardsfolder/f/feedback.txt svneol=native#text/plain res/cardsfolder/f/feedback_bolt.txt svneol=native#text/plain res/cardsfolder/f/feeding_frenzy.txt svneol=native#text/plain +res/cardsfolder/f/feeding_grounds.txt -text res/cardsfolder/f/feeling_of_dread.txt -text res/cardsfolder/f/feint.txt -text res/cardsfolder/f/feldons_cane.txt svneol=native#text/plain @@ -4946,6 +4947,7 @@ res/cardsfolder/h/hope_charm.txt svneol=native#text/plain res/cardsfolder/h/hopping_automaton.txt svneol=native#text/plain res/cardsfolder/h/horde_of_boggarts.txt -text res/cardsfolder/h/horde_of_notions.txt svneol=native#text/plain +res/cardsfolder/h/horizon_boughs.txt -text res/cardsfolder/h/horizon_canopy.txt svneol=native#text/plain res/cardsfolder/h/horizon_drake.txt svneol=native#text/plain res/cardsfolder/h/horizon_seed.txt -text diff --git a/res/cardsfolder/f/feeding_grounds.txt b/res/cardsfolder/f/feeding_grounds.txt new file mode 100644 index 00000000000..dbe580dcf5d --- /dev/null +++ b/res/cardsfolder/f/feeding_grounds.txt @@ -0,0 +1,13 @@ +Name:Feeding Grounds +ManaCost:no cost +Types:Plane Muraganda +S:Mode$ ReduceCost | EffectZone$ Command | ValidCard$ Card.Green | Type$ Spell | Amount$ 1 | Description$ Green spells cost 1 less to cast. +S:Mode$ ReduceCost | EffectZone$ Command | ValidCard$ Card.Red | Type$ Spell | Amount$ 1 | Description$ Red spells cost 1 less to cast. +T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ DBPutCounter | TriggerDescription$ Whenever you roll Chaos, put X +1/+1 counters on target creature, where X is that creature's converted mana cost. +T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up +SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 +SVar:DBPutCounter:DB$PutCounter | ValidTgts$ Creature | TgtPrompt$ Select target creature | CounterType$ P1P1 | CounterNum$ X +SVar:X:Targeted$CardManaCost +SVar:Picture:http://www.wizards.com/global/images/magic/general/feeding_grounds.jpg +SetInfo:HOP|Common|http://magiccards.info/extras/plane/planechase/feeding-grounds.jpg +Oracle:Red spells cost {1} less to cast.\nGreen spells cost {1} less to cast.\nWhenever you roll {C}, put X +1/+1 counters on target creature, where X is that creature's converted mana cost. diff --git a/res/cardsfolder/h/horizon_boughs.txt b/res/cardsfolder/h/horizon_boughs.txt new file mode 100644 index 00000000000..8b0b55ac43d --- /dev/null +++ b/res/cardsfolder/h/horizon_boughs.txt @@ -0,0 +1,11 @@ +Name:Horizon Boughs +ManaCost:no cost +Types:Plane Pyrulea +S:Mode$ Continuous | EffectZone$ Command | Affected$ Permanent | AddHiddenKeyword$ CARDNAME untaps during each other player's untap step. | Description$ All permanents untap during each player's untap step. +T:Mode$ PlanarDice | Result$ Chaos | TriggerZones$ Command | Execute$ DBFetch | TriggerDescription$ Whenever you roll Chaos, you may search your library for up to three basic land cards, put them onto the battlefield tapped, then shuffle your library. +T:Mode$ PlanarDice | Result$ Planeswalk | TriggerZones$ Command | Execute$ RolledWalk | Secondary$ True | TriggerDescription$ Whenever you roll Planeswalk, put this card on the bottom of its owner's planar deck face down, then move the top card of your planar deck off that planar deck and turn it face up +SVar:RolledWalk:AB$ Planeswalk | Cost$ 0 +SVar:DBFetch:DB$ChangeZone | Origin$ Library | Destination$ Battlefield | Tapped$ True | ChangeType$ Land.Basic | ChangeNum$ 3 +SVar:Picture:http://www.wizards.com/global/images/magic/general/horizon_boughs.jpg +SetInfo:HOP|Common|http://magiccards.info/extras/plane/planechase/horizon-boughs.jpg +Oracle:All permanents untap during each player's untap step.\nWhenever you roll {C}, you may search your library for up to three basic land cards, put them onto the battlefield tapped, then shuffle your library. From 5fc6b489dda3c4714d7a2754fa42bb2c19adbdfb Mon Sep 17 00:00:00 2001 From: swordshine Date: Sat, 2 Mar 2013 01:32:35 +0000 Subject: [PATCH 06/48] - Added Dimensional Breach and Lim-Dul's Vault --- .gitattributes | 2 ++ res/cardsfolder/d/dimensional_breach.txt | 16 ++++++++++++++++ res/cardsfolder/l/lim_duls_vault.txt | 16 ++++++++++++++++ .../java/forge/card/ability/ai/ChangeZoneAi.java | 5 +++-- .../forge/card/ability/effects/DigEffect.java | 2 +- 5 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 res/cardsfolder/d/dimensional_breach.txt create mode 100644 res/cardsfolder/l/lim_duls_vault.txt diff --git a/.gitattributes b/.gitattributes index 31a53af4a04..045f736bc75 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2611,6 +2611,7 @@ res/cardsfolder/d/diamond_valley.txt svneol=native#text/plain res/cardsfolder/d/didgeridoo.txt svneol=native#text/plain res/cardsfolder/d/diligent_farmhand.txt svneol=native#text/plain res/cardsfolder/d/diluvian_primordial.txt -text +res/cardsfolder/d/dimensional_breach.txt -text res/cardsfolder/d/diminish.txt svneol=native#text/plain res/cardsfolder/d/diminishing_returns.txt svneol=native#text/plain res/cardsfolder/d/dimir_aqueduct.txt svneol=native#text/plain @@ -6039,6 +6040,7 @@ res/cardsfolder/l/lim_dul_the_necromancer.txt svneol=native#text/plain res/cardsfolder/l/lim_duls_cohort.txt svneol=native#text/plain res/cardsfolder/l/lim_duls_high_guard.txt svneol=native#text/plain res/cardsfolder/l/lim_duls_paladin.txt -text +res/cardsfolder/l/lim_duls_vault.txt -text res/cardsfolder/l/limestone_golem.txt svneol=native#text/plain res/cardsfolder/l/limited_resources.txt -text res/cardsfolder/l/lin_sivvi_defiant_hero.txt svneol=native#text/plain diff --git a/res/cardsfolder/d/dimensional_breach.txt b/res/cardsfolder/d/dimensional_breach.txt new file mode 100644 index 00000000000..2e5360c8b13 --- /dev/null +++ b/res/cardsfolder/d/dimensional_breach.txt @@ -0,0 +1,16 @@ +Name:Dimensional Breach +ManaCost:5 W W +Types:Sorcery +A:SP$ ChangeZoneAll | Cost$ 5 W W | ChangeType$ Permanent | Origin$ Battlefield | Destination$ Exile | RememberChanged$ True | SubAbility$ DBEffect | SpellDescription$ Exile all permanents. For as long as any of those cards remain exiled, at the beginning of each player's upkeep, that player returns one of the exiled cards he or she owns to the battlefield. +SVar:DBEffect:DB$ Effect | Name$ Dimensional Breach Effect | Triggers$ TrigUpkeep,TrigCleanup | SVars$ BreachReturn,BreachCleanup,MoveChosen,BreachX | RememberObjects$ Remembered | Duration$ Permanent | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:TrigUpkeep:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ Player | Execute$ BreachReturn | TriggerZones$ Command | TriggerController$ TriggeredPlayer | CheckSVar$ BreachX | SVarCompare$ GE1 | TriggerDescription$ At the beginning of each player's upkeep, that player returns one of the exiled cards he or she owns to the battlefield. +SVar:BreachReturn:AB$ ChooseCard | Cost$ 0 | Defined$ TriggeredPlayer | Amount$ 1 | Mandatory$ True | ChoiceTitle$ Choose a card to return to the battlefield | Choices$ Card.IsRemembered+ActivePlayerCtrl | ChoiceZone$ Exile | SubAbility$ MoveChosen +SVar:MoveChosen:DB$ ChangeZone | Origin$ Exile | Destination$ Battlefield | Defined$ ChosenCard | ForgetChanged$ True +SVar:TrigCleanup:Mode$ Always | CheckSVar$ BreachX | SVarCompare$ EQ0 | Static$ True | Execute$ BreachCleanup | TriggerZones$ Command +SVar:BreachCleanup:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile +SVar:BreachX:Count$ValidExile Card.IsRemembered +SVar:Rarity:Rare +SVar:Picture:http://www.wizards.com/global/images/magic/general/dimensional_breach.jpg +SetInfo:SCG|Rare|http://magiccards.info/scans/en/sc/9.jpg +Oracle:Exile all permanents. For as long as any of those cards remain exiled, at the beginning of each player's upkeep, that player returns one of the exiled cards he or she owns to the battlefield. diff --git a/res/cardsfolder/l/lim_duls_vault.txt b/res/cardsfolder/l/lim_duls_vault.txt new file mode 100644 index 00000000000..da94f75b1ad --- /dev/null +++ b/res/cardsfolder/l/lim_duls_vault.txt @@ -0,0 +1,16 @@ +Name:Lim-Dul's Vault +ManaCost:U B +Types:Instant +A:SP$ Dig | Cost$ U B | DigNum$ 5 | NoMove$ True | SubAbility$ DBRepeat | RememberRevealed$ True | StackDescription$ SpellDescription | SpellDescription$ Look at the top five cards of your library. As many times as you choose, you may pay 1 life, put those cards on the bottom of your library in any order, then look at the top five cards of your library. Then shuffle your library and put the last cards you looked at this way on top of it in any order. +SVar:DBRepeat:DB$ Repeat | RepeatSubAbility$ CheckLifePaid | RepeatCheckSVar$ LifePaid | RepeatSVarCompare$ EQ0 | SubAbility$ DBShuffle | StackDescription$ None +SVar:CheckLifePaid:DB$ StoreSVar | SVar$ LifePaid | Type$ Number | Expression$ 1 | UnlessPayer$ You | UnlessCost$ PayLife<1> | UnlessResolveSubs$ WhenPaid | UnlessAI$ Never | SubAbility$ DBResetRem | StackDescription$ No move +SVar:DBResetRem:DB$ Cleanup | ClearRemembered$ True | SubAbility$ GoToBottom +SVar:GoToBottom:DB$ Dig | DigNum$ 5 | ChangeNum$ All | DestinationZone$ Library | LibraryPosition$ -1 | NoLooking$ True | SubAbility$ DBLookAgain | StackDescription$ None +SVar:DBLookAgain:DB$ Dig | DigNum$ 5 | NoMove$ True | RememberRevealed$ True | StackDescription$ None +SVar:DBShuffle:DB$ ChangeZone | Origin$ Library | Destination$ Library | LibraryPosition$ 0 | ChangeType$ Card.IsRemembered | ChangeNum$ 5 | SubAbility$ DBReset | Hidden$ True | SelectPrompt$ Pick 1 on the top of library | Mandatory$ True | NoReveal$ True | StackDescription$ None +SVar:DBReset:DB$ StoreSVar | SVar$ LifePaid | Type$ Number | Expression$ 0 | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:LifePaid:Number$0 +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/lim_duls_vault.jpg +Oracle:Look at the top five cards of your library. As many times as you choose, you may pay 1 life, put those cards on the bottom of your library in any order, then look at the top five cards of your library. Then shuffle your library and put the last cards you looked at this way on top of it in any order. diff --git a/src/main/java/forge/card/ability/ai/ChangeZoneAi.java b/src/main/java/forge/card/ability/ai/ChangeZoneAi.java index ef3944cc27a..703011b7a44 100644 --- a/src/main/java/forge/card/ability/ai/ChangeZoneAi.java +++ b/src/main/java/forge/card/ability/ai/ChangeZoneAi.java @@ -1319,8 +1319,9 @@ public class ChangeZoneAi extends SpellAbilityAi { player.shuffle(); } - if ((!ZoneType.Battlefield.equals(destination) && !"Card".equals(type) && !defined) - || (sa.hasParam("Reveal") && !fetched.isEmpty())) { + if (((!ZoneType.Battlefield.equals(destination) && !"Card".equals(type) && !defined) + || (sa.hasParam("Reveal") && !fetched.isEmpty())) + && !sa.hasParam("NoReveal")) { final String picked = player + " picked:"; if (fetched.size() > 0) { GuiChoose.one(picked, fetched); diff --git a/src/main/java/forge/card/ability/effects/DigEffect.java b/src/main/java/forge/card/ability/effects/DigEffect.java index fa4be8cc5ee..6d143710bab 100644 --- a/src/main/java/forge/card/ability/effects/DigEffect.java +++ b/src/main/java/forge/card/ability/effects/DigEffect.java @@ -143,7 +143,7 @@ public class DigEffect extends SpellAbilityEffect { } // Singletons.getModel().getGameAction().revealToCopmuter(top.toArray()); // - for when it exists - } else if (choser.isHuman()) { + } else if (choser.isHuman() && !sa.hasParam("NoLooking")) { // show the user the revealed cards GuiChoose.one("Looking at cards from library", top); } From 2a0b50230cac2bdcda174e67daaa9343a255f94d Mon Sep 17 00:00:00 2001 From: Sol Date: Sat, 2 Mar 2013 03:35:34 +0000 Subject: [PATCH 07/48] - Adding SetInfo for Lim-Dul's Vault (Special characters don't work with setinfoscript) --- res/cardsfolder/l/lim_duls_vault.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/res/cardsfolder/l/lim_duls_vault.txt b/res/cardsfolder/l/lim_duls_vault.txt index da94f75b1ad..a21c925e950 100644 --- a/res/cardsfolder/l/lim_duls_vault.txt +++ b/res/cardsfolder/l/lim_duls_vault.txt @@ -13,4 +13,5 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:LifePaid:Number$0 SVar:RemAIDeck:True SVar:Picture:http://www.wizards.com/global/images/magic/general/lim_duls_vault.jpg +SetInfo:ALL|Uncommon|http://magiccards.info/scans/en/ai/190.jpg Oracle:Look at the top five cards of your library. As many times as you choose, you may pay 1 life, put those cards on the bottom of your library in any order, then look at the top five cards of your library. Then shuffle your library and put the last cards you looked at this way on top of it in any order. From eaf447434a7c006e6063dd9a0710e30a9aa26a62 Mon Sep 17 00:00:00 2001 From: swordshine Date: Sat, 2 Mar 2013 04:15:41 +0000 Subject: [PATCH 08/48] - Added Eureka --- .gitattributes | 1 + res/cardsfolder/e/eureka.txt | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 res/cardsfolder/e/eureka.txt diff --git a/.gitattributes b/.gitattributes index 045f736bc75..1a230cf0794 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3300,6 +3300,7 @@ res/cardsfolder/e/ethersworn_canonist.txt -text res/cardsfolder/e/ethersworn_shieldmage.txt -text res/cardsfolder/e/etherwrought_page.txt -text svneol=unset#text/plain res/cardsfolder/e/eunuchs_intrigues.txt -text +res/cardsfolder/e/eureka.txt -text res/cardsfolder/e/evacuation.txt svneol=native#text/plain res/cardsfolder/e/evaporate.txt svneol=native#text/plain res/cardsfolder/e/evasive_action.txt svneol=native#text/plain diff --git a/res/cardsfolder/e/eureka.txt b/res/cardsfolder/e/eureka.txt new file mode 100644 index 00000000000..720b8c0ae59 --- /dev/null +++ b/res/cardsfolder/e/eureka.txt @@ -0,0 +1,20 @@ +Name:Eureka +ManaCost:2 G G +Types:Sorcery +A:SP$ Repeat | Cost$ 2 G G | RepeatSubAbility$ ResetCheck | RepeatCheckSVar$ NumPlayerGiveup | RepeatSVarCompare$ LTTotalPlayer | SubAbility$ DBChangeZoneAll | StackDescription$ SpellDescription | SpellDescription$ Starting with you, each player may put a permanent card from his or her hand onto the battlefield. Repeat this process until no one puts a card onto the battlefield. +SVar:ResetCheck:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ Number | Expression$ 0 | SubAbility$ DBRepeatChoice +SVar:DBRepeatChoice:DB$ RepeatEach | RepeatSubAbility$ DBChoice | RepeatPlayers$ Player +SVar:DBChoice:DB$ GenericChoice | Choices$ DBCheckHand,DBNoChange | Defined$ Player.IsRemembered +SVar:DBCheckHand:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ CountSVar | Expression$ NumPlayerGiveup/Plus.1 | ConditionCheckSVar$ CheckHand | ConditionSVarCompare$ EQ0 | SubAbility$ DBChoose | ChoiceDescription$ Choose a permanent to put onto the battlefield +SVar:DBChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Permanent.IsNotRemembered+RememberedPlayerCtrl | ChoiceZone$ Hand | Amount$ 1 | RememberChosen$ True | Mandatory$ True | ConditionCheckSVar$ CheckHand | ConditionSVarCompare$ GE1 +SVar:DBNoChange:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ CountSVar | Expression$ NumPlayerGiveup/Plus.1 | ChoiceDescription$ Do not put a permanent onto the battlefield +SVar:DBChangeZoneAll:DB$ ChangeZoneAll | Origin$ Hand | Destination$ Battlefield | ChangeType$ Card.IsRemembered | SubAbility$ FinalReset +SVar:FinalReset:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ Number | Expression$ 0 | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:NumPlayerGiveup:Number$0 +SVar:TotalPlayer:PlayerCountPlayers$Amount +SVar:CheckHand:Count$ValidHand Permanent.IsNotRemembered+RememberedPlayerCtrl +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/eureka.jpg +SetInfo:LEG|Rare|http://magiccards.info/scans/en/lg/99.jpg +Oracle:Starting with you, each player may put a permanent card from his or her hand onto the battlefield. Repeat this process until no one puts a card onto the battlefield. From 17f881c9db1c2da2e344b097723fb62a3882f16a Mon Sep 17 00:00:00 2001 From: swordshine Date: Sat, 2 Mar 2013 04:57:33 +0000 Subject: [PATCH 09/48] - Added Hypergenesis --- .gitattributes | 1 + res/cardsfolder/h/hypergenesis.txt | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 res/cardsfolder/h/hypergenesis.txt diff --git a/.gitattributes b/.gitattributes index 1a230cf0794..d0cd306df1e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5053,6 +5053,7 @@ res/cardsfolder/h/hydrosurge.txt -text res/cardsfolder/h/hyena_umbra.txt svneol=native#text/plain res/cardsfolder/h/hymn_of_rebirth.txt svneol=native#text/plain res/cardsfolder/h/hymn_to_tourach.txt svneol=native#text/plain +res/cardsfolder/h/hypergenesis.txt -text res/cardsfolder/h/hyperion_blacksmith.txt svneol=native#text/plain res/cardsfolder/h/hypersonic_dragon.txt -text res/cardsfolder/h/hypervolt_grasp.txt svneol=native#text/plain diff --git a/res/cardsfolder/h/hypergenesis.txt b/res/cardsfolder/h/hypergenesis.txt new file mode 100644 index 00000000000..f2b31f0faea --- /dev/null +++ b/res/cardsfolder/h/hypergenesis.txt @@ -0,0 +1,22 @@ +Name:Hypergenesis +ManaCost:no cost +Types:Sorcery +Colors:green +K:Suspend:3:1 G G +A:SP$ Repeat | Cost$ 2 G G | RepeatSubAbility$ ResetCheck | RepeatCheckSVar$ NumPlayerGiveup | RepeatSVarCompare$ LTTotalPlayer | SubAbility$ DBChangeZoneAll | StackDescription$ SpellDescription | SpellDescription$ Starting with you, each player may put an artifact, creature, enchantment, or land card from his or her hand onto the battlefield. Repeat this process until no one puts a card onto the battlefield. +SVar:ResetCheck:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ Number | Expression$ 0 | SubAbility$ DBRepeatChoice +SVar:DBRepeatChoice:DB$ RepeatEach | RepeatSubAbility$ DBChoice | RepeatPlayers$ Player +SVar:DBChoice:DB$ GenericChoice | Choices$ DBCheckHand,DBNoChange | Defined$ Player.IsRemembered +SVar:DBCheckHand:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ CountSVar | Expression$ NumPlayerGiveup/Plus.1 | ConditionCheckSVar$ CheckHand | ConditionSVarCompare$ EQ0 | SubAbility$ DBChoose | ChoiceDescription$ Choose an artifact, creature, enchantment, or land card from your hand onto the battlefield +SVar:DBChoose:DB$ ChooseCard | Defined$ Player.IsRemembered | Choices$ Artifact.IsNotRemembered+RememberedPlayerCtrl,Creature.IsNotRemembered+RememberedPlayerCtrl,Enchantment.IsNotRemembered+RememberedPlayerCtrl,Land.IsNotRemembered+RememberedPlayerCtrl | ChoiceZone$ Hand | Amount$ 1 | RememberChosen$ True | Mandatory$ True | ConditionCheckSVar$ CheckHand | ConditionSVarCompare$ GE1 +SVar:DBNoChange:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ CountSVar | Expression$ NumPlayerGiveup/Plus.1 | ChoiceDescription$ Do not put an artifact, creature, enchantment, or land card from your hand onto the battlefield +SVar:DBChangeZoneAll:DB$ ChangeZoneAll | Origin$ Hand | Destination$ Battlefield | ChangeType$ Card.IsRemembered | SubAbility$ FinalReset +SVar:FinalReset:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ Number | Expression$ 0 | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:NumPlayerGiveup:Number$0 +SVar:TotalPlayer:PlayerCountPlayers$Amount +SVar:CheckHand:Count$ValidHand Artifact.IsNotRemembered+RememberedPlayerCtrl,Creature.IsNotRemembered+RememberedPlayerCtrl,Enchantment.IsNotRemembered+RememberedPlayerCtrl,Land.IsNotRemembered+RememberedPlayerCtrl +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/hypergenesis.jpg +SetInfo:TSP|Rare|http://magiccards.info/scans/en/ts/201.jpg +Oracle:Sorcery\nSuspend 3- {1}{G}{G} (Rather than cast this card from your hand, pay {1}{G}{G} and exile it with three time counters on it. At the beginning of your upkeep, remove a time counter. When the last is removed, cast it without paying its mana cost.)\nStarting with you, each player may put an artifact, creature, enchantment, or land card from his or her hand onto the battlefield. Repeat this process until no one puts a card onto the battlefield. From ef7355859ed5c4fac9e0d150e42b9e83c975dbc1 Mon Sep 17 00:00:00 2001 From: swordshine Date: Sat, 2 Mar 2013 05:00:07 +0000 Subject: [PATCH 10/48] - Fixed the cost of Hypergenesis --- res/cardsfolder/h/hypergenesis.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/cardsfolder/h/hypergenesis.txt b/res/cardsfolder/h/hypergenesis.txt index f2b31f0faea..c61b183ebfc 100644 --- a/res/cardsfolder/h/hypergenesis.txt +++ b/res/cardsfolder/h/hypergenesis.txt @@ -3,7 +3,7 @@ ManaCost:no cost Types:Sorcery Colors:green K:Suspend:3:1 G G -A:SP$ Repeat | Cost$ 2 G G | RepeatSubAbility$ ResetCheck | RepeatCheckSVar$ NumPlayerGiveup | RepeatSVarCompare$ LTTotalPlayer | SubAbility$ DBChangeZoneAll | StackDescription$ SpellDescription | SpellDescription$ Starting with you, each player may put an artifact, creature, enchantment, or land card from his or her hand onto the battlefield. Repeat this process until no one puts a card onto the battlefield. +A:SP$ Repeat | Cost$ 0 | RepeatSubAbility$ ResetCheck | RepeatCheckSVar$ NumPlayerGiveup | RepeatSVarCompare$ LTTotalPlayer | SubAbility$ DBChangeZoneAll | StackDescription$ SpellDescription | SpellDescription$ Starting with you, each player may put an artifact, creature, enchantment, or land card from his or her hand onto the battlefield. Repeat this process until no one puts a card onto the battlefield. SVar:ResetCheck:DB$ StoreSVar | SVar$ NumPlayerGiveup | Type$ Number | Expression$ 0 | SubAbility$ DBRepeatChoice SVar:DBRepeatChoice:DB$ RepeatEach | RepeatSubAbility$ DBChoice | RepeatPlayers$ Player SVar:DBChoice:DB$ GenericChoice | Choices$ DBCheckHand,DBNoChange | Defined$ Player.IsRemembered From 4ae49efb4a3d0bb4f39768d756b85d05a2ba9761 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 2 Mar 2013 07:50:01 +0000 Subject: [PATCH 11/48] A number of inputs recieve stop(); clause --- src/main/java/forge/control/input/InputBlock.java | 1 + .../java/forge/control/input/InputCleanup.java | 1 + .../java/forge/control/input/InputControl.java | 15 ++++++++------- .../java/forge/control/input/InputMulligan.java | 3 ++- .../forge/control/input/InputPassPriority.java | 1 + src/main/java/forge/game/ai/AiInputCommon.java | 1 + 6 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/main/java/forge/control/input/InputBlock.java b/src/main/java/forge/control/input/InputBlock.java index 108013f8e63..d28f60d2cc1 100644 --- a/src/main/java/forge/control/input/InputBlock.java +++ b/src/main/java/forge/control/input/InputBlock.java @@ -106,6 +106,7 @@ public class InputBlock extends Input { currentAttacker = null; allBlocking.clear(); + stop(); FControl.SINGLETON_INSTANCE.getPlayer().getController().passPriority(); } } diff --git a/src/main/java/forge/control/input/InputCleanup.java b/src/main/java/forge/control/input/InputCleanup.java index a478cca5575..808a940efe3 100644 --- a/src/main/java/forge/control/input/InputCleanup.java +++ b/src/main/java/forge/control/input/InputCleanup.java @@ -59,6 +59,7 @@ public class InputCleanup extends Input { // goes to the next phase if (active.isUnlimitedHandSize() || n <= max || n <= 0 || active != turnOwner) { active.getController().passPriority(); + stop(); return; } ButtonUtil.disableAll(); diff --git a/src/main/java/forge/control/input/InputControl.java b/src/main/java/forge/control/input/InputControl.java index 83a3def162e..652f742d907 100644 --- a/src/main/java/forge/control/input/InputControl.java +++ b/src/main/java/forge/control/input/InputControl.java @@ -25,7 +25,7 @@ import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.player.PlayerController; import forge.game.zone.MagicStack; -import forge.util.MyObservable; +import forge.gui.match.controllers.CMessage; /** *

@@ -35,7 +35,7 @@ import forge.util.MyObservable; * @author Forge * @version $Id$ */ -public class InputControl extends MyObservable implements java.io.Serializable { +public class InputControl implements java.io.Serializable { /** Constant serialVersionUID=3955194449319994301L. */ private static final long serialVersionUID = 3955194449319994301L; @@ -134,12 +134,13 @@ public class InputControl extends MyObservable implements java.io.Serializable { * @param update * a boolean. */ - public final void resetInput() { resetInput(true); } - public final void resetInput(final boolean update) { + public final void resetInput() { this.input = null; - if (update) { - this.updateObservers(); - } + this.updateObservers(); + } + + private void updateObservers() { + CMessage.SINGLETON_INSTANCE.getInputControl().invalidate(); } /** diff --git a/src/main/java/forge/control/input/InputMulligan.java b/src/main/java/forge/control/input/InputMulligan.java index 85c82714684..ef7d36e8d7d 100644 --- a/src/main/java/forge/control/input/InputMulligan.java +++ b/src/main/java/forge/control/input/InputMulligan.java @@ -174,11 +174,12 @@ public class InputMulligan extends Input { next.initPlane(); } - //Set Field shown to current player. + //Set Field shown to current player. VField nextField = CMatchUI.SINGLETON_INSTANCE.getFieldViewFor(next); SDisplayUtil.showTab(nextField); game.getPhaseHandler().nextPhase(); + stop(); } @Override diff --git a/src/main/java/forge/control/input/InputPassPriority.java b/src/main/java/forge/control/input/InputPassPriority.java index 77ce4595bb0..80d02562045 100644 --- a/src/main/java/forge/control/input/InputPassPriority.java +++ b/src/main/java/forge/control/input/InputPassPriority.java @@ -75,6 +75,7 @@ public class InputPassPriority extends Input { @Override public final void selectButtonOK() { FControl.SINGLETON_INSTANCE.getPlayer().getController().passPriority(); + stop(); } /** {@inheritDoc} */ diff --git a/src/main/java/forge/game/ai/AiInputCommon.java b/src/main/java/forge/game/ai/AiInputCommon.java index c96048e34b8..391ebad1b06 100644 --- a/src/main/java/forge/game/ai/AiInputCommon.java +++ b/src/main/java/forge/game/ai/AiInputCommon.java @@ -108,6 +108,7 @@ public class AiInputCommon extends Input { } } player.getController().passPriority(); + stop(); } // getMessage(); /** From bfeee22e127c9a376a4d370b2471b4aa7efbacd8 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 2 Mar 2013 07:54:21 +0000 Subject: [PATCH 12/48] rolling back from last commit (should have sent it too early) --- .../java/forge/control/input/InputControl.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/java/forge/control/input/InputControl.java b/src/main/java/forge/control/input/InputControl.java index 652f742d907..83a3def162e 100644 --- a/src/main/java/forge/control/input/InputControl.java +++ b/src/main/java/forge/control/input/InputControl.java @@ -25,7 +25,7 @@ import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.player.PlayerController; import forge.game.zone.MagicStack; -import forge.gui.match.controllers.CMessage; +import forge.util.MyObservable; /** *

@@ -35,7 +35,7 @@ import forge.gui.match.controllers.CMessage; * @author Forge * @version $Id$ */ -public class InputControl implements java.io.Serializable { +public class InputControl extends MyObservable implements java.io.Serializable { /** Constant serialVersionUID=3955194449319994301L. */ private static final long serialVersionUID = 3955194449319994301L; @@ -134,13 +134,12 @@ public class InputControl implements java.io.Serializable { * @param update * a boolean. */ - public final void resetInput() { + public final void resetInput() { resetInput(true); } + public final void resetInput(final boolean update) { this.input = null; - this.updateObservers(); - } - - private void updateObservers() { - CMessage.SINGLETON_INSTANCE.getInputControl().invalidate(); + if (update) { + this.updateObservers(); + } } /** From 9286d5e943f80b2cfcd886eb4420db895cfb17a2 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 2 Mar 2013 07:55:01 +0000 Subject: [PATCH 13/48] StorageReaderFile passes record seq. number along with the record itself --- src/main/java/forge/card/BoosterData.java | 2 +- src/main/java/forge/card/CardBlock.java | 2 +- src/main/java/forge/card/CardEdition.java | 4 ++-- src/main/java/forge/card/FatPackData.java | 2 +- src/main/java/forge/card/FormatCollection.java | 4 ++-- src/main/java/forge/quest/QuestWorld.java | 7 ++++++- src/main/java/forge/util/storage/StorageReaderFile.java | 8 +++++--- 7 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/java/forge/card/BoosterData.java b/src/main/java/forge/card/BoosterData.java index fd8596b19c5..b1294a3d3fa 100644 --- a/src/main/java/forge/card/BoosterData.java +++ b/src/main/java/forge/card/BoosterData.java @@ -180,7 +180,7 @@ public class BoosterData { * @see forge.util.StorageReaderFile#read(java.lang.String) */ @Override - protected BoosterData read(String line) { + protected BoosterData read(String line, int i) { final FileSection section = FileSection.parse(line, ":", "|"); int nC = section.getInt("Commons", 0); int nU = section.getInt("Uncommons", 0); diff --git a/src/main/java/forge/card/CardBlock.java b/src/main/java/forge/card/CardBlock.java index e49658acb44..65dcd1ee945 100644 --- a/src/main/java/forge/card/CardBlock.java +++ b/src/main/java/forge/card/CardBlock.java @@ -229,7 +229,7 @@ public final class CardBlock implements Comparable { * @see forge.util.StorageReaderFile#read(java.lang.String) */ @Override - protected CardBlock read(String line) { + protected CardBlock read(String line, int i) { final String[] sParts = line.trim().split("\\|"); String name = null; diff --git a/src/main/java/forge/card/CardEdition.java b/src/main/java/forge/card/CardEdition.java index 4d8fff6582f..9f514a01dca 100644 --- a/src/main/java/forge/card/CardEdition.java +++ b/src/main/java/forge/card/CardEdition.java @@ -208,9 +208,9 @@ public final class CardEdition implements Comparable { // immutable } @Override - protected CardEdition read(String line) { + protected CardEdition read(String line, int i) { FileSection section = FileSection.parse(line, ":", "|"); - int index = section.getInt("index", -1); + int index = 1+i; String code2 = section.get("code2"); String code = section.get("code3"); String type = section.get("type"); diff --git a/src/main/java/forge/card/FatPackData.java b/src/main/java/forge/card/FatPackData.java index 233eaa61e7a..ac0c1998b4d 100644 --- a/src/main/java/forge/card/FatPackData.java +++ b/src/main/java/forge/card/FatPackData.java @@ -57,7 +57,7 @@ public class FatPackData { * @see forge.util.StorageReaderFile#read(java.lang.String) */ @Override - protected FatPackData read(String line) { + protected FatPackData read(String line, int i) { final FileSection section = FileSection.parse(line, ":", "|"); int nBoosters = section.getInt("Boosters", 0); int nLand = section.getInt("BasicLands", 0); diff --git a/src/main/java/forge/card/FormatCollection.java b/src/main/java/forge/card/FormatCollection.java index 2e4a1deb1ee..20d50a16bc0 100644 --- a/src/main/java/forge/card/FormatCollection.java +++ b/src/main/java/forge/card/FormatCollection.java @@ -93,7 +93,7 @@ public final class FormatCollection extends StorageView { * @see forge.util.StorageReaderFile#read(java.lang.String) */ @Override - protected GameFormat read(String line) { + protected GameFormat read(String line, int i) { final List sets = new ArrayList(); // default: all sets allowed final List bannedCards = new ArrayList(); // default: // nothing @@ -101,7 +101,7 @@ public final class FormatCollection extends StorageView { FileSection section = FileSection.parse(line, ":", "|"); String name = section.get("name"); - int index = section.getInt("index", 0); + int index = 1 + i; String strSets = section.get("sets"); if ( null != strSets ) { sets.addAll(Arrays.asList(strSets.split(", "))); diff --git a/src/main/java/forge/quest/QuestWorld.java b/src/main/java/forge/quest/QuestWorld.java index 5c00b5d54b3..e0dfb175035 100644 --- a/src/main/java/forge/quest/QuestWorld.java +++ b/src/main/java/forge/quest/QuestWorld.java @@ -24,6 +24,7 @@ import java.util.List; import com.google.common.base.Function; import forge.quest.data.GameFormatQuest; +import forge.util.FileSection; import forge.util.storage.StorageReaderFile; /** @@ -121,7 +122,7 @@ public class QuestWorld implements Comparable{ * @see forge.util.StorageReaderFile#read(java.lang.String) */ @Override - protected QuestWorld read(String line) { + protected QuestWorld read(String line, int i) { String useName = null; String useDir = null; GameFormatQuest useFormat = null; @@ -129,9 +130,13 @@ public class QuestWorld implements Comparable{ final List sets = new ArrayList(); final List bannedCards = new ArrayList(); // if both empty, no format + // This is what you need to use here => + // FileSection.parse(line, ":", "|"); + final String[] sParts = line.trim().split("\\|"); for (final String sPart : sParts) { + final String[] kv = sPart.split(":", 2); final String key = kv[0].toLowerCase(); if ("name".equals(key)) { diff --git a/src/main/java/forge/util/storage/StorageReaderFile.java b/src/main/java/forge/util/storage/StorageReaderFile.java index d788337e8f1..ae743e7010c 100644 --- a/src/main/java/forge/util/storage/StorageReaderFile.java +++ b/src/main/java/forge/util/storage/StorageReaderFile.java @@ -70,12 +70,13 @@ public abstract class StorageReaderFile implements IItemReader { public Map readAll() { final Map result = new TreeMap(); + int idx = 0; for (final String s : FileUtil.readFile(this.file)) { if (!this.lineContainsObject(s)) { continue; } - final T item = this.read(s); + final T item = this.read(s, idx); if (null == item) { final String msg = "An object stored in " + this.file.getPath() + " failed to load.\nPlease submit this as a bug with the mentioned file attached."; @@ -83,6 +84,7 @@ public abstract class StorageReaderFile implements IItemReader { continue; } + idx++; result.put(this.keySelector.apply(item), item); } @@ -95,8 +97,8 @@ public abstract class StorageReaderFile implements IItemReader { * @param line * the line * @return the t - */ - protected abstract T read(String line); + */ + protected abstract T read(String line, int idx); /** * Line contains object. From 8fb3c5e0b17f2aee6489ae299f90195e9ec84626 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 2 Mar 2013 08:08:55 +0000 Subject: [PATCH 14/48] commiting sets and blocks files with Index:LineNumber removed --- res/blockdata/blocks.txt | 98 ++++++------- res/blockdata/setdata.txt | 176 ++++++++++++------------ src/main/java/forge/card/CardBlock.java | 4 +- 3 files changed, 138 insertions(+), 140 deletions(-) diff --git a/res/blockdata/blocks.txt b/res/blockdata/blocks.txt index ca2be21257f..f7ed6355888 100644 --- a/res/blockdata/blocks.txt +++ b/res/blockdata/blocks.txt @@ -1,53 +1,53 @@ -Index:0|Set0:LEA|Name:Alpha|DraftPacks:3|LandSetCode:LEA|SealedPacks:6 -Index:1|Set0:LEB|Name:Beta|DraftPacks:3|LandSetCode:LEB|SealedPacks:6 -Index:2|Set0:2ED|Name:Unlimited|DraftPacks:3|LandSetCode:2ED|SealedPacks:6 -Index:3|Set0:ARN|Name:Arabian Nights|DraftPacks:5|LandSetCode:2ED|SealedPacks:9 -Index:4|Set0:ATQ|Name:Antiquities|DraftPacks:5|LandSetCode:2ED|SealedPacks:9 -Index:5|Set0:3ED|Name:Revised|DraftPacks:3|LandSetCode:3ED|SealedPacks:6 -Index:6|Set0:LEG|Name:Legends|DraftPacks:3|LandSetCode:3ED|SealedPacks:6 -Index:7|Set0:DRK|Name:The Dark|DraftPacks:5|LandSetCode:3ED|SealedPacks:9 -Index:8|Set0:FEM|Name:Fallen Empires|DraftPacks:5|LandSetCode:3ED|SealedPacks:9 -Index:9|Set0:4ED|Name:Fourth Edition|DraftPacks:3|LandSetCode:4ED|SealedPacks:6 +Set0:LEA|Name:Alpha|DraftPacks:3|LandSetCode:LEA|SealedPacks:6 +Set0:LEB|Name:Beta|DraftPacks:3|LandSetCode:LEB|SealedPacks:6 +Set0:2ED|Name:Unlimited|DraftPacks:3|LandSetCode:2ED|SealedPacks:6 +Set0:ARN|Name:Arabian Nights|DraftPacks:5|LandSetCode:2ED|SealedPacks:9 +Set0:ATQ|Name:Antiquities|DraftPacks:5|LandSetCode:2ED|SealedPacks:9 +Set0:3ED|Name:Revised|DraftPacks:3|LandSetCode:3ED|SealedPacks:6 +Set0:LEG|Name:Legends|DraftPacks:3|LandSetCode:3ED|SealedPacks:6 +Set0:DRK|Name:The Dark|DraftPacks:5|LandSetCode:3ED|SealedPacks:9 +Set0:FEM|Name:Fallen Empires|DraftPacks:5|LandSetCode:3ED|SealedPacks:9 +Set0:4ED|Name:Fourth Edition|DraftPacks:3|LandSetCode:4ED|SealedPacks:6 -Index:10|Set0:ICE|Set1:ALL|Set2:CSP|Name:Ice Age|DraftPacks:3|LandSetCode:ICE|SealedPacks:6 -Index:11|Set0:HML|Name:Homelands|DraftPacks:5|LandSetCode:4ED|SealedPacks:9 -Index:12|Set0:MIR|Set1:VIS|Set2:WTH|Name:Mirage|DraftPacks:3|LandSetCode:MIR|SealedPacks:6 -Index:13|Set0:5ED|Name:Fifth Edition|DraftPacks:3|LandSetCode:5ED|SealedPacks:6 -Index:14|Set0:POR|Name:Portal|DraftPacks:3|LandSetCode:POR|SealedPacks:6 -Index:15|Set0:TMP|Set1:STH|Set2:EXO|Name:Tempest|DraftPacks:3|LandSetCode:TMP|SealedPacks:6 -Index:16|Set0:PO2|Name:Portal Second Age|DraftPacks:3|LandSetCode:PO2|SealedPacks:6 -Index:17|Set0:USG|Set1:ULG|Set2:UDS|Name:Urza|DraftPacks:3|LandSetCode:USG|SealedPacks:6 -Index:18|Set0:6ED|Name:Sixth Edition|DraftPacks:3|LandSetCode:6ED|SealedPacks:6 -Index:19|Set0:PTK|Name:Portal Three Kingdoms|DraftPacks:5|LandSetCode:PTK|SealedPacks:9 +Set0:ICE|Set1:ALL|Set2:CSP|Name:Ice Age|DraftPacks:3|LandSetCode:ICE|SealedPacks:6 +Set0:HML|Name:Homelands|DraftPacks:5|LandSetCode:4ED|SealedPacks:9 +Set0:MIR|Set1:VIS|Set2:WTH|Name:Mirage|DraftPacks:3|LandSetCode:MIR|SealedPacks:6 +Set0:5ED|Name:Fifth Edition|DraftPacks:3|LandSetCode:5ED|SealedPacks:6 +Set0:POR|Name:Portal|DraftPacks:3|LandSetCode:POR|SealedPacks:6 +Set0:TMP|Set1:STH|Set2:EXO|Name:Tempest|DraftPacks:3|LandSetCode:TMP|SealedPacks:6 +Set0:PO2|Name:Portal Second Age|DraftPacks:3|LandSetCode:PO2|SealedPacks:6 +Set0:USG|Set1:ULG|Set2:UDS|Name:Urza|DraftPacks:3|LandSetCode:USG|SealedPacks:6 +Set0:6ED|Name:Sixth Edition|DraftPacks:3|LandSetCode:6ED|SealedPacks:6 +Set0:PTK|Name:Portal Three Kingdoms|DraftPacks:5|LandSetCode:PTK|SealedPacks:9 -Index:20|Set0:MMQ|Set1:NMS|Set2:PCY|Name:Masques|DraftPacks:3|LandSetCode:MMQ|SealedPacks:6 -Index:21|Set0:INV|Set1:PLS|Set2:APC|Name:Invasion|DraftPacks:3|LandSetCode:INV|SealedPacks:6 -Index:22|Set0:7ED|Name:Seventh Edition|DraftPacks:3|LandSetCode:7ED|SealedPacks:6 -Index:23|Set0:ODY|Set1:TOR|Set2:JUD|Name:Odyssey|DraftPacks:3|LandSetCode:ODY|SealedPacks:6 -Index:24|Set0:ONS|Set1:LGN|Set2:SCG|Name:Onslaught|DraftPacks:3|LandSetCode:ONS|SealedPacks:6 -Index:25|Set0:8ED|Name:Eighth Edition|DraftPacks:3|LandSetCode:8ED|SealedPacks:6 -Index:26|Set0:MRD|Set1:DST|Set2:5DN|Name:Mirrodin|DraftPacks:3|LandSetCode:MRD|SealedPacks:6 -Index:27|Set0:CHK|Set1:BOK|Set2:SOK|Name:Kamigawa|DraftPacks:3|LandSetCode:CHK|SealedPacks:6 -Index:28|Set0:9ED|Name:Ninth Edition|DraftPacks:3|LandSetCode:9ED|SealedPacks:6 -Index:29|Set0:RAV|Set1:GPT|Set2:DIS|Name:Ravnica|DraftPacks:3|LandSetCode:RAV|SealedPacks:6 +Set0:MMQ|Set1:NMS|Set2:PCY|Name:Masques|DraftPacks:3|LandSetCode:MMQ|SealedPacks:6 +Set0:INV|Set1:PLS|Set2:APC|Name:Invasion|DraftPacks:3|LandSetCode:INV|SealedPacks:6 +Set0:7ED|Name:Seventh Edition|DraftPacks:3|LandSetCode:7ED|SealedPacks:6 +Set0:ODY|Set1:TOR|Set2:JUD|Name:Odyssey|DraftPacks:3|LandSetCode:ODY|SealedPacks:6 +Set0:ONS|Set1:LGN|Set2:SCG|Name:Onslaught|DraftPacks:3|LandSetCode:ONS|SealedPacks:6 +Set0:8ED|Name:Eighth Edition|DraftPacks:3|LandSetCode:8ED|SealedPacks:6 +Set0:MRD|Set1:DST|Set2:5DN|Name:Mirrodin|DraftPacks:3|LandSetCode:MRD|SealedPacks:6 +Set0:CHK|Set1:BOK|Set2:SOK|Name:Kamigawa|DraftPacks:3|LandSetCode:CHK|SealedPacks:6 +Set0:9ED|Name:Ninth Edition|DraftPacks:3|LandSetCode:9ED|SealedPacks:6 +Set0:RAV|Set1:GPT|Set2:DIS|Name:Ravnica|DraftPacks:3|LandSetCode:RAV|SealedPacks:6 -Index:30|Set0:CSP|Name:Coldsnap|DraftPacks:3|LandSetCode:9ED|SealedPacks:6 -Index:31|Set0:TSP|Set1:PLC|Set2:FUT|Name:Time Spiral|DraftPacks:3|LandSetCode:TSP|SealedPacks:6 -Index:32|Set0:10E|Name:Tenth Edition|DraftPacks:3|LandSetCode:10E|SealedPacks:6 -Index:33|Set0:LRW|Set1:MOR|Name:Lorwyn|DraftPacks:3|LandSetCode:LRW|SealedPacks:6 -Index:34|Set0:SHM|Set1:EVE|Name:Shadowmoor|DraftPacks:3|LandSetCode:SHM|SealedPacks:6 -Index:35|Set0:ALA|Set1:CFX|Set2:ARB|Name:Shards of Alara|DraftPacks:3|LandSetCode:ALA|SealedPacks:6 -Index:36|Set0:M10|Name:Magic 2010|DraftPacks:3|LandSetCode:M10|SealedPacks:6 -Index:37|Set0:ZEN|Set1:WWK|Name:Zendikar|DraftPacks:3|LandSetCode:ZEN|SealedPacks:6 -Index:38|Set0:ROE|Name:Rise of the Eldrazi|DraftPacks:3|LandSetCode:ROE|SealedPacks:6 -Index:39|Set0:M11|Name:Magic 2011|DraftPacks:3|LandSetCode:M11|SealedPacks:6 +Set0:CSP|Name:Coldsnap|DraftPacks:3|LandSetCode:9ED|SealedPacks:6 +Set0:TSP|Set1:PLC|Set2:FUT|Name:Time Spiral|DraftPacks:3|LandSetCode:TSP|SealedPacks:6 +Set0:10E|Name:Tenth Edition|DraftPacks:3|LandSetCode:10E|SealedPacks:6 +Set0:LRW|Set1:MOR|Name:Lorwyn|DraftPacks:3|LandSetCode:LRW|SealedPacks:6 +Set0:SHM|Set1:EVE|Name:Shadowmoor|DraftPacks:3|LandSetCode:SHM|SealedPacks:6 +Set0:ALA|Set1:CFX|Set2:ARB|Name:Shards of Alara|DraftPacks:3|LandSetCode:ALA|SealedPacks:6 +Set0:M10|Name:Magic 2010|DraftPacks:3|LandSetCode:M10|SealedPacks:6 +Set0:ZEN|Set1:WWK|Name:Zendikar|DraftPacks:3|LandSetCode:ZEN|SealedPacks:6 +Set0:ROE|Name:Rise of the Eldrazi|DraftPacks:3|LandSetCode:ROE|SealedPacks:6 +Set0:M11|Name:Magic 2011|DraftPacks:3|LandSetCode:M11|SealedPacks:6 -Index:40|Set0:SOM|Set1:MBS|Set2:NPH|Name:Scars of Mirrodin|DraftPacks:3|LandSetCode:SOM|SealedPacks:6 -Index:41|Set0:M12|Name:Magic 2012|DraftPacks:3|LandSetCode:M12|SealedPacks:6 -Index:42|Set0:ISD|Set1:DKA|Name:Innistrad|DraftPacks:3|LandSetCode:ISD|SealedPacks:6 -Index:43|Set0:AVR|Name:Avacyn Restored|DraftPacks:3|LandSetCode:AVR|SealedPacks:6 -Index:44|Set0:M13|Name:Magic 2013|DraftPacks:3|LandSetCode:M13|SealedPacks:6 -Index:45|Set0:RTR|Name:Return to Ravnica|DraftPacks:3|LandSetCode:RTR|SealedPacks:6 -Index:46|Set0:RTR|Set1:RTR|Set2:RTR|Set3:RTR|Set4:RTR|Meta0:CHOOSE1/CUBE/RtRGuildAzorius/Azorius Guild;CUBE/RtRGuildIzzet/Izzet Guild;CUBE/RtRGuildRakdos/Rakdos Guild;CUBE/RtRGuildGolgari/Golgari Guild;CUBE/RtRGuildSelesnya/Selesnya Guild/GUILD|Meta1:CHOOSE1/CUBE/RtRPromoAzorius/Azorius Guild;CUBE/RtRPromoIzzet/Izzet Guild;CUBE/RtRPromoRakdos/Rakdos Guild;CUBE/RtRPromoGolgari/Golgari Guild;CUBE/RtRPromoSelesnya/Selesnya Guild/PROMO|Name:Return to Ravnica Guild Sealed|DraftPacks:3|LandSetCode:RTR|SealedPacks:7 -Index:47|Set0:GTC|Name:Gatecrash|DraftPacks:3|LandSetCode:RTR|SealedPacks:6 -Index:48|Set0:GTC|Set1:GTC|Set2:GTC|Set3:GTC|Set4:GTC|Meta0:CHOOSE1/CUBE/GtcGuildBoros/Boros Guild;CUBE/GtcGuildDimir/Dimir Guild;CUBE/GtcGuildGruul/Gruul Guild;CUBE/GtcGuildOrzhov/Orzhov Guild;CUBE/GtcGuildSimic/Simic Guild/GUILD|Meta1:CHOOSE1/CUBE/GtcPromoBoros/Boros Guild;CUBE/GtcPromoDimir/Dimir Guild;CUBE/GtcPromoGruul/Gruul Guild;CUBE/GtcPromoOrzhov/Orzhov Guild;CUBE/GtcPromoSimic/Simic Guild/PROMO|Name:Gatecrash Guild Sealed|DraftPacks:3|LandSetCode:RTR|SealedPacks:7 +Set0:SOM|Set1:MBS|Set2:NPH|Name:Scars of Mirrodin|DraftPacks:3|LandSetCode:SOM|SealedPacks:6 +Set0:M12|Name:Magic 2012|DraftPacks:3|LandSetCode:M12|SealedPacks:6 +Set0:ISD|Set1:DKA|Name:Innistrad|DraftPacks:3|LandSetCode:ISD|SealedPacks:6 +Set0:AVR|Name:Avacyn Restored|DraftPacks:3|LandSetCode:AVR|SealedPacks:6 +Set0:M13|Name:Magic 2013|DraftPacks:3|LandSetCode:M13|SealedPacks:6 +Set0:RTR|Name:Return to Ravnica|DraftPacks:3|LandSetCode:RTR|SealedPacks:6 +Set0:RTR|Set1:RTR|Set2:RTR|Set3:RTR|Set4:RTR|Meta0:CHOOSE1/CUBE/RtRGuildAzorius/Azorius Guild;CUBE/RtRGuildIzzet/Izzet Guild;CUBE/RtRGuildRakdos/Rakdos Guild;CUBE/RtRGuildGolgari/Golgari Guild;CUBE/RtRGuildSelesnya/Selesnya Guild/GUILD|Meta1:CHOOSE1/CUBE/RtRPromoAzorius/Azorius Guild;CUBE/RtRPromoIzzet/Izzet Guild;CUBE/RtRPromoRakdos/Rakdos Guild;CUBE/RtRPromoGolgari/Golgari Guild;CUBE/RtRPromoSelesnya/Selesnya Guild/PROMO|Name:Return to Ravnica Guild Sealed|DraftPacks:3|LandSetCode:RTR|SealedPacks:7 +Set0:GTC|Name:Gatecrash|DraftPacks:3|LandSetCode:RTR|SealedPacks:6 +Set0:GTC|Set1:GTC|Set2:GTC|Set3:GTC|Set4:GTC|Meta0:CHOOSE1/CUBE/GtcGuildBoros/Boros Guild;CUBE/GtcGuildDimir/Dimir Guild;CUBE/GtcGuildGruul/Gruul Guild;CUBE/GtcGuildOrzhov/Orzhov Guild;CUBE/GtcGuildSimic/Simic Guild/GUILD|Meta1:CHOOSE1/CUBE/GtcPromoBoros/Boros Guild;CUBE/GtcPromoDimir/Dimir Guild;CUBE/GtcPromoGruul/Gruul Guild;CUBE/GtcPromoOrzhov/Orzhov Guild;CUBE/GtcPromoSimic/Simic Guild/PROMO|Name:Gatecrash Guild Sealed|DraftPacks:3|LandSetCode:RTR|SealedPacks:7 diff --git a/res/blockdata/setdata.txt b/res/blockdata/setdata.txt index f6b95befc23..28fa4f6cc7d 100644 --- a/res/blockdata/setdata.txt +++ b/res/blockdata/setdata.txt @@ -1,97 +1,97 @@ -Index:0|Code2:MBP|Code3:MBP|Type:Other|Name:Media Insert Promo|Alias:PRO -Index:1|Code2:A|Code3:LEA|Type:Core|Name:Limited Edition Alpha -Index:2|Code2:B|Code3:LEB|Type:Core|Name:Limited Edition Beta -Index:3|Code2:U|Code3:2ED|Type:Core|Border:White|Name:Unlimited Edition -Index:4|Code2:AN|Code3:ARN|Type:Expansion|Name:Arabian Nights -Index:5|Code2:AQ|Code3:ATQ|Type:Expansion|Name:Antiquities -Index:6|Code2:R|Code3:3ED|Type:Core|Border:White|Name:Revised Edition -Index:7|Code2:LG|Code3:LEG|Type:Expansion|Name:Legends -Index:8|Code2:DK|Code3:DRK|Type:Expansion|Name:The Dark -Index:9|Code2:FE|Code3:FEM|Type:Expansion|Name:Fallen Empires +Code2:MBP|Code3:MBP|Type:Other|Name:Media Insert Promo|Alias:PRO +Code2:A|Code3:LEA|Type:Core|Name:Limited Edition Alpha +Code2:B|Code3:LEB|Type:Core|Name:Limited Edition Beta +Code2:U|Code3:2ED|Type:Core|Border:White|Name:Unlimited Edition +Code2:AN|Code3:ARN|Type:Expansion|Name:Arabian Nights +Code2:AQ|Code3:ATQ|Type:Expansion|Name:Antiquities +Code2:R|Code3:3ED|Type:Core|Border:White|Name:Revised Edition +Code2:LG|Code3:LEG|Type:Expansion|Name:Legends +Code2:DK|Code3:DRK|Type:Expansion|Name:The Dark +Code2:FE|Code3:FEM|Type:Expansion|Name:Fallen Empires -Index:10|Code2:4E|Code3:4ED|Type:Core|Border:White|Name:Fourth Edition -Index:11|Code2:IA|Code3:ICE|Type:Expansion|Name:Ice Age -Index:12|Code2:CH|Code3:CHR|Type:Reprint|Border:White|Name:Chronicles -Index:13|Code2:HL|Code3:HML|Type:Expansion|Name:Homelands -Index:14|Code2:AL|Code3:ALL|Type:Expansion|Name:Alliances -Index:15|Code2:MI|Code3:MIR|Type:Expansion|Name:Mirage -Index:16|Code2:VI|Code3:VIS|Type:Expansion|Name:Visions -Index:17|Code2:5E|Code3:5ED|Type:Core|Border:White|Name:Fifth Edition -Index:18|Code2:PT|Code3:POR|Type:Starter|Name:Portal -Index:19|Code2:WL|Code3:WTH|Type:Expansion|Name:Weatherlight +Code2:4E|Code3:4ED|Type:Core|Border:White|Name:Fourth Edition +Code2:IA|Code3:ICE|Type:Expansion|Name:Ice Age +Code2:CH|Code3:CHR|Type:Reprint|Border:White|Name:Chronicles +Code2:HL|Code3:HML|Type:Expansion|Name:Homelands +Code2:AL|Code3:ALL|Type:Expansion|Name:Alliances +Code2:MI|Code3:MIR|Type:Expansion|Name:Mirage +Code2:VI|Code3:VIS|Type:Expansion|Name:Visions +Code2:5E|Code3:5ED|Type:Core|Border:White|Name:Fifth Edition +Code2:PT|Code3:POR|Type:Starter|Name:Portal +Code2:WL|Code3:WTH|Type:Expansion|Name:Weatherlight -Index:20|Code2:TE|Code3:TMP|Type:Expansion|Name:Tempest -Index:21|Code2:SH|Code3:STH|Type:Expansion|Name:Stronghold -Index:22|Code2:EX|Code3:EXO|Type:Expansion|Name:Exodus -Index:23|Code2:P2|Code3:PO2|Type:Starter|Name:Portal Second Age|Alias:P02 -Index:24|Code2:US|Code3:USG|Type:Expansion|Name:Urza's Saga -Index:25|Code2:UL|Code3:ULG|Type:Expansion|Name:Urza's Legacy -Index:26|Code2:6E|Code3:6ED|Type:Core|Border:White|Name:Classic (Sixth Edition) -Index:27|Code2:UD|Code3:UDS|Type:Expansion|Name:Urza's Destiny -Index:28|Code2:P3|Code3:PTK|Type:Starter|Border:White|Name:Portal Three Kingdoms -Index:29|Code2:ST|Code3:S99|Type:Starter|Border:White|Name:Starter 1999 +Code2:TE|Code3:TMP|Type:Expansion|Name:Tempest +Code2:SH|Code3:STH|Type:Expansion|Name:Stronghold +Code2:EX|Code3:EXO|Type:Expansion|Name:Exodus +Code2:P2|Code3:PO2|Type:Starter|Name:Portal Second Age|Alias:P02 +Code2:US|Code3:USG|Type:Expansion|Name:Urza's Saga +Code2:UL|Code3:ULG|Type:Expansion|Name:Urza's Legacy +Code2:6E|Code3:6ED|Type:Core|Border:White|Name:Classic (Sixth Edition) +Code2:UD|Code3:UDS|Type:Expansion|Name:Urza's Destiny +Code2:P3|Code3:PTK|Type:Starter|Border:White|Name:Portal Three Kingdoms +Code2:ST|Code3:S99|Type:Starter|Border:White|Name:Starter 1999 -Index:30|Code2:MM|Code3:MMQ|Type:Expansion|Name:Mercadian Masques -Index:31|Code2:NE|Code3:NMS|Type:Expansion|Name:Nemesis|Alias:NEM -Index:32|Code2:S2K|Code3:S00|Type:Starter|Border:White|Name:Starter 2000 -Index:33|Code2:PY|Code3:PCY|Type:Expansion|Name:Prophecy -Index:34|Code2:IN|Code3:INV|Type:Expansion|Name:Invasion -Index:35|Code2:PS|Code3:PLS|Type:Expansion|Name:Planeshift -Index:36|Code2:7E|Code3:7ED|Type:Core|Border:White|Name:Seventh Edition -Index:37|Code2:AP|Code3:APC|Type:Expansion|Name:Apocalypse -Index:38|Code2:OD|Code3:ODY|Type:Expansion|Name:Odyssey -Index:39|Code2:TO|Code3:TOR|Type:Expansion|Name:Torment +Code2:MM|Code3:MMQ|Type:Expansion|Name:Mercadian Masques +Code2:NE|Code3:NMS|Type:Expansion|Name:Nemesis|Alias:NEM +Code2:S2K|Code3:S00|Type:Starter|Border:White|Name:Starter 2000 +Code2:PY|Code3:PCY|Type:Expansion|Name:Prophecy +Code2:IN|Code3:INV|Type:Expansion|Name:Invasion +Code2:PS|Code3:PLS|Type:Expansion|Name:Planeshift +Code2:7E|Code3:7ED|Type:Core|Border:White|Name:Seventh Edition +Code2:AP|Code3:APC|Type:Expansion|Name:Apocalypse +Code2:OD|Code3:ODY|Type:Expansion|Name:Odyssey +Code2:TO|Code3:TOR|Type:Expansion|Name:Torment -Index:40|Code2:JU|Code3:JUD|Type:Expansion|Name:Judgment -Index:41|Code2:ON|Code3:ONS|Type:Expansion|Name:Onslaught -Index:42|Code2:LE|Code3:LGN|Type:Expansion|Name:Legions -Index:43|Code2:SC|Code3:SCG|Type:Expansion|Name:Scourge -Index:44|Code2:8E|Code3:8ED|Type:Core|Border:White|Name:Core Set - Eighth Edition -Index:45|Code2:MR|Code3:MRD|Type:Expansion|Name:Mirrodin -Index:46|Code2:DS|Code3:DST|Type:Expansion|Name:Darksteel -Index:47|Code2:FD|Code3:5DN|Type:Expansion|Name:Fifth Dawn -Index:48|Code2:CHK|Code3:CHK|Type:Expansion|Name:Champions of Kamigawa -Index:49|Code2:BOK|Code3:BOK|Type:Expansion|Name:Betrayers of Kamigawa +Code2:JU|Code3:JUD|Type:Expansion|Name:Judgment +Code2:ON|Code3:ONS|Type:Expansion|Name:Onslaught +Code2:LE|Code3:LGN|Type:Expansion|Name:Legions +Code2:SC|Code3:SCG|Type:Expansion|Name:Scourge +Code2:8E|Code3:8ED|Type:Core|Border:White|Name:Core Set - Eighth Edition +Code2:MR|Code3:MRD|Type:Expansion|Name:Mirrodin +Code2:DS|Code3:DST|Type:Expansion|Name:Darksteel +Code2:FD|Code3:5DN|Type:Expansion|Name:Fifth Dawn +Code2:CHK|Code3:CHK|Type:Expansion|Name:Champions of Kamigawa +Code2:BOK|Code3:BOK|Type:Expansion|Name:Betrayers of Kamigawa -Index:50|Code2:SOK|Code3:SOK|Type:Expansion|Name:Saviors of Kamigawa -Index:51|Code2:9E|Code3:9ED|Type:Core|Border:White|Name:Core Set - Ninth Edition -Index:52|Code2:RAV|Code3:RAV|Type:Expansion|Name:Ravnica: City of Guilds -Index:53|Code2:GP|Code3:GPT|Type:Expansion|Name:Guildpact -Index:54|Code2:DIS|Code3:DIS|Type:Expansion|Name:Dissension -Index:55|Code2:CS|Code3:CSP|Type:Expansion|Name:Coldsnap -Index:56|Code2:TSP|Code3:TSP|Type:Expansion|Name:Time Spiral -Index:57|Code2:TSB|Code3:TSB|Type:Expansion|Name:Time Spiral Timeshifted -Index:58|Code2:PLC|Code3:PLC|Type:Expansion|Name:Planar Chaos -Index:59|Code2:FUT|Code3:FUT|Type:Expansion|Name:Future Sight +Code2:SOK|Code3:SOK|Type:Expansion|Name:Saviors of Kamigawa +Code2:9E|Code3:9ED|Type:Core|Border:White|Name:Core Set - Ninth Edition +Code2:RAV|Code3:RAV|Type:Expansion|Name:Ravnica: City of Guilds +Code2:GP|Code3:GPT|Type:Expansion|Name:Guildpact +Code2:DIS|Code3:DIS|Type:Expansion|Name:Dissension +Code2:CS|Code3:CSP|Type:Expansion|Name:Coldsnap +Code2:TSP|Code3:TSP|Type:Expansion|Name:Time Spiral +Code2:TSB|Code3:TSB|Type:Expansion|Name:Time Spiral Timeshifted +Code2:PLC|Code3:PLC|Type:Expansion|Name:Planar Chaos +Code2:FUT|Code3:FUT|Type:Expansion|Name:Future Sight -Index:60|Code2:10E|Code3:10E|Type:Core|Name:Core Set - Tenth Edition -Index:61|Code2:LRW|Code3:LRW|Type:Expansion|Name:Lorwyn -Index:62|Code2:MOR|Code3:MOR|Type:Expansion|Name:Morningtide -Index:63|Code2:SHM|Code3:SHM|Type:Expansion|Name:Shadowmoor -Index:64|Code2:EVE|Code3:EVE|Type:Expansion|Name:Eventide|Alias:EVT -Index:65|Code2:ALA|Code3:ALA|Type:Expansion|Name:Shards of Alara -Index:66|Code2:CFX|Code3:CFX|Type:Expansion|Name:Conflux|Alias:CON -Index:67|Code2:ARB|Code3:ARB|Type:Expansion|Name:Alara Reborn -Index:68|Code2:M10|Code3:M10|Type:Core|Name:Magic 2010 -Index:69|Code2:ZEN|Code3:ZEN|Type:Expansion|Name:Zendikar +Code2:10E|Code3:10E|Type:Core|Name:Core Set - Tenth Edition +Code2:LRW|Code3:LRW|Type:Expansion|Name:Lorwyn +Code2:MOR|Code3:MOR|Type:Expansion|Name:Morningtide +Code2:SHM|Code3:SHM|Type:Expansion|Name:Shadowmoor +Code2:EVE|Code3:EVE|Type:Expansion|Name:Eventide|Alias:EVT +Code2:ALA|Code3:ALA|Type:Expansion|Name:Shards of Alara +Code2:CFX|Code3:CFX|Type:Expansion|Name:Conflux|Alias:CON +Code2:ARB|Code3:ARB|Type:Expansion|Name:Alara Reborn +Code2:M10|Code3:M10|Type:Core|Name:Magic 2010 +Code2:ZEN|Code3:ZEN|Type:Expansion|Name:Zendikar -Index:70|Code2:WWK|Code3:WWK|Type:Expansion|Name:Worldwake -Index:71|Code2:ROE|Code3:ROE|Type:Expansion|Name:Rise of the Eldrazi -Index:72|Code2:M11|Code3:M11|Type:Core|Name:Magic 2011 -Index:73|Code2:SOM|Code3:SOM|Type:Expansion|Name:Scars of Mirrodin -Index:74|Code2:MBS|Code3:MBS|Type:Expansion|Name:Mirrodin Besieged -Index:75|Code2:NPH|Code3:NPH|Type:Expansion|Name:New Phyrexia -Index:76|Code2:COM|Code3:COM|Type:Other|Name:Commander -Index:77|Code2:M12|Code3:M12|Type:Core|Name:Magic 2012 -Index:78|Code2:ISD|Code3:ISD|Type:Expansion|Name:Innistrad -Index:79|Code2:DKA|Code3:DKA|Type:Expansion|Name:Dark Ascension +Code2:WWK|Code3:WWK|Type:Expansion|Name:Worldwake +Code2:ROE|Code3:ROE|Type:Expansion|Name:Rise of the Eldrazi +Code2:M11|Code3:M11|Type:Core|Name:Magic 2011 +Code2:SOM|Code3:SOM|Type:Expansion|Name:Scars of Mirrodin +Code2:MBS|Code3:MBS|Type:Expansion|Name:Mirrodin Besieged +Code2:NPH|Code3:NPH|Type:Expansion|Name:New Phyrexia +Code2:COM|Code3:COM|Type:Other|Name:Commander +Code2:M12|Code3:M12|Type:Core|Name:Magic 2012 +Code2:ISD|Code3:ISD|Type:Expansion|Name:Innistrad +Code2:DKA|Code3:DKA|Type:Expansion|Name:Dark Ascension -Index:80|Code2:AVR|Code3:AVR|Type:Expansion|Name:Avacyn Restored -Index:81|Code2:PC2|Code3:PC2|Type:Other|Name:Planechase 2012 Edition -Index:82|Code2:M13|Code3:M13|Type:Core|Name:Magic 2013 -Index:83|Code2:RTR|Code3:RTR|Type:Expansion|Name:Return to Ravnica -Index:84|Code2:GTC|Code3:GTC|Type:Expansion|Name:Gatecrash +Code2:AVR|Code3:AVR|Type:Expansion|Name:Avacyn Restored +Code2:PC2|Code3:PC2|Type:Other|Name:Planechase 2012 Edition +Code2:M13|Code3:M13|Type:Core|Name:Magic 2013 +Code2:RTR|Code3:RTR|Type:Expansion|Name:Return to Ravnica +Code2:GTC|Code3:GTC|Type:Expansion|Name:Gatecrash -Index:86|Code2:VAN|Code3:VAN|Type:Other|Name:Vanguard -Index:87|Code2:ARC|Code3:ARC|Type:Other|Name:Archenemy -Index:88|Code2:HOP|Code3:HOP|Type:Other|Name:Planechase +Code2:VAN|Code3:VAN|Type:Other|Name:Vanguard +Code2:ARC|Code3:ARC|Type:Other|Name:Archenemy +Code2:HOP|Code3:HOP|Type:Other|Name:Planechase diff --git a/src/main/java/forge/card/CardBlock.java b/src/main/java/forge/card/CardBlock.java index 65dcd1ee945..3ff4691e6b7 100644 --- a/src/main/java/forge/card/CardBlock.java +++ b/src/main/java/forge/card/CardBlock.java @@ -233,7 +233,7 @@ public final class CardBlock implements Comparable { final String[] sParts = line.trim().split("\\|"); String name = null; - int index = -1; + int index = 1+i; final List sets = new ArrayList(9); // add support for up to 9 different sets in a block! final ArrayList metas = new ArrayList(); CardEdition landSet = null; @@ -245,8 +245,6 @@ public final class CardBlock implements Comparable { final String key = kv[0].toLowerCase(); if ("name".equals(key)) { name = kv[1]; - } else if ("index".equals(key)) { - index = Integer.parseInt(kv[1]); } else if ("set0".equals(key) || "set1".equals(key) || "set2".equals(key) || "set3".equals(key) || "set4".equals(key) || "set5".equals(key) || "set6".equals(key) || "set7".equals(key) || "set8".equals(key)) { From f6746365ffe283ce73011a0ec73f82341ecc8f1f Mon Sep 17 00:00:00 2001 From: swordshine Date: Sat, 2 Mar 2013 08:50:02 +0000 Subject: [PATCH 15/48] - Fixed Soldevi Golem --- res/cardsfolder/s/soldevi_golem.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/cardsfolder/s/soldevi_golem.txt b/res/cardsfolder/s/soldevi_golem.txt index 50d58deb86f..e3641c596f8 100644 --- a/res/cardsfolder/s/soldevi_golem.txt +++ b/res/cardsfolder/s/soldevi_golem.txt @@ -4,7 +4,7 @@ Types:Artifact Creature Golem PT:5/3 K:CARDNAME doesn't untap during your untap step. T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | OptionalDecider$ You | Execute$ TrigUntap | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your upkeep, you may untap target tapped creature an opponent controls. If you do, untap CARDNAME. -SVar:TrigUntap:AB$ Untap | Cost$ 0 | ValidTgts$ Creature.| SubAbility$ DBCleanup+tapped | TgtPrompt$ Select target tapped creature an opponent controls | SubAbility$ DBUntap +SVar:TrigUntap:AB$ Untap | Cost$ 0 | ValidTgts$ Creature.OppCtrl+tapped | TgtPrompt$ Select target tapped creature an opponent controls | SubAbility$ DBUntap SVar:DBUntap:DB$ Untap | Defined$ Self SVar:RemAIDeck:True SVar:Rarity:Uncommon From 06f252b2e462d4cc51f8e1f323bdb0a6c9b4bfc7 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 2 Mar 2013 09:21:25 +0000 Subject: [PATCH 16/48] PlayArea is intialized with a r/o list that is a reference to all cards in given zone. --- src/main/java/forge/gui/GuiDisplayUtil.java | 88 ------------------ .../gui/match/nonsingleton/CCommand.java | 7 +- .../forge/gui/match/nonsingleton/CField.java | 4 +- .../gui/match/nonsingleton/VCommand.java | 3 +- .../forge/gui/match/nonsingleton/VField.java | 2 +- src/main/java/forge/view/arcane/PlayArea.java | 89 ++++++++++++++++++- 6 files changed, 94 insertions(+), 99 deletions(-) diff --git a/src/main/java/forge/gui/GuiDisplayUtil.java b/src/main/java/forge/gui/GuiDisplayUtil.java index 3c0012d13cc..cd601122daa 100644 --- a/src/main/java/forge/gui/GuiDisplayUtil.java +++ b/src/main/java/forge/gui/GuiDisplayUtil.java @@ -18,7 +18,6 @@ package forge.gui; import java.awt.Color; -import java.awt.Rectangle; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.FileInputStream; @@ -61,8 +60,6 @@ import forge.game.zone.ZoneType; import forge.item.CardDb; import forge.item.CardPrinted; import forge.item.IPaperCard; -import forge.view.arcane.PlayArea; -import forge.view.arcane.util.Animation; /** *

@@ -255,91 +252,6 @@ public final class GuiDisplayUtil { } - /** - *

- * setupPlayZone. - *

- * - * @param p - * a {@link forge.view.arcane.PlayArea} object. - * @param c - * an array of {@link forge.Card} objects. - */ - public static void setupPlayZone(final PlayArea p, final List c) { - List tmp, diff; - tmp = new ArrayList(); - for (final forge.view.arcane.CardPanel cpa : p.getCardPanels()) { - tmp.add(cpa.getGameCard()); - } - diff = new ArrayList(tmp); - diff.removeAll(c); - if (diff.size() == p.getCardPanels().size()) { - p.clear(); - } else { - for (final Card card : diff) { - p.removeCardPanel(p.getCardPanel(card.getUniqueNumber())); - } - } - diff = new ArrayList(c); - diff.removeAll(tmp); - - List panelList = new ArrayList(); - for (final Card card : diff) { - panelList.add(p.addCard(card)); - } - if (!diff.isEmpty()) { - p.doLayout(); - } - for (final forge.view.arcane.CardPanel toPanel : panelList) { - p.scrollRectToVisible(new Rectangle(toPanel.getCardX(), toPanel.getCardY(), toPanel - .getCardWidth(), toPanel.getCardHeight())); - Animation.moveCard(toPanel); - } - - for (final Card card : c) { - final forge.view.arcane.CardPanel toPanel = p.getCardPanel(card.getUniqueNumber()); - if (card.isTapped()) { - toPanel.setTapped(true); - toPanel.setTappedAngle(forge.view.arcane.CardPanel.TAPPED_ANGLE); - } else { - toPanel.setTapped(false); - toPanel.setTappedAngle(0); - } - toPanel.getAttachedPanels().clear(); - if (card.isEnchanted()) { - final ArrayList enchants = card.getEnchantedBy(); - for (final Card e : enchants) { - final forge.view.arcane.CardPanel cardE = p.getCardPanel(e.getUniqueNumber()); - if (cardE != null) { - toPanel.getAttachedPanels().add(cardE); - } - } - } - - if (card.isEquipped()) { - final ArrayList enchants = card.getEquippedBy(); - for (final Card e : enchants) { - final forge.view.arcane.CardPanel cardE = p.getCardPanel(e.getUniqueNumber()); - if (cardE != null) { - toPanel.getAttachedPanels().add(cardE); - } - } - } - - if (card.isEnchantingCard()) { - toPanel.setAttachedToPanel(p.getCardPanel(card.getEnchantingCard().getUniqueNumber())); - } else if (card.isEquipping()) { - toPanel.setAttachedToPanel(p.getCardPanel(card.getEquipping().get(0).getUniqueNumber())); - } else { - toPanel.setAttachedToPanel(null); - } - - toPanel.setCard(toPanel.getGameCard()); - } - p.invalidate(); - p.repaint(); - } - /** *

* updateGUI. diff --git a/src/main/java/forge/gui/match/nonsingleton/CCommand.java b/src/main/java/forge/gui/match/nonsingleton/CCommand.java index e7bf41f086a..0e19f4339c2 100644 --- a/src/main/java/forge/gui/match/nonsingleton/CCommand.java +++ b/src/main/java/forge/gui/match/nonsingleton/CCommand.java @@ -29,9 +29,7 @@ import forge.Card; import forge.Command; import forge.game.player.Player; -import forge.game.zone.PlayerZone; import forge.game.zone.ZoneType; -import forge.gui.GuiDisplayUtil; import forge.gui.framework.ICDoc; import forge.gui.match.CMatchUI; import forge.gui.match.controllers.CMessage; @@ -55,8 +53,7 @@ public class CCommand implements ICDoc { private final Observer observerPlay = new Observer() { @Override public void update(final Observable a, final Object b) { - final PlayerZone pZone = (PlayerZone) a; - GuiDisplayUtil.setupPlayZone(CCommand.this.view.getTabletop(), pZone.getCards(false)); + CCommand.this.view.getTabletop().setupPlayZone(); } }; @@ -118,7 +115,7 @@ public class CCommand implements ICDoc { if (c != null && c.isInZone(ZoneType.Command)) { //TODO: Cast commander/activate avatar/roll planar dice here. - CMessage.SINGLETON_INSTANCE.getInputControl().getInput().selectCard(c); + CMessage.SINGLETON_INSTANCE.getInputControl().selectCard(c, player.getZone(ZoneType.Command)); } } diff --git a/src/main/java/forge/gui/match/nonsingleton/CField.java b/src/main/java/forge/gui/match/nonsingleton/CField.java index 0d62d09c590..2e14f5e8dae 100644 --- a/src/main/java/forge/gui/match/nonsingleton/CField.java +++ b/src/main/java/forge/gui/match/nonsingleton/CField.java @@ -50,7 +50,6 @@ import forge.game.zone.PlayerZone; import forge.game.zone.ZoneType; import forge.gui.ForgeAction; import forge.gui.GuiChoose; -import forge.gui.GuiDisplayUtil; import forge.gui.framework.ICDoc; import forge.gui.match.CMatchUI; import forge.gui.match.controllers.CMessage; @@ -147,8 +146,7 @@ public class CField implements ICDoc { private final Observer observerPlay = new Observer() { @Override public void update(final Observable a, final Object b) { - final PlayerZone pZone = (PlayerZone) a; - GuiDisplayUtil.setupPlayZone(CField.this.view.getTabletop(), pZone.getCards(false)); + CField.this.view.getTabletop().setupPlayZone(); } }; diff --git a/src/main/java/forge/gui/match/nonsingleton/VCommand.java b/src/main/java/forge/gui/match/nonsingleton/VCommand.java index b4dc3be18ac..17711a00c6c 100644 --- a/src/main/java/forge/gui/match/nonsingleton/VCommand.java +++ b/src/main/java/forge/gui/match/nonsingleton/VCommand.java @@ -23,6 +23,7 @@ import javax.swing.border.MatteBorder; import net.miginfocom.swing.MigLayout; import forge.game.player.Player; +import forge.game.zone.ZoneType; import forge.gui.framework.DragCell; import forge.gui.framework.DragTab; import forge.gui.framework.EDocID; @@ -66,7 +67,7 @@ public class VCommand implements IVDoc { // TODO player is hard-coded into tabletop...should be dynamic // (haven't looked into it too deeply). Doublestrike 12-04-12 - tabletop = new PlayArea(scroller, id0 == EDocID.COMMAND_0); + tabletop = new PlayArea(scroller, id0 == EDocID.COMMAND_0, player.getZone(ZoneType.Command).getCards(false)); control = new CCommand(player, this); diff --git a/src/main/java/forge/gui/match/nonsingleton/VField.java b/src/main/java/forge/gui/match/nonsingleton/VField.java index bfc435f4828..1efc4e95d9f 100644 --- a/src/main/java/forge/gui/match/nonsingleton/VField.java +++ b/src/main/java/forge/gui/match/nonsingleton/VField.java @@ -121,7 +121,7 @@ public class VField implements IVDoc { // TODO player is hard-coded into tabletop...should be dynamic // (haven't looked into it too deeply). Doublestrike 12-04-12 - tabletop = new PlayArea(scroller, id0 == EDocID.FIELD_1); + tabletop = new PlayArea(scroller, id0 == EDocID.FIELD_1, player.getZone(ZoneType.Battlefield).getCards(false)); control = new CField(player, this, playerViewer); diff --git a/src/main/java/forge/view/arcane/PlayArea.java b/src/main/java/forge/view/arcane/PlayArea.java index 3b878e19d3f..b15772cdd1b 100644 --- a/src/main/java/forge/view/arcane/PlayArea.java +++ b/src/main/java/forge/view/arcane/PlayArea.java @@ -27,6 +27,7 @@ import java.util.List; import javax.swing.JScrollPane; import forge.Card; +import forge.view.arcane.util.Animation; import forge.view.arcane.util.CardPanelMouseListener; /** @@ -65,6 +66,8 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen private int extraCardSpacingX, cardSpacingX, cardSpacingY; private int stackSpacingX, stackSpacingY; + private List model; + /** *

* Constructor for PlayArea. @@ -76,10 +79,11 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen * a boolean. * @param modelRef */ - public PlayArea(final JScrollPane scrollPane, final boolean mirror) { + public PlayArea(final JScrollPane scrollPane, final boolean mirror, List modelRef) { super(scrollPane); this.setBackground(Color.white); this.mirror = mirror; + this.model = modelRef; } private final CardStackRow collectAllLands() { @@ -478,6 +482,89 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen super.mouseLeftClicked(panel, evt); } + /** + *

+ * setupPlayZone. + *

+ * + * @param newList + * an array of {@link forge.Card} objects. + */ + public void setupPlayZone() { + List oldCards, toDelete; + oldCards = new ArrayList(); + for (final CardPanel cpa : getCardPanels()) { + oldCards.add(cpa.getGameCard()); + } + toDelete = new ArrayList(oldCards); + toDelete.removeAll(model); + if (toDelete.size() == getCardPanels().size()) { + clear(); + } else { + for (final Card card : toDelete) { + removeCardPanel(getCardPanel(card.getUniqueNumber())); + } + } + + List toAdd = new ArrayList(model); + toAdd.removeAll(oldCards); + + List newPanels = new ArrayList(); + for (final Card card : toAdd) { + newPanels.add(addCard(card)); + } + if (!toAdd.isEmpty()) { + doLayout(); + } + for (final CardPanel toPanel : newPanels) { + scrollRectToVisible(new Rectangle(toPanel.getCardX(), toPanel.getCardY(), toPanel.getCardWidth(), toPanel.getCardHeight())); + Animation.moveCard(toPanel); + } + + for (final Card card : model) { + final CardPanel toPanel = getCardPanel(card.getUniqueNumber()); + if (card.isTapped()) { + toPanel.setTapped(true); + toPanel.setTappedAngle(forge.view.arcane.CardPanel.TAPPED_ANGLE); + } else { + toPanel.setTapped(false); + toPanel.setTappedAngle(0); + } + toPanel.getAttachedPanels().clear(); + if (card.isEnchanted()) { + final ArrayList enchants = card.getEnchantedBy(); + for (final Card e : enchants) { + final forge.view.arcane.CardPanel cardE = getCardPanel(e.getUniqueNumber()); + if (cardE != null) { + toPanel.getAttachedPanels().add(cardE); + } + } + } + + if (card.isEquipped()) { + final ArrayList enchants = card.getEquippedBy(); + for (final Card e : enchants) { + final forge.view.arcane.CardPanel cardE = getCardPanel(e.getUniqueNumber()); + if (cardE != null) { + toPanel.getAttachedPanels().add(cardE); + } + } + } + + if (card.isEnchantingCard()) { + toPanel.setAttachedToPanel(getCardPanel(card.getEnchantingCard().getUniqueNumber())); + } else if (card.isEquipping()) { + toPanel.setAttachedToPanel(getCardPanel(card.getEquipping().get(0).getUniqueNumber())); + } else { + toPanel.setAttachedToPanel(null); + } + + toPanel.setCard(toPanel.getGameCard()); + } + invalidate(); + repaint(); + } + private static enum RowType { Land, Creature, From 95e7428ad00a6a50906759198578789d6fb38c7c Mon Sep 17 00:00:00 2001 From: moomarc Date: Sat, 2 Mar 2013 11:15:25 +0000 Subject: [PATCH 17/48] - Added an AI svar to Hecatomb --- res/cardsfolder/h/hecatomb.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/res/cardsfolder/h/hecatomb.txt b/res/cardsfolder/h/hecatomb.txt index f9f7d6166d1..b2faa648ee3 100644 --- a/res/cardsfolder/h/hecatomb.txt +++ b/res/cardsfolder/h/hecatomb.txt @@ -8,6 +8,8 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:X:Remembered$Amount A:AB$ DealDamage | Cost$ tapXType<1/Swamp> | ValidTgts$ Creature,Player | TgtPrompt$ Select target creature or player | NumDmg$ 1 | SpellDescription$ CARDNAME deals 1 damage to target creature or player. SVar:RemAIDeck:True +SVar:NeedsToPlayVar:Creats GE4 +SVar:Creats:Count$Valid Creature.YouCtrl SVar:Rarity:Rare SVar:Picture:http://www.wizards.com/global/images/magic/general/hecatomb.jpg SetInfo:5ED|Rare|http://magiccards.info/scans/en/5e/29.jpg From ff079efed58e7d3c1e6a56e04665dbbdf86aeb86 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sat, 2 Mar 2013 12:15:03 +0000 Subject: [PATCH 18/48] - Updated some AI SVars. --- res/cardsfolder/e/eureka.txt | 1 + res/cardsfolder/g/grisly_spectacle.txt | 1 - res/cardsfolder/h/hypergenesis.txt | 1 + res/cardsfolder/r/ratcatcher.txt | 1 - 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/cardsfolder/e/eureka.txt b/res/cardsfolder/e/eureka.txt index 720b8c0ae59..eb67b5629fb 100644 --- a/res/cardsfolder/e/eureka.txt +++ b/res/cardsfolder/e/eureka.txt @@ -15,6 +15,7 @@ SVar:NumPlayerGiveup:Number$0 SVar:TotalPlayer:PlayerCountPlayers$Amount SVar:CheckHand:Count$ValidHand Permanent.IsNotRemembered+RememberedPlayerCtrl SVar:RemAIDeck:True +SVar:RemRandomDeck:True SVar:Picture:http://www.wizards.com/global/images/magic/general/eureka.jpg SetInfo:LEG|Rare|http://magiccards.info/scans/en/lg/99.jpg Oracle:Starting with you, each player may put a permanent card from his or her hand onto the battlefield. Repeat this process until no one puts a card onto the battlefield. diff --git a/res/cardsfolder/g/grisly_spectacle.txt b/res/cardsfolder/g/grisly_spectacle.txt index 5f8ce043b74..0bcbb7a9ff7 100644 --- a/res/cardsfolder/g/grisly_spectacle.txt +++ b/res/cardsfolder/g/grisly_spectacle.txt @@ -4,7 +4,6 @@ Types:Instant A:SP$ Destroy | Cost$ 2 B B | ValidTgts$ Creature.nonArtifact | TgtPrompt$ Select target nonartifact creature | SubAbility$ DBMill | SpellDescription$ Destroy target nonartifact creature. Its controller puts a number of cards equal to that creature's power from the top of his or her library into his or her graveyard. SVar:DBMill:DB$ Mill | NumCards$ X | Defined$ TargetedController | References$ X SVar:X:Targeted$CardPower -SVar:RemAIDeck:True SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/grisly_spectacle.jpg SetInfo:GTC|Common|http://magiccards.info/scans/en/gtc/66.jpg diff --git a/res/cardsfolder/h/hypergenesis.txt b/res/cardsfolder/h/hypergenesis.txt index c61b183ebfc..94ca133900b 100644 --- a/res/cardsfolder/h/hypergenesis.txt +++ b/res/cardsfolder/h/hypergenesis.txt @@ -16,6 +16,7 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:NumPlayerGiveup:Number$0 SVar:TotalPlayer:PlayerCountPlayers$Amount SVar:CheckHand:Count$ValidHand Artifact.IsNotRemembered+RememberedPlayerCtrl,Creature.IsNotRemembered+RememberedPlayerCtrl,Enchantment.IsNotRemembered+RememberedPlayerCtrl,Land.IsNotRemembered+RememberedPlayerCtrl +SVar:RemRandomDeck:True SVar:RemAIDeck:True SVar:Picture:http://www.wizards.com/global/images/magic/general/hypergenesis.jpg SetInfo:TSP|Rare|http://magiccards.info/scans/en/ts/201.jpg diff --git a/res/cardsfolder/r/ratcatcher.txt b/res/cardsfolder/r/ratcatcher.txt index 993629d14e4..735558d4c4f 100644 --- a/res/cardsfolder/r/ratcatcher.txt +++ b/res/cardsfolder/r/ratcatcher.txt @@ -6,7 +6,6 @@ PT:4/4 K:Fear T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | OptionalDecider$ You | Execute$ TrigChange | TriggerDescription$ At the beginning of your upkeep, you may search your library for a Rat card, reveal it, and put it into your hand. If you do, shuffle your library. SVar:TrigChange:AB$ChangeZone | Cost$ 0 | Origin$ Library | Destination$ Hand | ChangeType$ Card.Rat | ChangeNum$ 1 -SVar:RemRandomDeck:True SVar:Rarity:Rare SVar:Picture:http://www.wizards.com/global/images/magic/general/ratcatcher.jpg SetInfo:DIS|Rare|http://magiccards.info/scans/en/di/52.jpg From 613dd2bac1086838475b78413ddb882c3b0e42ea Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 2 Mar 2013 12:17:12 +0000 Subject: [PATCH 19/48] compare with zero in a more delicate way --- src/main/java/forge/card/cost/Cost.java | 2 +- src/main/java/forge/card/mana/ManaCost.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/forge/card/cost/Cost.java b/src/main/java/forge/card/cost/Cost.java index c1355b6324b..7bc61487139 100644 --- a/src/main/java/forge/card/cost/Cost.java +++ b/src/main/java/forge/card/cost/Cost.java @@ -78,7 +78,7 @@ public class Cost { * @return a boolean. */ public final boolean hasNoManaCost() { - return this.getTotalMana().toString().equals(ManaCost.ZERO.toString()); + return this.getTotalMana().isZero(); } /** diff --git a/src/main/java/forge/card/mana/ManaCost.java b/src/main/java/forge/card/mana/ManaCost.java index 200bbec7044..2fab180f2ab 100644 --- a/src/main/java/forge/card/mana/ManaCost.java +++ b/src/main/java/forge/card/mana/ManaCost.java @@ -183,6 +183,10 @@ public final class ManaCost implements Comparable { return this.shards.isEmpty() && !this.isNoCost(); } + public boolean isZero() { + return genericCost == 0 && isPureGeneric(); + } + /* * (non-Javadoc) * From 846507ef40787d61481939d74d31de9fe229a41c Mon Sep 17 00:00:00 2001 From: Sloth Date: Sat, 2 Mar 2013 12:29:46 +0000 Subject: [PATCH 20/48] - Prevented playSpellAbilities from creating infinite loops. --- src/main/java/forge/game/ai/AiInputCommon.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/forge/game/ai/AiInputCommon.java b/src/main/java/forge/game/ai/AiInputCommon.java index 391ebad1b06..a4ec0dbaa2b 100644 --- a/src/main/java/forge/game/ai/AiInputCommon.java +++ b/src/main/java/forge/game/ai/AiInputCommon.java @@ -162,7 +162,9 @@ public class AiInputCommon extends Input { sa = computer.getSpellAbilityToPlay(); if ( sa == null ) break; //System.out.println("Playing sa: " + sa); - ComputerUtil.handlePlayingSpellAbility(player, sa, game); + if (!ComputerUtil.handlePlayingSpellAbility(player, sa, game)) { + break; + } } while ( sa != null ); } From 8310172ffb7959b86b22dd2fc37006f38845676a Mon Sep 17 00:00:00 2001 From: Sloth Date: Sat, 2 Mar 2013 12:34:38 +0000 Subject: [PATCH 21/48] - Fixed AttachAI not checking Sacrifice or Life Costs. --- src/main/java/forge/card/ability/ai/AttachAi.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/forge/card/ability/ai/AttachAi.java b/src/main/java/forge/card/ability/ai/AttachAi.java index f8623031015..17903ae8c6a 100644 --- a/src/main/java/forge/card/ability/ai/AttachAi.java +++ b/src/main/java/forge/card/ability/ai/AttachAi.java @@ -25,6 +25,7 @@ import forge.card.spellability.SpellAbility; import forge.card.spellability.Target; import forge.card.staticability.StaticAbility; import forge.game.ai.ComputerUtilCard; +import forge.game.ai.ComputerUtilCost; import forge.game.ai.ComputerUtilMana; import forge.game.phase.CombatUtil; import forge.game.phase.PhaseHandler; @@ -46,7 +47,13 @@ public class AttachAi extends SpellAbilityAi { final Card source = sa.getSourceCard(); if (abCost != null) { - // No Aura spells have Additional Costs + // AI currently disabled for these costs + if (!ComputerUtilCost.checkSacrificeCost(ai, abCost, source)) { + return false; + } + if (!ComputerUtilCost.checkLifeCost(ai, abCost, source, 4, null)) { + return false; + } } // prevent run-away activations - first time will always return true From 481e142be7e294766b5eb3aad5c5352159b24a6b Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 2 Mar 2013 13:26:00 +0000 Subject: [PATCH 22/48] - Cleared out the changes.txt file, now ready for new material. --- CHANGES.txt | 215 ++-------------------------------------------------- README.txt | 21 +++++ 2 files changed, 28 insertions(+), 208 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 67d47ffd57f..21e9ab0e7ff 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,217 +1,32 @@ -Forge Beta: 03-01-2013 ver 1.3.9 +Forge Beta: 03-##-2013 ver 1.3.10 -12193 cards in total. +12### cards in total. Release Notes: -You can now cast cards for it's miracle cost without getting a crash. Blocking with a creature was not resetting after combat and this would prevent this creature from blocking in subsequent turns, now fixed. -Work continues on the quest worlds format and a new world based on Ravnica is coming along nicely. - -Added a 'copy to clipboard' button on WinLose screen so players can easily copy the game log. - -Find-as-you-type is now implemented for Deck Editor tables. Just start typing while the table has focus and the next card with a matching string in its name will be highlighted. If more than one card matches, hit Enter to select the next matching card. A popup panel will appear with the search string so you know what you are searching for. If no cards match the string, the string will be highlighted in red. Normally, if you hit the spacebar while a card is selected in one table, the card will be moved to the other table (catalog/deck). When the popup is displayed, space characters are interpreted as part of the search string. Find-as-you-type mode is automatically exited after 5 seconds of inactivity, or hit Escape to exit find-as-you-type mode immediately. - -The Deck Editor has also gained some hotkey and context menu abilities. R-click on a card (or a group of selected cards) for a list of actions and keyboard shortcuts. In particular, you can now transfer cards 4 at a time using the keyboard and interact with the sideboard from anywhere. Also remember that you can jump to the other table with the arrow keys and jump to the text filter with ctrl/cmd+f. From the text filter, you can jump down to the tables by pressing enter. - -In recent weeks people had noticed that the computer was picking the weakest cards in Draft mode rather than the strongest cards. This left the AI with a draft mode deck that was suboptimal. The computer should now pick the strongest cards rather than the weakest cards. - -Work was also done on making the UI more keyboard-friendly. For example, the OK button should now stay focused during matches, so you can advance through the stages by hitting Enter without having to go over and click the button all the time. If you find the button is losing focus, please report it as a bug. - -Gatecrash Guild Sealed game mode has been added. To use it, start a new Sealed Mode Game, select "Block / Set" and "Gatecrash Guild Sealed". Select the first (default) configuration in the "Choose Set Combination" dialog, and when asked to pick your boosters, choose the guild you want twice (once for the guild-specific booster, and then for the extra promo cards). -The following cards are not included in the guild boosters of this game mode because they are not currently implemented in Forge: Bane Alley Broker, Bioshift, Killing Glare, Simic Manipulator. - -All Traditional sets are now up to 85% complete. Standard Format is supported at 99.19%. We are now at under 800 unsupported cards that are missing from Forge. - -A person reported "Love the game but I seem to be having a problem using a draft pool to start a quest. It works for sealed for me but when I select the draft deck option it's always blank even if I have one or several drafts completed." This should now be fixed and draft decks should now show up in quest start combobox. - -Several of the exiting sound files were changed and a handful of new sounds were added to the /res/sound/ folder. - -Our snapshot and beta releases should now display the correct SVN revision number in the title bar. This should allow people to file a bug report with the correct SVN revision number. New Cards: -Archery Training -Aurelia's Fury -Aven Shrine -Barrin's Spite -Battletide Alchemist -Bioshift -Blind Seer -Blinding Powder -Bloom Tender -Bomb Squad -Bounty of the Hunt -Builder's Bane -Cabal Shrine -Cannibalize -Cephalid Shrine -Chant of Vitu-Ghazi -Chaoslace -Charm Peddler -Circle of Despair -Cleansing Meditation -Common Cause -Conflagrate -Conjurer's Ban -Cornered Market -Covenant of Minds -Crashing Boars -Crush Underfoot -Cryptic Gateway -Deathlace -Deepwood Elder -Desecrator Hag -Disruption Aura -Duplicity -Dwarven Shrine -Eight-and-a-Half-Tails -Embolden -Endemic Plague -Epochrasite -Ersatz Gnomes -Eye for an Eye -Eye of Singularity -Eye of Yawgmoth -Feint -Fiery Bombardment -Fiery Justice -Fire and Brimstone -Fire Covenant -Flash -Flickerform -Forbidden Crypt -Forked Lightning -Frostwielder -Game Preserve -Gargantuan Gorilla -Ghosts of the Innocent -Glamer Spinners -Guard Dogs -Hail of Arrows -Heartseeker -Heroic Defiance -Hint of Insanity -Holistic Wisdom -Infectious Rage -Infernal Harvest -Invoke Prejudice -Jaded Response -Jaws of Stone -Killing Glare -Knollspine Invocation -Knowledge Exploitation -Kumano's Blessing -Kumano's Pupils -Kumano, Master Yamabushi -Leonin Bola -Library of Leng -Lifelace -Light from Within -Lightning Dart -Living Inferno -Magmatic Core -Mana Vapors -Marble Priest -Mark of Eviction -Martyr's Cause -Memory Crystal -Meteor Shower -Mirror Golem -Mist of Stagnation -Mist of Stagnation -Moonlace -Moonring Mirror -Nantuko Shrine -Not of This World -Pendrell Flux -Phosphorescent Feast -Phyrexian Purge -Pious Kitsune -Plague Boiler -Planeswalker's Mischief -Pledge of Loyalty -Pollen Remedy -Protean Hulk -Psychic Allergy -Purelace -Purgatory -Quenchable Fire -Rally the Horde -Razia's Purification -Razor Boomerang -Reincarnation -Reins of the Vinesteed -Remedy -Retribution -Reverent Mantra -Reviving Vapors -Reweave -Rite of Ruin -Rock Slide -Rolling Thunder -Sabertooth Cobra -Samite Elder -Sapphire Drake -Searing Rays -Serra's Hymn -Shambling Swarm -Shared Animosity -Shuriken -Simic Guildmage -Sphinx Ambassador -Spike Cannibal -Spoils of War -Struggle for Sanity -Sunforger -Surestrike Trident -Tainted Pact -Takeno, Samurai General -Talara's Bane -Talruum Piper -Temporal Extortion -Thelon of Havenwood -Thought Gorger -Thoughtlace -Thran Tome -Unforge -Vodalian Mystic -Volcanic Wind -Warren Weirding -Winnow -Worldpurge + New Phenomenons: -Chaotic AEther -Planewide Disaster + New Planes: -Aretopolis -Undercity Reaches + New Vanguard Avatars: -Arcanis the Omnipotent Avatar -Bosh, Iron Golem Avatar -Figure of Destiny Avatar -Haakon Stromgald Scourge Avatar -Jaya Ballard Avatar -Maro Avatar -Master of the Wild Hunt Avatar -Necropotence Avatar -Sisters of Stone Death Avatar -Stuffy Doll Avatar -Two Headed Giant of Foriys Avatar -Vampire Nocturnus Avatar -Viridian Zealot Avatar + Known Issues: @@ -222,8 +37,6 @@ Several people have noticed that the cards displayed on the battlefield will fai Some time was spent turning the static ETB triggers into the proper ETB replacement effects they should be, mainly to interact correctly with each other. This work is not yet finished. As a result there is currently some inconsistencies with "Enters the battlefield with counters" (Not incredibly noticeable). -It seems like the front face of double faced cards aren't triggering properly, but the back face and single faced cards are. - A recent contribution to the code base should fix some of the bugs that people noticed with cloning type abilities. At this time there are two remaining issues that we hope will be addressed in the near future. 1. Leave play triggers don't work correct for clones. @@ -240,21 +53,7 @@ Some people use the Windows application 7zip. This utility can be found at http: Contributors to This Release: -Agetian -Asepetci -Foreroes -Gos -Hellfish -Marc -Max -Myk -Rooger -RumbleBBU -Serrasmurf -Sloth -Sol -Swordshine -Chris H + (Quest icons used created by Teekatas, from his Legendora set http://raindropmemory.deviantart.com) diff --git a/README.txt b/README.txt index 0d2827b3215..135b489ca9e 100644 --- a/README.txt +++ b/README.txt @@ -496,6 +496,27 @@ The "Full catalog view" button appears to the left of the "Buy Card" button. Tog Multibuy: By selecting any number of items and hitting space (or selecting the "Buy Card" or "Sell Card" buttons), a player can buy one of everything selected. +Find-as-you-type is now implemented for Deck Editor tables. Just start typing while the table has focus and the next card with a matching string in its name will be highlighted. If more than one card matches, hit Enter to select the next matching card. A popup panel will appear with the search string so you know what you are searching for. If no cards match the string, the string will be highlighted in red. Normally, if you hit the spacebar while a card is selected in one table, the card will be moved to the other table (catalog/deck). When the popup is displayed, space characters are interpreted as part of the search string. Find-as-you-type mode is automatically exited after 5 seconds of inactivity, or hit Escape to exit find-as-you-type mode immediately. + +The Deck Editor has also gained some hotkey and context menu abilities. R-click on a card (or a group of selected cards) for a list of actions and keyboard shortcuts. In particular, you can now transfer cards 4 at a time using the keyboard and interact with the sideboard from anywhere. Also remember that you can jump to the other table with the arrow keys and jump to the text filter with ctrl/cmd+f. From the text filter, you can jump down to the tables by pressing enter. + + +The Game Log: + +Added a 'copy to clipboard' button on WinLose screen so players can easily copy the game log. + + +The UI more keyboard-friendly: + +Work was also done on making the UI more keyboard-friendly. For example, the OK button should now stay focused during matches, so you can advance through the stages by hitting Enter without having to go over and click the button all the time. If you find the button is losing focus, please report it as a bug. + + +Gatecrash Guild Sealed game mode: + +Gatecrash Guild Sealed game mode has been added. To use it, start a new Sealed Mode Game, select "Block / Set" and "Gatecrash Guild Sealed". Select the first (default) configuration in the "Choose Set Combination" dialog, and when asked to pick your boosters, choose the guild you want twice (once for the guild-specific booster, and then for the extra promo cards). + +The following cards are not included in the guild boosters of this game mode because they are not currently implemented in Forge: Bane Alley Broker, Bioshift, Killing Glare, Simic Manipulator. + Our Lawyers Made Us Do This: From 74cc5de83f965c2b5c4a0ccbe54be37d7a8cdc7b Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 2 Mar 2013 13:27:24 +0000 Subject: [PATCH 23/48] - Added new card names to changes.txt. --- CHANGES.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 21e9ab0e7ff..985c4d0c695 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -11,7 +11,10 @@ Release Notes: New Cards: - +Dimensional Breach +Lim-Dul's Vault +Eureka +Hypergenesis New Phenomenons: @@ -21,7 +24,8 @@ New Phenomenons: New Planes: - +Feeding Grounds +Horizon Boughs New Vanguard Avatars: From 7b54bc2718dedb4506c16ee4f909e0e4ebb636f5 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sat, 2 Mar 2013 14:05:28 +0000 Subject: [PATCH 24/48] - Fixed "You may have CARDNAME assign its combat damage as though it weren't blocked." messing around when the AI is blocking. --- src/main/java/forge/game/ai/ComputerUtilCombat.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/forge/game/ai/ComputerUtilCombat.java b/src/main/java/forge/game/ai/ComputerUtilCombat.java index 557f8102d9c..f9ac54c0223 100644 --- a/src/main/java/forge/game/ai/ComputerUtilCombat.java +++ b/src/main/java/forge/game/ai/ComputerUtilCombat.java @@ -1648,13 +1648,13 @@ public class ComputerUtilCombat { public static Map distributeAIDamage(final Card attacker, final List block, int dmgCanDeal, GameEntity defender) { Map damageMap = new HashMap(); - if (attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.") - || attacker.hasKeyword("CARDNAME assigns its combat damage as though it weren't blocked.")) { + boolean isAttacking = defender != null; + + if (isAttacking && (attacker.hasKeyword("You may have CARDNAME assign its combat damage as though it weren't blocked.") + || attacker.hasKeyword("CARDNAME assigns its combat damage as though it weren't blocked."))) { damageMap.put(null, dmgCanDeal); return damageMap; } - - boolean isAttacking = defender != null; final boolean hasTrample = attacker.hasKeyword("Trample"); From 050df94e49aa113d27f9e8d85778f9f200d7c6a0 Mon Sep 17 00:00:00 2001 From: Sol Date: Sat, 2 Mar 2013 14:46:14 +0000 Subject: [PATCH 25/48] - Restore accidentally removed hardcoded Temporal Aperture --- .../cardfactory/CardFactoryArtifacts.java | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/src/main/java/forge/card/cardfactory/CardFactoryArtifacts.java b/src/main/java/forge/card/cardfactory/CardFactoryArtifacts.java index 3851f04a5a1..2fd9dca9477 100644 --- a/src/main/java/forge/card/cardfactory/CardFactoryArtifacts.java +++ b/src/main/java/forge/card/cardfactory/CardFactoryArtifacts.java @@ -3,10 +3,15 @@ package forge.card.cardfactory; import java.util.ArrayList; import java.util.List; +import javax.swing.JOptionPane; + import forge.Card; +import forge.Command; import forge.Singletons; import forge.card.cost.Cost; +import forge.card.mana.ManaCost; +import forge.card.spellability.Ability; import forge.card.spellability.AbilityActivated; import forge.card.spellability.Target; import forge.control.input.Input; @@ -193,5 +198,126 @@ class CardFactoryArtifacts { ability.setStackDescription(sbStack.toString()); card.addSpellAbility(ability); } // *************** END ************ END ************************** + + + // *************** START *********** START ************************** + else if (cardName.equals("Temporal Aperture")) { + /* + * 5, Tap: Shuffle your library, then reveal the top card. Until end + * of turn, for as long as that card remains on top of your library, + * play with the top card of your library revealed and you may play + * that card without paying its mana cost. (If it has X in its mana + * cost, X is 0.) + */ + final Card[] topCard = new Card[1]; + + final Ability freeCast = new Ability(card, ManaCost.ZERO) { + + @Override + public boolean canPlay() { + final PlayerZone lib = card.getController().getZone(ZoneType.Library); + return super.canPlay() && ((lib.size() > 0) && lib.get(0).equals(topCard[0])); + } + + @Override + public void resolve() { + final Card freeCard = topCard[0]; + final Player player = card.getController(); + if (freeCard != null) { + if (freeCard.isLand()) { + if (player.canPlayLand(freeCard)) { + player.playLand(freeCard); + } else { + JOptionPane.showMessageDialog(null, "You can't play any more lands this turn.", "", + JOptionPane.INFORMATION_MESSAGE); + } + } else { + Singletons.getModel().getGame().getActionPlay().playCardWithoutManaCost(freeCard, player); + } + } else { + final StringBuilder sb = new StringBuilder(); + sb.append("Error in ").append(cardName).append(". freeCard is null"); + JOptionPane.showMessageDialog(null, sb.toString(), "", JOptionPane.INFORMATION_MESSAGE); + } + + } + + @Override + public boolean canPlayAI() { + return false; + } + + }; + freeCast.setDescription("Play the previously revealed top card of your library for free."); + final StringBuilder sb = new StringBuilder(); + sb.append(cardName).append(" - play card without paying its mana cost."); + freeCast.setStackDescription(sb.toString()); + + class AbilityTemporalAperture extends AbilityActivated { + public AbilityTemporalAperture(final Card ca, final Cost co, final Target t) { + super(ca, co, t); + } + + @Override + public AbilityActivated getCopy() { + AbilityActivated res = new AbilityTemporalAperture(getSourceCard(), + getPayCosts(), getTarget() == null ? null : new Target(getTarget())); + CardFactoryUtil.copySpellAbility(this, res); + return res; + } + + private static final long serialVersionUID = -7328518969488588777L; + + @Override + public void resolve() { + final PlayerZone lib = card.getController().getZone(ZoneType.Library); + if (lib.size() > 0) { + + // shuffle your library + card.getController().shuffle(); + + // reveal the top card + topCard[0] = lib.get(0); + final StringBuilder sb = new StringBuilder(); + sb.append("Revealed card:\n").append(topCard[0].getName()); + JOptionPane.showMessageDialog(null, sb.toString(), card.getName(), JOptionPane.PLAIN_MESSAGE); + + card.addSpellAbility(freeCast); + card.addExtrinsicKeyword("Play with the top card of your library revealed."); + Singletons.getModel().getGame().getEndOfTurn().addUntil(new Command() { + private static final long serialVersionUID = -2860753262177388046L; + + @Override + public void execute() { + card.removeSpellAbility(freeCast); + card.removeExtrinsicKeyword("Play with the top card of your library revealed."); + } + }); + } + } // resolve + + @Override + public boolean canPlayAI() { + return false; + } + } + + final Cost abCost = new Cost(card, "5 T", true); + final AbilityActivated ability = new AbilityTemporalAperture(card, abCost, null); + + final StringBuilder sbStack = new StringBuilder(); + sbStack.append(card).append(" - Shuffle your library, then reveal the top card."); + ability.setStackDescription(sbStack.toString()); + + final StringBuilder sbDesc = new StringBuilder(); + sbDesc.append(abCost).append("Shuffle your library, then reveal the top card. "); + sbDesc.append("Until end of turn, for as long as that card remains on top of your "); + sbDesc.append("library, play with the top card of your library revealed "); + sbDesc.append("and you may play that card without paying its mana cost. "); + sbDesc.append("(If it has X in its mana cost, X is 0.)"); + ability.setDescription(sbDesc.toString()); + + card.addSpellAbility(ability); + } // *************** END ************ END ************************** } } From 888ab412f7f41aa0a25856d5a869b517c285b64a Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 2 Mar 2013 15:23:04 +0000 Subject: [PATCH 26/48] card layout code was leaving too big gaps between cards --- src/main/java/forge/view/arcane/PlayArea.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/forge/view/arcane/PlayArea.java b/src/main/java/forge/view/arcane/PlayArea.java index b15772cdd1b..62acf479920 100644 --- a/src/main/java/forge/view/arcane/PlayArea.java +++ b/src/main/java/forge/view/arcane/PlayArea.java @@ -214,6 +214,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen while (deltaCardWidth > 0) { List template = tryArrangePilesOfWidth(lands, tokens, creatures, others); + //System.out.println(template == null ? "won't fit" : "Fits @ " + cardWidth + " !!! " + template.toString()); deltaCardWidth = (getCardWidth() - lastGoodCardWidth) / 2; if (template != null) { @@ -258,6 +259,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen int x = 0; int y = PlayArea.GUTTER_Y; + //System.out.println("-------- " + (mirror ? "^" : "_") + " (Positioning ) Card width = " + cardWidth + ". Playarea = " + playAreaWidth + " x " + playAreaHeight ); for (final CardStackRow row : template) { int rowBottom = 0; x = PlayArea.GUTTER_X; @@ -277,10 +279,11 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen this.setComponentZOrder(panel, panelIndex); final int panelX = x + (stackPosition * this.stackSpacingX); final int panelY = y + (stackPosition * this.stackSpacingY); + //System.out.println("... placinng " + panel.getCard() + " @ (" + panelX + ", " + panelY + ")" ); panel.setCardBounds(panelX, panelY, this.getCardWidth(), this.cardHeight); } rowBottom = Math.max(rowBottom, y + stack.getHeight()); - x += stack.getWidth() + cardSpacingX; + x += stack.getWidth(); } y = rowBottom; } @@ -291,6 +294,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen int afterFirstRow; + //System.out.println( "======== " + ( mirror ? "^" : "_" ) + " (try arrange) Card width = " + cardWidth + ". PlayArea = " + playAreaWidth + " x " + playAreaHeight + " ========"); boolean landsFit, tokensFit, creaturesFit; if (this.mirror) { // Wrap all creatures and lands. @@ -354,13 +358,13 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen // card width. final boolean isMinimalSize = this.getCardWidth() == this.getCardWidthMin(); -// System.err.format("[%d] @ %d - Repaint playarea - %s %n", new Date().getTime(), cntRepaints++, mirror ? "MIRROR" : "DIRECT"); - CardStackRow currentRow = new CardStackRow(); for (final CardStack stack : sourceRow) { final int rowWidth = currentRow.getWidth(); + final int stackWidth = stack.getWidth(); + //System.out.printf("Adding %s (+%dpx), current row is %dpx and has %s \n", stack, stackWidth, rowWidth, currentRow ); // If the row is not empty and this stack doesn't fit, add the row. - if (rowWidth + stack.getWidth() > this.playAreaWidth && !currentRow.isEmpty() ) { + if (rowWidth + stackWidth > this.playAreaWidth && !currentRow.isEmpty() ) { // Stop processing if the row is too wide or tall. if (rowWidth > this.playAreaWidth || this.getRowsHeight(template) + sourceRow.getHeight() > this.playAreaHeight) { @@ -388,6 +392,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen template.add(insertIndex, currentRow); } else return false; } + //System.out.println("... row complete! " + currentRow.getWidth() + "px"); return true; } @@ -409,6 +414,7 @@ public class PlayArea extends CardPanelContainer implements CardPanelMouseListen private int planOthersRow(final List sourceRow, final int firstPile, final List template, final CardStackRow rowToFill) { int rowWidth = rowToFill.getWidth(); + // System.out.println("This row has:" + rowToFill + "; want to add:" + sourceRow ); for (int i = firstPile; i < sourceRow.size(); i++ ) { CardStack stack = sourceRow.get(i); From 8ecdd641b31e687a248ca0bf6fa72296657a41e8 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 2 Mar 2013 15:40:53 +0000 Subject: [PATCH 27/48] reverting 19970 as it must have ruined all those ETB effects --- src/main/java/forge/control/input/InputBlock.java | 1 - src/main/java/forge/control/input/InputCleanup.java | 1 - src/main/java/forge/control/input/InputMulligan.java | 3 +-- src/main/java/forge/control/input/InputPassPriority.java | 1 - src/main/java/forge/game/ai/AiInputCommon.java | 1 - 5 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/forge/control/input/InputBlock.java b/src/main/java/forge/control/input/InputBlock.java index d28f60d2cc1..108013f8e63 100644 --- a/src/main/java/forge/control/input/InputBlock.java +++ b/src/main/java/forge/control/input/InputBlock.java @@ -106,7 +106,6 @@ public class InputBlock extends Input { currentAttacker = null; allBlocking.clear(); - stop(); FControl.SINGLETON_INSTANCE.getPlayer().getController().passPriority(); } } diff --git a/src/main/java/forge/control/input/InputCleanup.java b/src/main/java/forge/control/input/InputCleanup.java index 808a940efe3..a478cca5575 100644 --- a/src/main/java/forge/control/input/InputCleanup.java +++ b/src/main/java/forge/control/input/InputCleanup.java @@ -59,7 +59,6 @@ public class InputCleanup extends Input { // goes to the next phase if (active.isUnlimitedHandSize() || n <= max || n <= 0 || active != turnOwner) { active.getController().passPriority(); - stop(); return; } ButtonUtil.disableAll(); diff --git a/src/main/java/forge/control/input/InputMulligan.java b/src/main/java/forge/control/input/InputMulligan.java index ef7d36e8d7d..85c82714684 100644 --- a/src/main/java/forge/control/input/InputMulligan.java +++ b/src/main/java/forge/control/input/InputMulligan.java @@ -174,12 +174,11 @@ public class InputMulligan extends Input { next.initPlane(); } - //Set Field shown to current player. + //Set Field shown to current player. VField nextField = CMatchUI.SINGLETON_INSTANCE.getFieldViewFor(next); SDisplayUtil.showTab(nextField); game.getPhaseHandler().nextPhase(); - stop(); } @Override diff --git a/src/main/java/forge/control/input/InputPassPriority.java b/src/main/java/forge/control/input/InputPassPriority.java index 80d02562045..77ce4595bb0 100644 --- a/src/main/java/forge/control/input/InputPassPriority.java +++ b/src/main/java/forge/control/input/InputPassPriority.java @@ -75,7 +75,6 @@ public class InputPassPriority extends Input { @Override public final void selectButtonOK() { FControl.SINGLETON_INSTANCE.getPlayer().getController().passPriority(); - stop(); } /** {@inheritDoc} */ diff --git a/src/main/java/forge/game/ai/AiInputCommon.java b/src/main/java/forge/game/ai/AiInputCommon.java index a4ec0dbaa2b..5276194e4f0 100644 --- a/src/main/java/forge/game/ai/AiInputCommon.java +++ b/src/main/java/forge/game/ai/AiInputCommon.java @@ -108,7 +108,6 @@ public class AiInputCommon extends Input { } } player.getController().passPriority(); - stop(); } // getMessage(); /** From 46d290ae02bc2ea7865297c7a137bff0beafd936 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sat, 2 Mar 2013 16:12:48 +0000 Subject: [PATCH 28/48] - Real fix for chooseSacrificeType. --- src/main/java/forge/card/cost/Cost.java | 1 - src/main/java/forge/game/ai/ComputerUtil.java | 14 ++++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/forge/card/cost/Cost.java b/src/main/java/forge/card/cost/Cost.java index 7bc61487139..70176025dc7 100644 --- a/src/main/java/forge/card/cost/Cost.java +++ b/src/main/java/forge/card/cost/Cost.java @@ -373,7 +373,6 @@ public class Cost { } public final CostPartMana getCostMana() { - // TODO: Change where ChangeCost happens for (final CostPart part : this.costParts) { if (part instanceof CostPartMana) { return (CostPartMana) part; diff --git a/src/main/java/forge/game/ai/ComputerUtil.java b/src/main/java/forge/game/ai/ComputerUtil.java index ed0074b056a..4820a5e2c87 100644 --- a/src/main/java/forge/game/ai/ComputerUtil.java +++ b/src/main/java/forge/game/ai/ComputerUtil.java @@ -425,14 +425,16 @@ public class ComputerUtil { int count = 0; while (count < amount) { - final Card prefCard = ComputerUtil.getCardPreference(ai, source, "SacCost", typeList); - if (prefCard != null) { - sacList.add(prefCard); - typeList.remove(prefCard); - count++; - } else { + Card prefCard = ComputerUtil.getCardPreference(ai, source, "SacCost", typeList); + if (prefCard == null) { + prefCard = ComputerUtilCard.getWorstAI(typeList); + } + if (prefCard == null) { return null; } + sacList.add(prefCard); + typeList.remove(prefCard); + count++; } return sacList; } From 04efd635542d82170e807a5c86423347c0ac45a5 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sat, 2 Mar 2013 16:46:28 +0000 Subject: [PATCH 29/48] - Fixed UnlessCosts not always setting activating players (fixes Scythe Tiger). --- src/main/java/forge/card/ability/AbilityUtils.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/forge/card/ability/AbilityUtils.java b/src/main/java/forge/card/ability/AbilityUtils.java index 26c4617a637..3a2cec6b930 100644 --- a/src/main/java/forge/card/ability/AbilityUtils.java +++ b/src/main/java/forge/card/ability/AbilityUtils.java @@ -1110,6 +1110,8 @@ public class AbilityUtils { if (paid) { unpaidCommand = paidCommand; } + ability.setActivatingPlayer(payer); + ability.setTarget(sa.getTarget()); GameActionUtil.payCostDuringAbilityResolve(payer, ability, cost, paidCommand, unpaidCommand, sa, game); waitForInput = true; // wait for the human input break; // multiple human players are not supported From c79b3d0cd24cc1a4abb6f484b5c16bcaf92fda1b Mon Sep 17 00:00:00 2001 From: Sloth Date: Sat, 2 Mar 2013 19:24:14 +0000 Subject: [PATCH 30/48] - The AI can now use Gruul Charm. --- res/cardsfolder/g/gruul_charm.txt | 2 +- src/main/java/forge/card/ability/ai/ControlGainAi.java | 7 +++++++ src/main/java/forge/card/ability/ai/DamageAllAi.java | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/res/cardsfolder/g/gruul_charm.txt b/res/cardsfolder/g/gruul_charm.txt index 32df38a81eb..817734e9974 100644 --- a/res/cardsfolder/g/gruul_charm.txt +++ b/res/cardsfolder/g/gruul_charm.txt @@ -4,7 +4,7 @@ Types:Instant A:SP$ Charm | Cost$ R G | Choices$ CantBlockEffect,DBGainCtrl,DmgAll | CharmNum$ 1 | SpellDescription$ Choose one - Creatures without flying can't block this turn; or gain control of all permanents you own; or Gruul Charm deals 3 damage to each creature with flying. SVar:CantBlockEffect:DB$ Effect | Name$ Gruul Charm Effect | StaticAbilities$ KWPump | AILogic$ Evasion | SpellDescription$ Creatures without flying can't block this turn. SVar:KWPump:Mode$ Continuous | EffectZone$ Command | AffectedZone$ Battlefield | Affected$ Creature.withoutFlying | AddHiddenKeyword$ CARDNAME can't block. | Description$ Creatures without flying can't block this turn. -SVar:DBGainCtrl:DB$ GainControl | Cost$ R | AllValid$ Permanent.YouOwn | SpellDescription$ Gain control of all permanents you own. +SVar:DBGainCtrl:DB$ GainControl | AllValid$ Permanent.YouOwn | SpellDescription$ Gain control of all permanents you own. SVar:DmgAll:DB$ DamageAll | NumDmg$ 3 | ValidCards$ Creature.withFlying | ValidDescription$ each creature with flying. | SpellDescription$ CARDNAME deals 3 damage to each creature with flying. SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/gruul_charm.jpg diff --git a/src/main/java/forge/card/ability/ai/ControlGainAi.java b/src/main/java/forge/card/ability/ai/ControlGainAi.java index 2d11c84248d..8515e0f8ff4 100644 --- a/src/main/java/forge/card/ability/ai/ControlGainAi.java +++ b/src/main/java/forge/card/ability/ai/ControlGainAi.java @@ -77,6 +77,13 @@ public class ControlGainAi extends SpellAbilityAi { // if Defined, then don't worry about targeting if (tgt == null) { + if (sa.hasParam("AllValid")) { + List tgtCards = ai.getOpponent().getCardsIn(ZoneType.Battlefield); + tgtCards = AbilityUtils.filterListByType(tgtCards, sa.getParam("AllValid"), sa); + if (tgtCards.isEmpty()) { + return false; + } + } return true; } else { tgt.resetTargets(); diff --git a/src/main/java/forge/card/ability/ai/DamageAllAi.java b/src/main/java/forge/card/ability/ai/DamageAllAi.java index 27477bb4c06..6a8ea75c1ef 100644 --- a/src/main/java/forge/card/ability/ai/DamageAllAi.java +++ b/src/main/java/forge/card/ability/ai/DamageAllAi.java @@ -91,7 +91,7 @@ public class DamageAllAi extends SpellAbilityAi { } int minGain = 200; // The minimum gain in destroyed creatures - if (sa.getPayCosts().isReusuableResource()) { + if (sa.getPayCosts() != null && sa.getPayCosts().isReusuableResource()) { minGain = 100; } From 099c1ed11c82393608b8e522e0074ed521b8adf1 Mon Sep 17 00:00:00 2001 From: Maxmtg Date: Sat, 2 Mar 2013 20:23:46 +0000 Subject: [PATCH 31/48] Changing new input setup. A special thread will set up new input to actual state. This will eliminate the longest stack traces --- .gitattributes | 2 +- .../ability/effects/RestartGameEffect.java | 2 +- .../forge/control/input/InputControl.java | 25 ++- src/main/java/forge/game/GameNew.java | 151 ++++++++++-------- src/main/java/forge/game/MatchController.java | 7 +- .../gui/{GuiInput.java => InputProxy.java} | 30 ++-- .../forge/gui/match/controllers/CMessage.java | 6 +- 7 files changed, 125 insertions(+), 98 deletions(-) rename src/main/java/forge/gui/{GuiInput.java => InputProxy.java} (69%) diff --git a/.gitattributes b/.gitattributes index d0cd306df1e..a2d664be4c6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14220,9 +14220,9 @@ src/main/java/forge/gui/GuiChoose.java -text src/main/java/forge/gui/GuiDialog.java -text src/main/java/forge/gui/GuiDisplayUtil.java svneol=native#text/plain src/main/java/forge/gui/GuiImportPicture.java svneol=native#text/plain -src/main/java/forge/gui/GuiInput.java svneol=native#text/plain src/main/java/forge/gui/GuiProgressBarWindow.java svneol=native#text/plain src/main/java/forge/gui/GuiUtils.java svneol=native#text/plain +src/main/java/forge/gui/InputProxy.java svneol=native#text/plain src/main/java/forge/gui/ListChooser.java svneol=native#text/plain src/main/java/forge/gui/MultiLineLabel.java svneol=native#text/plain src/main/java/forge/gui/MultiLineLabelUI.java svneol=native#text/plain diff --git a/src/main/java/forge/card/ability/effects/RestartGameEffect.java b/src/main/java/forge/card/ability/effects/RestartGameEffect.java index a4d60190aae..91fa1d8ccaa 100644 --- a/src/main/java/forge/card/ability/effects/RestartGameEffect.java +++ b/src/main/java/forge/card/ability/effects/RestartGameEffect.java @@ -48,7 +48,7 @@ public class RestartGameEffect extends SpellAbilityEffect { playerLibraries.put(p, newLibrary); } - GameNew.restartGame(game, sa.getActivatingPlayer(), playerLibraries); + GameNew.restartGame(Singletons.getModel().getMatch(), game, sa.getActivatingPlayer(), playerLibraries); } /* (non-Javadoc) diff --git a/src/main/java/forge/control/input/InputControl.java b/src/main/java/forge/control/input/InputControl.java index 83a3def162e..01cccb60cbf 100644 --- a/src/main/java/forge/control/input/InputControl.java +++ b/src/main/java/forge/control/input/InputControl.java @@ -25,6 +25,7 @@ import forge.game.phase.PhaseType; import forge.game.player.Player; import forge.game.player.PlayerController; import forge.game.zone.MagicStack; +import forge.gui.match.controllers.CMessage; import forge.util.MyObservable; /** @@ -65,7 +66,7 @@ public class InputControl extends MyObservable implements java.io.Serializable { */ public final void setInput(final Input in) { boolean isInputEmpty = this.input == null || this.input instanceof InputPassPriority; - System.out.println(in.getClass().getName()); + //System.out.println(in.getClass().getName()); if (!this.game.getStack().isResolving() && isInputEmpty) { this.input = in; } else { @@ -134,12 +135,9 @@ public class InputControl extends MyObservable implements java.io.Serializable { * @param update * a boolean. */ - public final void resetInput() { resetInput(true); } - public final void resetInput(final boolean update) { + public final void resetInput() { this.input = null; - if (update) { - this.updateObservers(); - } + this.updateObservers(); } /** @@ -244,4 +242,19 @@ public class InputControl extends MyObservable implements java.io.Serializable { return pc.getDefaultInput(); } // getInput() + public final void setNewInput(GameState game) { + PhaseHandler ph = game.getPhaseHandler(); + + final Input tmp = getActualInput(); + //String message = String.format("%s's %s, priority of %s [%sP] input is %s", ph.getPlayerTurn(), ph.getPhase(), ph.getPriorityPlayer(), ph.isPlayerPriorityAllowed() ? "+" : "-", tmp == null ? "null" : tmp.getClass().getSimpleName()); + //System.out.println(message); + if (tmp != null) { + //System.out.println(ph.getPlayerTurn() + "'s " + ph.getPhase() + ", priority of " + ph.getPriorityPlayer() + " @ input is " + tmp.getClass().getName() ); + CMessage.SINGLETON_INSTANCE.getInputControl().setInput(tmp); + } else if (!ph.isPlayerPriorityAllowed()) { + // System.out.println("cannot have priority, forced to pass"); + ph.getPriorityPlayer().getController().passPriority(); + } + } + } // InputControl diff --git a/src/main/java/forge/game/GameNew.java b/src/main/java/forge/game/GameNew.java index f0ad3c3b15d..e80a1fa73c2 100644 --- a/src/main/java/forge/game/GameNew.java +++ b/src/main/java/forge/game/GameNew.java @@ -11,8 +11,6 @@ import java.util.Set; import javax.swing.JOptionPane; - - import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.Iterables; @@ -25,11 +23,13 @@ import forge.CardUtil; import forge.Singletons; import forge.card.trigger.TriggerHandler; import forge.card.trigger.TriggerType; +import forge.control.input.Input; import forge.control.input.InputControl; import forge.control.input.InputMulligan; import forge.deck.Deck; import forge.deck.CardPool; import forge.deck.DeckSection; +import forge.error.BugReporter; import forge.game.event.FlipCoinEvent; import forge.game.phase.PhaseHandler; import forge.game.phase.PhaseType; @@ -38,9 +38,11 @@ import forge.game.player.LobbyPlayer; import forge.game.player.Player; import forge.game.zone.PlayerZone; import forge.game.zone.ZoneType; +import forge.gui.match.controllers.CMessage; import forge.gui.match.views.VAntes; import forge.item.CardPrinted; import forge.item.IPaperCard; +import forge.properties.ForgePreferences; import forge.properties.ForgePreferences.FPref; import forge.util.Aggregates; import forge.util.MyRandom; @@ -50,6 +52,45 @@ import forge.util.MyRandom; * All of these methods can and should be static. */ public class GameNew { + + /** + * TODO: Write javadoc for this type. + * + */ + public static final class GameInputUpdatesThread extends Thread { + private final MatchController match; + private final GameState game; + private boolean wasChangedRecently; + + /** + * TODO: Write javadoc for Constructor. + * @param match + * @param game + */ + public GameInputUpdatesThread(MatchController match, GameState game) { + this.match = match; + this.game = game; + } + + public void run(){ + while(!game.isGameOver()) { + boolean needsNewInput = CMessage.SINGLETON_INSTANCE.getInputControl().isValid() == false; + if ( needsNewInput ) { + match.getInput().setNewInput(game); + wasChangedRecently = true; + } + try { + Thread.sleep(wasChangedRecently ? 2 : 40); + wasChangedRecently = false; + } catch (InterruptedException e) { + BugReporter.reportException(e); + break; + } + } + } + } + + public static final ForgePreferences preferences = Singletons.getModel().getPreferences(); private static void preparePlayerLibrary(Player player, final ZoneType zoneType, CardPool secion, boolean canRandomFoil, Random generator) { PlayerZone library = player.getZone(zoneType); @@ -60,7 +101,7 @@ public class GameNew { final Card card = cardPrinted.toForgeCard(player); // apply random pictures for cards - if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_CARD_ART)) { + if (preferences.getPrefBoolean(FPref.UI_RANDOM_CARD_ART)) { final int cntVariants = cardPrinted.getRules().getEditionInfo(cardPrinted.getEdition()).getCopiesCount(); if (cntVariants > 1) { card.setRandomPicture(generator.nextInt(cntVariants - 1) + 1); @@ -86,8 +127,8 @@ public class GameNew { * TODO: Accept something like match state as parameter. Match should be aware of players, * their decks and other special starting conditions. */ - public static void newGame(final Map playersConditions, final GameState game, final boolean canRandomFoil) { - Singletons.getModel().getMatch().getInput().clearInput(); + public static void newGame(final MatchController match, final Map playersConditions, final GameState game, final boolean canRandomFoil) { + match.getInput().clearInput(); Card.resetUniqueNumber(); // need this code here, otherwise observables fail @@ -97,7 +138,7 @@ public class GameNew { trigHandler.clearDelayedTrigger(); // friendliness - boolean useAnte = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE); + boolean useAnte = preferences.getPrefBoolean(FPref.UI_ANTE); final Set rAICards = new HashSet(); Map> removedAnteCards = new HashMap>(); @@ -112,8 +153,8 @@ public class GameNew { initVariantsZones(player, psc); - GameType gameType = Singletons.getModel().getMatch().getGameType(); - boolean isFirstGame = Singletons.getModel().getMatch().getPlayedGames().isEmpty(); + GameType gameType = match.getGameType(); + boolean isFirstGame = match.getPlayedGames().isEmpty(); boolean hasSideboard = psc.getOriginalDeck().has(DeckSection.Sideboard); boolean canSideBoard = !isFirstGame && gameType.isSideboardingAllowed() && hasSideboard; @@ -132,7 +173,7 @@ public class GameNew { preparePlayerLibrary(player, ZoneType.Sideboard, myDeck.get(DeckSection.Sideboard), canRandomFoil, generator); // Shuffling - if (player instanceof AIPlayer && Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_SMOOTH_LAND)) { + if (player instanceof AIPlayer && preferences.getPrefBoolean(FPref.UI_SMOOTH_LAND)) { // AI may do this instead of shuffling its deck final Iterable c1 = GameNew.smoothComputerManaCurve(player.getCardsIn(ZoneType.Library)); player.getZone(ZoneType.Library).setCards(c1); @@ -174,7 +215,7 @@ public class GameNew { JOptionPane.showMessageDialog(null, ante.toString(), "", JOptionPane.INFORMATION_MESSAGE); } - GameNew.actuateGame(game, false); + GameNew.actuateGame(match, game, false); } private static void initVariantsZones(final Player player, final PlayerStartConditions psc) { @@ -243,8 +284,7 @@ public class GameNew { } // ultimate of Karn the Liberated - public static void restartGame(final GameState game, final Player startingTurn, Map> playerLibraries) { - MatchController match = Singletons.getModel().getMatch(); + public static void restartGame(final MatchController match, final GameState game, final Player startingTurn, Map> playerLibraries) { Map players = match.getPlayers(); Map playersConditions = new HashMap(); @@ -291,7 +331,7 @@ public class GameNew { PhaseHandler phaseHandler = game.getPhaseHandler(); phaseHandler.setPlayerTurn(startingTurn); - GameNew.actuateGame(game, true); + GameNew.actuateGame(match, game, true); } /** @@ -302,10 +342,10 @@ public class GameNew { * newGame, then when all is ready, call this function. * @param isRestartedGame Whether the actuated game is the first start or a restart */ - private static void actuateGame(final GameState game, boolean isRestartedGame) { + private static void actuateGame(final MatchController match, final GameState game, boolean isRestartedGame) { if (!isRestartedGame) { // Deciding which cards go to ante - if (Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_ANTE)) { + if (preferences.getPrefBoolean(FPref.UI_ANTE)) { final String nl = System.getProperty("line.separator"); final StringBuilder msg = new StringBuilder(); for (final Player p : game.getPlayers()) { @@ -324,15 +364,24 @@ public class GameNew { JOptionPane.showMessageDialog(null, msg, "Ante", JOptionPane.INFORMATION_MESSAGE); } - GameOutcome lastGameOutcome = Singletons.getModel().getMatch().getLastGameOutcome(); + GameOutcome lastGameOutcome = match.getLastGameOutcome(); // Only cut/coin toss if it's the first game of the match - if (lastGameOutcome == null) { - GameNew.seeWhoPlaysFirstDice(); + Player goesFirst; + Player humanPlayer = Singletons.getControl().getPlayer(); + boolean isFirstGame = lastGameOutcome == null; + if (isFirstGame) { + goesFirst = GameNew.seeWhoPlaysFirstDice(game); } else { - Player human = Singletons.getControl().getPlayer(); - Player goesFirst = lastGameOutcome.isWinner(human.getLobbyPlayer()) ? human.getOpponent() : human; - setPlayersFirstTurn(goesFirst, false); + + goesFirst = lastGameOutcome.isWinner(humanPlayer.getLobbyPlayer()) ? humanPlayer.getOpponent() : humanPlayer; } + String message = goesFirst + ( isFirstGame ? " has won the coin toss." : " lost the last game."); + boolean willPlay = goesFirst.getController().getWillPlayOnFirstTurn(message); + if ( goesFirst != humanPlayer ) { + JOptionPane.showMessageDialog(null, message + "\nComputer Going First", "You are drawing", JOptionPane.INFORMATION_MESSAGE); + } + goesFirst = willPlay ? goesFirst : goesFirst.getOpponent(); + game.getPhaseHandler().setPlayerTurn(goesFirst); } // Draw cards @@ -340,9 +389,20 @@ public class GameNew { p.drawCards(p.getMaxHandSize()); } + + game.getPhaseHandler().setPhaseState(PhaseType.MULLIGAN); - InputControl control = Singletons.getModel().getMatch().getInput(); - control.setInput(new InputMulligan()); + + InputControl control = match.getInput(); + Input tmp = new InputMulligan(); + control.setInput(tmp); + + + Thread thGame = new GameInputUpdatesThread(match, game); + + match.getInput().getInput().showMessage(); + thGame.setName("Game input updater"); + thGame.start(); } // newGame() private static String buildFourColumnList(String firstLine, Iterable cAnteRemoved) { @@ -418,49 +478,14 @@ public class GameNew { *

* seeWhoPlaysFirstCoinToss. *

+ * @return */ - private static void seeWhoPlaysFirstDice() { - int playerDie = 0; - int computerDie = 0; - - while (playerDie == computerDie) { - playerDie = MyRandom.getRandom().nextInt(20); - computerDie = MyRandom.getRandom().nextInt(20); - } - + private static Player seeWhoPlaysFirstDice(final GameState game) { // Play the Flip Coin sound - Singletons.getModel().getGame().getEvents().post(new FlipCoinEvent()); + game.getEvents().post(new FlipCoinEvent()); - List allPlayers = Singletons.getModel().getGame().getPlayers(); - setPlayersFirstTurn(allPlayers.get(MyRandom.getRandom().nextInt(allPlayers.size())), true); + List allPlayers = game.getPlayers(); + return allPlayers.get(MyRandom.getRandom().nextInt(allPlayers.size())); } - private static void setPlayersFirstTurn(Player goesFirst, boolean firstGame) { - StringBuilder sb = new StringBuilder(goesFirst.toString()); - if (firstGame) { - sb.append(" has won the coin toss."); - } - else { - sb.append(" lost the last game."); - } - if (goesFirst.isHuman()) { - if (!humanPlayOrDraw(sb.toString())) { - goesFirst = goesFirst.getOpponent(); - } - } else { - sb.append("\nComputer Going First"); - JOptionPane.showMessageDialog(null, sb.toString(), "Play or Draw?", JOptionPane.INFORMATION_MESSAGE); - } - Singletons.getModel().getGame().getPhaseHandler().setPlayerTurn(goesFirst); - } // seeWhoPlaysFirstDice() - - private static boolean humanPlayOrDraw(String message) { - final String[] possibleValues = { "Play", "Draw" }; - - final Object playDraw = JOptionPane.showOptionDialog(null, message + "\n\nWould you like to play or draw?", - "Play or Draw?", JOptionPane.DEFAULT_OPTION, JOptionPane.INFORMATION_MESSAGE, null, - possibleValues, possibleValues[0]); - - return !playDraw.equals(1); - } } diff --git a/src/main/java/forge/game/MatchController.java b/src/main/java/forge/game/MatchController.java index c3c87c78df6..4f0e9455979 100644 --- a/src/main/java/forge/game/MatchController.java +++ b/src/main/java/forge/game/MatchController.java @@ -19,7 +19,7 @@ import forge.game.player.Player; import forge.game.player.PlayerStatistics; import forge.game.player.PlayerType; import forge.game.zone.ZoneType; -import forge.gui.GuiInput; +import forge.gui.InputProxy; import forge.gui.framework.EDocID; import forge.gui.framework.SDisplayUtil; import forge.gui.match.CMatchUI; @@ -149,8 +149,7 @@ public class MatchController { Singletons.getControl().changeState(FControl.Screens.MATCH_SCREEN); SDisplayUtil.showTab(EDocID.REPORT_LOG.getDoc()); - // set all observers - GuiInput inputControl = CMessage.SINGLETON_INSTANCE.getInputControl(); + InputProxy inputControl = CMessage.SINGLETON_INSTANCE.getInputControl(); input.addObserver(inputControl); currentGame.getStack().addObserver(inputControl); currentGame.getPhaseHandler().addObserver(inputControl); @@ -159,7 +158,7 @@ public class MatchController { // some observers are set in CMatchUI.initMatch final boolean canRandomFoil = Singletons.getModel().getPreferences().getPrefBoolean(FPref.UI_RANDOM_FOIL) && gameType == GameType.Constructed; - GameNew.newGame(startConditions, currentGame, canRandomFoil); + GameNew.newGame(this, startConditions, currentGame, canRandomFoil); // TODO restore this functionality!!! //VMatchUI.SINGLETON_INSTANCE.getViewDevMode().getDocument().setVisible(Preferences.DEV_MODE); diff --git a/src/main/java/forge/gui/GuiInput.java b/src/main/java/forge/gui/InputProxy.java similarity index 69% rename from src/main/java/forge/gui/GuiInput.java rename to src/main/java/forge/gui/InputProxy.java index 787f195b2c1..d767040375b 100644 --- a/src/main/java/forge/gui/GuiInput.java +++ b/src/main/java/forge/gui/InputProxy.java @@ -21,9 +21,7 @@ import java.util.Observable; import java.util.Observer; import forge.Card; -import forge.Singletons; import forge.control.input.Input; -import forge.game.phase.PhaseHandler; import forge.game.player.Player; import forge.game.zone.PlayerZone; import forge.util.MyObservable; @@ -36,28 +34,16 @@ import forge.util.MyObservable; * @author Forge * @version $Id$ */ -public class GuiInput extends MyObservable implements Observer { +public class InputProxy extends MyObservable implements Observer { /** The input. */ private Input input; + private volatile boolean valid = false; - - /** {@inheritDoc} */ @Override public final void update(final Observable observable, final Object obj) { - PhaseHandler ph = Singletons.getModel().getGame().getPhaseHandler(); - - final Input tmp = Singletons.getModel().getMatch().getInput().getActualInput(); - // System.out.println(ph.getPlayerTurn() + "'s " + ph.getPhase() + ", priority of " + ph.getPriorityPlayer() + " @ actual input is " + ( tmp == null ? "null" : tmp.getClass().getName()) + "; MHP = " + ph.mayPlayerHavePriority() ); - if (tmp != null) { - // System.out.println(ph.getPlayerTurn() + "'s " + ph.getPhase() + ", priority of " + ph.getPriorityPlayer() + " @ input is " + tmp.getClass().getName() ); - this.setInput(tmp); - } else if (!ph.isPlayerPriorityAllowed()) { - //System.out.println("cannot have priority, forced to pass"); - ph.passPriority(); - } + valid = false; } - /** *

* Setter for the field input. @@ -66,9 +52,10 @@ public class GuiInput extends MyObservable implements Observer { * @param in * a {@link forge.control.input.Input} object. */ - private void setInput(final Input in) { + public void setInput(final Input in) { + valid = true; this.input = in; - this.input.showMessage(); + this.input.showMessage(); // this call may invalidate the input by the time it returns } /** @@ -121,10 +108,13 @@ public class GuiInput extends MyObservable implements Observer { return this.getInput().toString(); } - /** @return {@link forge.gui.GuiInput.Input} */ + /** @return {@link forge.gui.InputProxy.Input} */ public Input getInput() { return this.input; } + public boolean isValid() { + return valid; + } } diff --git a/src/main/java/forge/gui/match/controllers/CMessage.java b/src/main/java/forge/gui/match/controllers/CMessage.java index 0e4573e6d5c..ba32802f0b8 100644 --- a/src/main/java/forge/gui/match/controllers/CMessage.java +++ b/src/main/java/forge/gui/match/controllers/CMessage.java @@ -28,7 +28,7 @@ import javax.swing.JButton; import forge.Command; import forge.game.MatchController; -import forge.gui.GuiInput; +import forge.gui.InputProxy; import forge.gui.framework.ICDoc; import forge.gui.framework.SDisplayUtil; import forge.gui.match.views.VMessage; @@ -42,7 +42,7 @@ public enum CMessage implements ICDoc { /** */ SINGLETON_INSTANCE; - private GuiInput inputControl = new GuiInput(); + private InputProxy inputControl = new InputProxy(); private Component lastFocusedButton = null; private final ActionListener actCancel = new ActionListener() { @@ -87,7 +87,7 @@ public enum CMessage implements ICDoc { * * @return GuiInput */ - public GuiInput getInputControl() { + public InputProxy getInputControl() { return this.inputControl; } From 50bc1772d1330f1197b55e36387016f2bff32873 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sat, 2 Mar 2013 20:27:02 +0000 Subject: [PATCH 32/48] - Added some keyword entries to isUsefulAttachKeyword. --- res/cardsfolder/j/jovens_tools.txt | 1 - res/cardsfolder/v/varchilds_crusader.txt | 2 +- src/main/java/forge/card/ability/ai/AttachAi.java | 6 ++++-- src/main/java/forge/card/ability/ai/PumpAiBase.java | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/res/cardsfolder/j/jovens_tools.txt b/res/cardsfolder/j/jovens_tools.txt index 215f8d366df..1687a915830 100644 --- a/res/cardsfolder/j/jovens_tools.txt +++ b/res/cardsfolder/j/jovens_tools.txt @@ -2,7 +2,6 @@ Name:Joven's Tools ManaCost:6 Types:Artifact A:AB$ Pump | Cost$ 4 T | ValidTgts$ Creature | TgtPrompt$ Select target creature | KW$ HIDDEN CARDNAME can't be blocked except by Walls. | SpellDescription$ Target creature can't be blocked this turn except by Walls. -SVar:RemRandomDeck:True SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/jovens_tools.jpg SetInfo:HML|Uncommon|http://magiccards.info/scans/en/hl/133.jpg diff --git a/res/cardsfolder/v/varchilds_crusader.txt b/res/cardsfolder/v/varchilds_crusader.txt index a5fd7f12213..ba6c6e273f6 100644 --- a/res/cardsfolder/v/varchilds_crusader.txt +++ b/res/cardsfolder/v/varchilds_crusader.txt @@ -2,7 +2,7 @@ Name:Varchild's Crusader ManaCost:3 R Types:Creature Human Knight PT:3/2 -A:AB$ Pump | Cost$ 0 | KW$ CARDNAME can't be blocked except by Walls. & HIDDEN At the beginning of the end step, sacrifice CARDNAME. | SpellDescription$ CARDNAME can't be blocked this turn except by Walls. Sacrifice CARDNAME at the beginning of the next end step. +A:AB$ Pump | Cost$ 0 | KW$ HIDDEN CARDNAME can't be blocked except by Walls. & HIDDEN At the beginning of the end step, sacrifice CARDNAME. | SpellDescription$ CARDNAME can't be blocked this turn except by Walls. Sacrifice CARDNAME at the beginning of the next end step. SVar:RemAIDeck:True SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/varchilds_crusader.jpg diff --git a/src/main/java/forge/card/ability/ai/AttachAi.java b/src/main/java/forge/card/ability/ai/AttachAi.java index 17903ae8c6a..8af929b570c 100644 --- a/src/main/java/forge/card/ability/ai/AttachAi.java +++ b/src/main/java/forge/card/ability/ai/AttachAi.java @@ -998,10 +998,12 @@ public class AttachAi extends SpellAbilityAi { if (!CardUtil.isStackingKeyword(keyword) && card.hasKeyword(keyword)) { return false; } - final boolean evasive = (keyword.endsWith("Unblockable") || keyword.equals("Fear") + final boolean evasive = (keyword.equals("Unblockable") || keyword.equals("Fear") || keyword.equals("Intimidate") || keyword.equals("Shadow") || keyword.equals("Flying") || keyword.equals("Horsemanship") - || keyword.endsWith("walk")); + || keyword.endsWith("walk") || keyword.equals("CARDNAME can't be blocked except by Walls.") + || keyword.equals("All creatures able to block CARDNAME do so.") + || keyword.equals("CARDNAME can't be blocked by more than one creature.")); // give evasive keywords to creatures that can attack and deal damage if (evasive) { if (card.getNetCombatDamage() <= 0 diff --git a/src/main/java/forge/card/ability/ai/PumpAiBase.java b/src/main/java/forge/card/ability/ai/PumpAiBase.java index 6d35c7e80b1..c7e8174d045 100644 --- a/src/main/java/forge/card/ability/ai/PumpAiBase.java +++ b/src/main/java/forge/card/ability/ai/PumpAiBase.java @@ -166,7 +166,7 @@ public abstract class PumpAiBase extends SpellAbilityAi { final boolean evasive = (keyword.endsWith("Unblockable") || keyword.endsWith("Fear") || keyword.endsWith("Intimidate") || keyword.endsWith("Shadow") - || keyword.contains("CantBeBlockedBy")); + || keyword.contains("CantBeBlockedBy") || keyword.endsWith("CARDNAME can't be blocked except by Walls.")); final boolean combatRelevant = (keyword.endsWith("First Strike") || keyword.contains("Bushido")); // give evasive keywords to creatures that can or do attack if (evasive) { From 68def26221b849c40b11a7d6f102b57ad7944611 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sun, 3 Mar 2013 08:47:27 +0000 Subject: [PATCH 33/48] - Improved usage of playReusable. --- src/main/java/forge/card/ability/SpellAbilityAi.java | 6 ++++++ src/main/java/forge/card/ability/ai/ChangeZoneAi.java | 2 +- src/main/java/forge/card/ability/ai/CounterAi.java | 4 ++-- src/main/java/forge/card/ability/ai/CountersPutAllAi.java | 2 +- src/main/java/forge/card/ability/ai/LifeLoseAi.java | 2 +- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/forge/card/ability/SpellAbilityAi.java b/src/main/java/forge/card/ability/SpellAbilityAi.java index 9bbd3e0a529..f6451d40f27 100644 --- a/src/main/java/forge/card/ability/SpellAbilityAi.java +++ b/src/main/java/forge/card/ability/SpellAbilityAi.java @@ -84,6 +84,12 @@ public abstract class SpellAbilityAi { if (sa.getRestrictions().getPlaneswalker() && Singletons.getModel().getGame().getPhaseHandler().is(PhaseType.MAIN2)) { return true; } + if (sa.isTrigger()) { + return true; + } + if (sa.isSpell() && !sa.isBuyBackAbility()) { + return false; + } PhaseHandler phase = Singletons.getModel().getGame().getPhaseHandler(); return phase.is(PhaseType.END_OF_TURN) && phase.getNextTurn().equals(ai); diff --git a/src/main/java/forge/card/ability/ai/ChangeZoneAi.java b/src/main/java/forge/card/ability/ai/ChangeZoneAi.java index 703011b7a44..acd6aacbcfc 100644 --- a/src/main/java/forge/card/ability/ai/ChangeZoneAi.java +++ b/src/main/java/forge/card/ability/ai/ChangeZoneAi.java @@ -747,7 +747,7 @@ public class ChangeZoneAi extends SpellAbilityAi { } } // Blink permanents with ETB triggers - else if (sa.isAbility() && (sa.getPayCosts() != null) && SpellAbilityAi.playReusable(ai, sa)) { + else if (SpellAbilityAi.playReusable(ai, sa)) { aiPermanents = CardLists.filter(aiPermanents, new Predicate() { @Override public boolean apply(final Card c) { diff --git a/src/main/java/forge/card/ability/ai/CounterAi.java b/src/main/java/forge/card/ability/ai/CounterAi.java index 3ceda11de74..9e084635dfb 100644 --- a/src/main/java/forge/card/ability/ai/CounterAi.java +++ b/src/main/java/forge/card/ability/ai/CounterAi.java @@ -80,7 +80,7 @@ public class CounterAi extends SpellAbilityAi { if (toPay <= usableManaSources) { // If this is a reusable Resource, feel free to play it most of // the time - if (!sa.getPayCosts().isReusuableResource() || sa.isSpell()) { + if (!SpellAbilityAi.playReusable(ai,sa)) { return false; } } @@ -148,7 +148,7 @@ public class CounterAi extends SpellAbilityAi { if (toPay <= usableManaSources) { // If this is a reusable Resource, feel free to play it most // of the time - if (!sa.getPayCosts().isReusuableResource() || (MyRandom.getRandom().nextFloat() < .4)) { + if (!SpellAbilityAi.playReusable(ai,sa) || (MyRandom.getRandom().nextFloat() < .4)) { return false; } } diff --git a/src/main/java/forge/card/ability/ai/CountersPutAllAi.java b/src/main/java/forge/card/ability/ai/CountersPutAllAi.java index 09ffc91f5d9..d63ac7b9e22 100644 --- a/src/main/java/forge/card/ability/ai/CountersPutAllAi.java +++ b/src/main/java/forge/card/ability/ai/CountersPutAllAi.java @@ -124,7 +124,7 @@ public class CountersPutAllAi extends SpellAbilityAi { } } - if (sa.isTrigger() || sa instanceof AbilitySub || SpellAbilityAi.playReusable(ai, sa)) { + if (SpellAbilityAi.playReusable(ai, sa)) { return chance; } diff --git a/src/main/java/forge/card/ability/ai/LifeLoseAi.java b/src/main/java/forge/card/ability/ai/LifeLoseAi.java index d552c0759d0..86e7a717cc4 100644 --- a/src/main/java/forge/card/ability/ai/LifeLoseAi.java +++ b/src/main/java/forge/card/ability/ai/LifeLoseAi.java @@ -132,7 +132,7 @@ public class LifeLoseAi extends SpellAbilityAi { } boolean randomReturn = r.nextFloat() <= .6667; - if (SpellAbilityAi.playReusable(ai, sa) || priority) { + if (priority || SpellAbilityAi.playReusable(ai, sa)) { randomReturn = true; } From d185e5e3eba91d27d598948e1c9041e984e1e9f8 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sun, 3 Mar 2013 08:55:05 +0000 Subject: [PATCH 34/48] - Updated two isReusable() functions. --- src/main/java/forge/card/cost/CostPutCounter.java | 1 - src/main/java/forge/card/cost/CostReveal.java | 3 +++ src/main/java/forge/card/cost/CostUnattach.java | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/forge/card/cost/CostPutCounter.java b/src/main/java/forge/card/cost/CostPutCounter.java index 5659db410c9..84a6ae0fa21 100644 --- a/src/main/java/forge/card/cost/CostPutCounter.java +++ b/src/main/java/forge/card/cost/CostPutCounter.java @@ -78,7 +78,6 @@ public class CostPutCounter extends CostPartWithList { super(amount, type, description); this.counter = cntr; } - @Override public boolean isReusable() { return true; } diff --git a/src/main/java/forge/card/cost/CostReveal.java b/src/main/java/forge/card/cost/CostReveal.java index 7ad3d877dff..0714f8356a0 100644 --- a/src/main/java/forge/card/cost/CostReveal.java +++ b/src/main/java/forge/card/cost/CostReveal.java @@ -56,6 +56,9 @@ public class CostReveal extends CostPartWithList { super(amount, type, description); } + @Override + public boolean isReusable() { return true; } + /* * (non-Javadoc) * diff --git a/src/main/java/forge/card/cost/CostUnattach.java b/src/main/java/forge/card/cost/CostUnattach.java index 9019077a030..cec1332bbab 100644 --- a/src/main/java/forge/card/cost/CostUnattach.java +++ b/src/main/java/forge/card/cost/CostUnattach.java @@ -45,7 +45,7 @@ public class CostUnattach extends CostPartWithList { public boolean isUndoable() { return false; } @Override - public boolean isReusable() { return false; } + public boolean isReusable() { return true; } /* * (non-Javadoc) From 33b713df93b53fe7d58052d7baf81c3d7bfdff48 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sun, 3 Mar 2013 09:20:27 +0000 Subject: [PATCH 35/48] - Little fix for "AnyNumber" in DiscardEffect.java. --- src/main/java/forge/card/ability/effects/DiscardEffect.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/forge/card/ability/effects/DiscardEffect.java b/src/main/java/forge/card/ability/effects/DiscardEffect.java index 49fd91ea912..27aef564e8f 100644 --- a/src/main/java/forge/card/ability/effects/DiscardEffect.java +++ b/src/main/java/forge/card/ability/effects/DiscardEffect.java @@ -270,7 +270,7 @@ public class DiscardEffect extends RevealEffectBase { List chosen = getDiscardedList(p, dPChHand); for (Card c : chosen) { - dPChHand.remove(chosen); + dPChHand.remove(c); toBeDiscarded.add(c); } } else From f409a66f0138a1ec05e97d98374bf2487ed37e99 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sun, 3 Mar 2013 11:39:42 +0000 Subject: [PATCH 36/48] - Updated some Shandalar world decks. --- .../world/shandalar/duels/Sorcerer 1.dck | 2 +- .../world/shandalar/duels/Sorcerer 2.dck | 2 +- .../world/shandalar/duels/Sorceress 1.dck | 7 +++--- .../world/shandalar/duels/Sorceress 2.dck | 4 ++-- .../world/shandalar/duels/Summoner 3.dck | 8 +++---- .../world/shandalar/duels/Summoner 4.dck | 24 +++++++++---------- .../shandalar/duels/Thought Invoker 3.dck | 6 ++--- .../shandalar/duels/Thought Invoker 4.dck | 11 ++++----- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/res/quest/world/shandalar/duels/Sorcerer 1.dck b/res/quest/world/shandalar/duels/Sorcerer 1.dck index 62370c3947a..4581dd2360c 100644 --- a/res/quest/world/shandalar/duels/Sorcerer 1.dck +++ b/res/quest/world/shandalar/duels/Sorcerer 1.dck @@ -11,6 +11,7 @@ Deck Type=constructed 3 Brass Man|ARN 4 Giant Strength|4ED 4 Goblin Balloon Brigade|4ED +4 Goblin Digging Team|DRK 3 Hurr Jackal|ARN 3 Immolation|LEG 4 Lightning Bolt|2ED @@ -18,5 +19,4 @@ Deck Type=constructed 4 Mons's Goblin Raiders|3ED 20 Mountain|4ED 4 Sisters of the Flame|DRK -4 Winds of Change|4ED [sideboard] diff --git a/res/quest/world/shandalar/duels/Sorcerer 2.dck b/res/quest/world/shandalar/duels/Sorcerer 2.dck index 49e7553ba43..0d5b9fc6d02 100644 --- a/res/quest/world/shandalar/duels/Sorcerer 2.dck +++ b/res/quest/world/shandalar/duels/Sorcerer 2.dck @@ -9,6 +9,7 @@ Deck Type=constructed [main] 3 Ali Baba|ARN 3 Ankh of Mishra|LEB +4 Black Vise|LEB 4 Giant Strength|4ED 4 Goblin Balloon Brigade|4ED 3 Hurr Jackal|ARN @@ -19,5 +20,4 @@ Deck Type=constructed 16 Mountain|4ED 4 Sisters of the Flame|DRK 4 Strip Mine|ATQ -4 Winds of Change|4ED [sideboard] diff --git a/res/quest/world/shandalar/duels/Sorceress 1.dck b/res/quest/world/shandalar/duels/Sorceress 1.dck index 422a54f98b5..211d3be8ad7 100644 --- a/res/quest/world/shandalar/duels/Sorceress 1.dck +++ b/res/quest/world/shandalar/duels/Sorceress 1.dck @@ -7,17 +7,18 @@ Difficulty=easy Description=Pumpable Red weenies with Dwarven Warriors and Meekstone. Deck Type=constructed [main] +1 Artifact Blast|ATQ 3 Ball Lightning|4ED 4 Bird Maiden|ARN -4 Blood Lust|LEG 2 Dragon Whelp|4ED 4 Dwarven Warriors|LEB +1 Eternal Warrior|LEG 4 Firebreathing|4ED 2 Hurloon Minotaur|LEB 4 Hurr Jackal|ARN 3 Iron Star|LEB -2 Meekstone|LEB +4 Meekstone|LEB +4 Mons's Goblin Raiders|3ED 23 Mountain|4ED 2 Shatter|4ED -3 The Brute|LEG [sideboard] diff --git a/res/quest/world/shandalar/duels/Sorceress 2.dck b/res/quest/world/shandalar/duels/Sorceress 2.dck index 7856b4e0b65..90148c128c1 100644 --- a/res/quest/world/shandalar/duels/Sorceress 2.dck +++ b/res/quest/world/shandalar/duels/Sorceress 2.dck @@ -9,7 +9,6 @@ Deck Type=constructed [main] 3 Ball Lightning|4ED 4 Bird Maiden|ARN -4 Blood Lust|LEG 3 Dragon Whelp|4ED 4 Dwarven Warriors|LEB 2 Fire Drake|CHR @@ -17,7 +16,8 @@ Deck Type=constructed 2 Hurloon Minotaur|LEB 4 Hurr Jackal|ARN 3 Iron Star|LEB -2 Meekstone|LEB +2 Lightning Bolt|2ED +4 Meekstone|LEB 23 Mountain|4ED 2 Shatter|4ED [sideboard] diff --git a/res/quest/world/shandalar/duels/Summoner 3.dck b/res/quest/world/shandalar/duels/Summoner 3.dck index 3e27664070b..f68240c94dd 100644 --- a/res/quest/world/shandalar/duels/Summoner 3.dck +++ b/res/quest/world/shandalar/duels/Summoner 3.dck @@ -8,17 +8,17 @@ Description=Big Green creatures with a splash of White. Deck Type=constructed [main] 4 Birds of Paradise|4ED -1 Channel|4ED 2 Colossus of Sardia|4ED 2 Disenchant|4ED 3 Force of Nature|2ED -20 Forest|4ED +16 Forest|4ED 3 Giant Growth|2ED -2 Healing Salve|2ED -3 Holy Strength|2ED +1 Healing Salve|2ED 4 Hurricane|4ED 4 Plains|4ED 4 Radjan Spirit|4ED +4 Savannah|LEB 4 Spirit Link|LEG +4 Swords to Plowshares|LEB 4 War Mammoth|2ED [sideboard] diff --git a/res/quest/world/shandalar/duels/Summoner 4.dck b/res/quest/world/shandalar/duels/Summoner 4.dck index 0ecfc56db1e..1a9d43128d1 100644 --- a/res/quest/world/shandalar/duels/Summoner 4.dck +++ b/res/quest/world/shandalar/duels/Summoner 4.dck @@ -7,23 +7,23 @@ Difficulty=very hard Description=Big Green creatures with a splash of White. Deck Type=constructed [main] -1 Channel|LEB -1 Colossus of Sardia|ATQ +4 Birds of Paradise|4ED 4 Desert Twister|4ED 2 Disenchant|4ED -2 Flying Carpet|ARN 3 Force of Nature|LEB -13 Forest|4ED -3 Giant Growth|2ED -2 Healing Salve|2ED -2 Holy Strength|4ED +11 Forest|4ED 4 Hurricane|4ED 4 Llanowar Elves|2ED -1 Mox Emerald|LEB -1 Mox Pearl|LEB -3 Plains|4ED -3 Radjan Spirit|LEG +1 Mox Emerald|2ED +1 Mox Jet|2ED +1 Mox Pearl|2ED +1 Mox Ruby|2ED +1 Mox Sapphire|2ED +4 Plains|4ED 4 Savannah|LEB -4 Spirit Link|LEG +4 Serra Angel|LEB +1 Sol Ring|LEB +2 Su-Chi|ATQ +4 Swords to Plowshares|LEB 4 War Mammoth|LEB [sideboard] diff --git a/res/quest/world/shandalar/duels/Thought Invoker 3.dck b/res/quest/world/shandalar/duels/Thought Invoker 3.dck index b55da81f231..b1df738c98f 100644 --- a/res/quest/world/shandalar/duels/Thought Invoker 3.dck +++ b/res/quest/world/shandalar/duels/Thought Invoker 3.dck @@ -7,17 +7,17 @@ Difficulty=hard Description=Big Blue fliers and effects to impede opponent's progress. Deck Type=constructed [main] +4 Air Elemental|LEB 2 Control Magic|LEB +3 Counterspell|LEB 2 Energy Flux|4ED -3 Feedback|LEB 4 Ghost Ship|DRK 4 Giant Tortoise|ARN 22 Island|4ED 2 Mahamoti Djinn|LEB -4 Mana Short|LEB 4 Phantom Monster|LEB 4 Power Sink|4ED 4 Psychic Venom|LEB 2 Time Elemental|LEG -3 Twiddle|LEB +3 Unsummon|LEB [sideboard] diff --git a/res/quest/world/shandalar/duels/Thought Invoker 4.dck b/res/quest/world/shandalar/duels/Thought Invoker 4.dck index f84cf559790..f9047729733 100644 --- a/res/quest/world/shandalar/duels/Thought Invoker 4.dck +++ b/res/quest/world/shandalar/duels/Thought Invoker 4.dck @@ -7,19 +7,18 @@ Difficulty=very hard Description=Big Blue fliers and effects to impede opponent's progress. Deck Type=constructed [main] +4 Air Elemental|LEB 1 Ancestral Recall|LEB -2 Control Magic|LEB -2 Energy Flux|4ED +4 Control Magic|LEB 4 Ghost Ship|DRK 4 Giant Tortoise|ARN 22 Island|4ED -2 Mahamoti Djinn|LEB -4 Mana Short|LEB +4 Mahamoti Djinn|LEB +4 Mana Drain|LEG 1 Mox Sapphire|LEB 4 Phantom Monster|LEB 4 Power Sink|4ED -4 Psychic Venom|LEB 1 Sol Ring|LEB 2 Time Elemental|LEG -3 Twiddle|LEB +1 Time Walk|LEB [sideboard] From cd5c3bfa69cf97b89ac2163d7000ee9cd4ecd263 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sun, 3 Mar 2013 11:54:53 +0000 Subject: [PATCH 37/48] - Added the condition "AllTargetsLegal" (untested). --- .../spellability/SpellAbilityCondition.java | 11 +++++++++++ .../spellability/SpellAbilityVariables.java | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/main/java/forge/card/spellability/SpellAbilityCondition.java b/src/main/java/forge/card/spellability/SpellAbilityCondition.java index e6634dfa608..17eeb328e66 100644 --- a/src/main/java/forge/card/spellability/SpellAbilityCondition.java +++ b/src/main/java/forge/card/spellability/SpellAbilityCondition.java @@ -81,6 +81,9 @@ public class SpellAbilityCondition extends SpellAbilityVariables { if (value.equals("Kicked")) { this.setKicked(true); } + if (value.equals("AllTargetsLegal")) { + this.setAllTargetsLegal(true); + } } if (params.containsKey("ConditionZone")) { @@ -196,6 +199,14 @@ public class SpellAbilityCondition extends SpellAbilityVariables { return false; } } + if (this.isAllTargetsLegal()) { + SpellAbility root = sa.getRootAbility(); + for (Card c : root.getTarget().getTargetCards()) { + if (!CardFactoryUtil.isTargetStillValid(sa, c)) { + return false; + } + } + } if (this.isSorcerySpeed() && !activator.canCastSorcery()) { return false; diff --git a/src/main/java/forge/card/spellability/SpellAbilityVariables.java b/src/main/java/forge/card/spellability/SpellAbilityVariables.java index 2a980244160..023d0a1e3f0 100644 --- a/src/main/java/forge/card/spellability/SpellAbilityVariables.java +++ b/src/main/java/forge/card/spellability/SpellAbilityVariables.java @@ -69,6 +69,7 @@ public class SpellAbilityVariables { this.threshold = sav.isThreshold(); this.metalcraft = sav.isThreshold(); this.hellbent = sav.isHellbent(); + this.allTargetsLegal = sav.isAllTargetsLegal(); this.prowl = new ArrayList(sav.getProwl()); this.isPresent = sav.getIsPresent(); this.presentCompare = sav.getPresentCompare(); @@ -136,6 +137,8 @@ public class SpellAbilityVariables { /** The Kicked. */ private boolean kicked = false; + + private boolean allTargetsLegal = false; /** The prowl. */ private ArrayList prowl = new ArrayList(); @@ -519,6 +522,21 @@ public class SpellAbilityVariables { } + /** + * @return the allTargetsLegal + */ + public boolean isAllTargetsLegal() { + return allTargetsLegal; + } + + /** + * @param allTargetsLegal0 the allTargetsLegal to set + */ + public void setAllTargetsLegal(boolean allTargets) { + this.allTargetsLegal = allTargets; + } + + /** *

* Setter for the field prowl. From 9bd3cd6bcb6232c74be70a5216df806c617fec0f Mon Sep 17 00:00:00 2001 From: Sloth Date: Sun, 3 Mar 2013 12:41:22 +0000 Subject: [PATCH 38/48] - Fixed "Defined$ TriggeredCard" returning the LKI copy of the card. --- src/main/java/forge/card/ability/AbilityUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/forge/card/ability/AbilityUtils.java b/src/main/java/forge/card/ability/AbilityUtils.java index 3a2cec6b930..94115041100 100644 --- a/src/main/java/forge/card/ability/AbilityUtils.java +++ b/src/main/java/forge/card/ability/AbilityUtils.java @@ -143,7 +143,6 @@ public class AbilityUtils { final Object crd = root.getTriggeringObject(defined.substring(9)); if (crd instanceof Card) { c = Singletons.getModel().getGame().getCardState((Card) crd); - c = (Card) crd; } else if (crd instanceof List) { for (final Card cardItem : (List) crd) { cards.add(cardItem); From 3c9ee0f01284563a97901e83f0121a4377f96ff3 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sun, 3 Mar 2013 12:55:30 +0000 Subject: [PATCH 39/48] - Fixed Skullclamp not working on tokens. --- src/main/java/forge/game/GameAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/forge/game/GameAction.java b/src/main/java/forge/game/GameAction.java index 97385a0180e..d91fe8c86ca 100644 --- a/src/main/java/forge/game/GameAction.java +++ b/src/main/java/forge/game/GameAction.java @@ -248,7 +248,7 @@ public class GameAction { copied.getCharacteristics().resetCardColor(); } - if (zoneFrom.is(ZoneType.Battlefield)) { + if (zoneFrom.is(ZoneType.Battlefield) && !c.isToken()) { copied.setSuspendCast(false); copied.setState(CardCharacteristicName.Original); // Soulbond unpairing From cb74a3b60e236e10d6a97d1859a7b074c4bf0692 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sun, 3 Mar 2013 13:33:31 +0000 Subject: [PATCH 40/48] - The AI can now use Spirit Guides. --- res/cardsfolder/e/elvish_spirit_guide.txt | 1 - res/cardsfolder/s/shardless_agent.txt | 1 + res/cardsfolder/s/simian_spirit_guide.txt | 1 - src/main/java/forge/game/ai/ComputerUtilMana.java | 1 + 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/res/cardsfolder/e/elvish_spirit_guide.txt b/res/cardsfolder/e/elvish_spirit_guide.txt index 14ea0b282ca..c32d4badb8f 100644 --- a/res/cardsfolder/e/elvish_spirit_guide.txt +++ b/res/cardsfolder/e/elvish_spirit_guide.txt @@ -3,7 +3,6 @@ ManaCost:2 G Types:Creature Elf Spirit PT:2/2 A:AB$ Mana | Cost$ ExileFromHand<1/CARDNAME> | Produced$ G | ActivationZone$ Hand | SpellDescription$ Add G to your mana pool. -SVar:RemAIDeck:True SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/elvish_spirit_guide.jpg SetInfo:ALL|Uncommon|http://magiccards.info/scans/en/ai/69.jpg diff --git a/res/cardsfolder/s/shardless_agent.txt b/res/cardsfolder/s/shardless_agent.txt index 296e93183ed..54a004c6c8e 100644 --- a/res/cardsfolder/s/shardless_agent.txt +++ b/res/cardsfolder/s/shardless_agent.txt @@ -3,6 +3,7 @@ ManaCost:1 G U Types:Artifact Creature Human Rogue PT:2/2 K:Cascade +SVar:PlayMain1:TRUE SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/shardless_agent.jpg SetInfo:PC2|Uncommon|http://magiccards.info/scans/en/pc2/104.jpg diff --git a/res/cardsfolder/s/simian_spirit_guide.txt b/res/cardsfolder/s/simian_spirit_guide.txt index 54aae9e2426..1f8721c8584 100644 --- a/res/cardsfolder/s/simian_spirit_guide.txt +++ b/res/cardsfolder/s/simian_spirit_guide.txt @@ -3,7 +3,6 @@ ManaCost:2 R Types:Creature Ape Spirit PT:2/2 A:AB$ Mana | Cost$ ExileFromHand<1/CARDNAME> | Produced$ R | ActivationZone$ Hand | SpellDescription$ Add R to your mana pool. -SVar:RemAIDeck:True SVar:Rarity:Common SVar:Picture:http://www.wizards.com/global/images/magic/general/simian_spirit_guide.jpg SetInfo:PLC|Common|http://magiccards.info/scans/en/pc/122.jpg diff --git a/src/main/java/forge/game/ai/ComputerUtilMana.java b/src/main/java/forge/game/ai/ComputerUtilMana.java index ef3de857485..c7f4542b3d1 100644 --- a/src/main/java/forge/game/ai/ComputerUtilMana.java +++ b/src/main/java/forge/game/ai/ComputerUtilMana.java @@ -460,6 +460,7 @@ public class ComputerUtilMana { private static List getAvailableMana(final Player ai, final boolean checkPlayable) { final GameState game = Singletons.getModel().getGame(); final List list = ai.getCardsIn(ZoneType.Battlefield); + list.addAll(ai.getCardsIn(ZoneType.Hand)); final List manaSources = CardLists.filter(list, new Predicate() { @Override public boolean apply(final Card c) { From d2911a6f8fd46c677051b2db203f5614f9d40ee4 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sun, 3 Mar 2013 22:27:18 +0000 Subject: [PATCH 41/48] - Improved AI using Show and Tell and Eureka. --- res/cardsfolder/e/eureka.txt | 3 ++- res/cardsfolder/h/hypergenesis.txt | 3 ++- res/cardsfolder/s/show_and_tell.txt | 2 ++ src/main/java/forge/card/ability/ai/ChangeZoneAi.java | 2 -- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/res/cardsfolder/e/eureka.txt b/res/cardsfolder/e/eureka.txt index eb67b5629fb..31eceae5f5c 100644 --- a/res/cardsfolder/e/eureka.txt +++ b/res/cardsfolder/e/eureka.txt @@ -14,8 +14,9 @@ SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:NumPlayerGiveup:Number$0 SVar:TotalPlayer:PlayerCountPlayers$Amount SVar:CheckHand:Count$ValidHand Permanent.IsNotRemembered+RememberedPlayerCtrl -SVar:RemAIDeck:True SVar:RemRandomDeck:True +SVar:NeedsToPlayVar:Y GE1 +SVar:Y:Count$ValidHand Permanent.YouCtrl+cmcGE5 SVar:Picture:http://www.wizards.com/global/images/magic/general/eureka.jpg SetInfo:LEG|Rare|http://magiccards.info/scans/en/lg/99.jpg Oracle:Starting with you, each player may put a permanent card from his or her hand onto the battlefield. Repeat this process until no one puts a card onto the battlefield. diff --git a/res/cardsfolder/h/hypergenesis.txt b/res/cardsfolder/h/hypergenesis.txt index 94ca133900b..2cf2f6651ec 100644 --- a/res/cardsfolder/h/hypergenesis.txt +++ b/res/cardsfolder/h/hypergenesis.txt @@ -17,7 +17,8 @@ SVar:NumPlayerGiveup:Number$0 SVar:TotalPlayer:PlayerCountPlayers$Amount SVar:CheckHand:Count$ValidHand Artifact.IsNotRemembered+RememberedPlayerCtrl,Creature.IsNotRemembered+RememberedPlayerCtrl,Enchantment.IsNotRemembered+RememberedPlayerCtrl,Land.IsNotRemembered+RememberedPlayerCtrl SVar:RemRandomDeck:True -SVar:RemAIDeck:True +SVar:NeedsToPlayVar:Y GE1 +SVar:Y:Count$ValidHand Permanent.YouCtrl+cmcGE5 SVar:Picture:http://www.wizards.com/global/images/magic/general/hypergenesis.jpg SetInfo:TSP|Rare|http://magiccards.info/scans/en/ts/201.jpg Oracle:Sorcery\nSuspend 3- {1}{G}{G} (Rather than cast this card from your hand, pay {1}{G}{G} and exile it with three time counters on it. At the beginning of your upkeep, remove a time counter. When the last is removed, cast it without paying its mana cost.)\nStarting with you, each player may put an artifact, creature, enchantment, or land card from his or her hand onto the battlefield. Repeat this process until no one puts a card onto the battlefield. diff --git a/res/cardsfolder/s/show_and_tell.txt b/res/cardsfolder/s/show_and_tell.txt index ef824c8cc15..67b753e3ca3 100644 --- a/res/cardsfolder/s/show_and_tell.txt +++ b/res/cardsfolder/s/show_and_tell.txt @@ -2,6 +2,8 @@ Name:Show and Tell ManaCost:2 U Types:Sorcery A:SP$ ChangeZone | Cost$ 2 U | Origin$ Hand | Destination$ Battlefield | ChangeType$ Creature,Artifact,Enchantment,Land | DefinedPlayer$ Player | ChangeNum$ 1 | SpellDescription$ Each player may put an artifact, creature, enchantment, or land card from his or her hand onto the battlefield. +SVar:NeedsToPlayVar:Y GE1 +SVar:Y:Count$ValidHand Permanent.YouCtrl+cmcGE4 SVar:Rarity:Rare SVar:Picture:http://www.wizards.com/global/images/magic/general/show_and_tell.jpg SetInfo:USG|Rare|http://magiccards.info/scans/en/us/96.jpg diff --git a/src/main/java/forge/card/ability/ai/ChangeZoneAi.java b/src/main/java/forge/card/ability/ai/ChangeZoneAi.java index acd6aacbcfc..7ae758ddf9c 100644 --- a/src/main/java/forge/card/ability/ai/ChangeZoneAi.java +++ b/src/main/java/forge/card/ability/ai/ChangeZoneAi.java @@ -294,8 +294,6 @@ public class ChangeZoneAi extends SpellAbilityAi { } } - chance &= (r.nextFloat() < .8); - final AbilitySub subAb = sa.getSubAbility(); chance &= subAb == null || subAb.getAi().chkDrawbackWithSubs(ai, subAb); From d2040989f9b84b06d008d999ffa50caf55e59473 Mon Sep 17 00:00:00 2001 From: Sloth Date: Sun, 3 Mar 2013 23:03:24 +0000 Subject: [PATCH 42/48] - Added AI support for Mind Grind. --- .../java/forge/card/ability/ai/DigUntilAi.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/forge/card/ability/ai/DigUntilAi.java b/src/main/java/forge/card/ability/ai/DigUntilAi.java index 9095786cc7d..eb784eac053 100644 --- a/src/main/java/forge/card/ability/ai/DigUntilAi.java +++ b/src/main/java/forge/card/ability/ai/DigUntilAi.java @@ -2,9 +2,12 @@ package forge.card.ability.ai; import java.util.Random; +import forge.Card; import forge.card.ability.SpellAbilityAi; +import forge.card.spellability.AbilitySub; import forge.card.spellability.SpellAbility; import forge.card.spellability.Target; +import forge.game.ai.ComputerUtilMana; import forge.game.player.AIPlayer; import forge.game.player.Player; import forge.game.zone.ZoneType; @@ -14,6 +17,7 @@ public class DigUntilAi extends SpellAbilityAi { @Override protected boolean canPlayAI(AIPlayer ai, SpellAbility sa) { + Card source = sa.getSourceCard(); double chance = .4; // 40 percent chance with instant speed stuff if (SpellAbilityAi.isSorcerySpeed(sa)) { chance = .667; // 66.7% chance for sorcery speed (since it will @@ -36,6 +40,18 @@ public class DigUntilAi extends SpellAbilityAi { libraryOwner = opp; } + final String num = sa.getParam("Amount"); + if ((num != null) && num.equals("X") && source.getSVar(num).equals("Count$xPaid")) { + // Set PayX here to maximum value. + if (!(sa instanceof AbilitySub) || source.getSVar("PayX").equals("")) { + int numCards = ComputerUtilMana.determineLeftoverMana(sa, ai); + if (numCards <= 0) { + return false; + } + source.setSVar("PayX", Integer.toString(numCards)); + } + } + // return false if nothing to dig into if (libraryOwner.getCardsIn(ZoneType.Library).isEmpty()) { return false; From 412e2c990dbf8a2a96712692a80c1b3c0a4b708f Mon Sep 17 00:00:00 2001 From: Sloth Date: Sun, 3 Mar 2013 23:05:16 +0000 Subject: [PATCH 43/48] - Improved the Boromir 4 deck. --- res/quest/duels/Boromir 4.dck | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/res/quest/duels/Boromir 4.dck b/res/quest/duels/Boromir 4.dck index a21d295fd82..6e72a430e45 100644 --- a/res/quest/duels/Boromir 4.dck +++ b/res/quest/duels/Boromir 4.dck @@ -7,7 +7,7 @@ Description=UG Show and Tell deck with huge creatures Icon=Boromir.jpg Deck Type=constructed [main] -4 Misty Rainforest +3 Misty Rainforest 4 Tropical Island 3 Polluted Delta 3 Scalding Tarn @@ -19,6 +19,7 @@ Deck Type=constructed 1 Mox Pearl 1 Mox Ruby 1 Mox Sapphire +1 Sol Ring 1 Ancestral Recall 1 Time Walk 4 Show and Tell @@ -26,7 +27,7 @@ Deck Type=constructed 2 Lure of Prey 2 Defense of the Heart 4 Personal Tutor -1 Autochthon Wurm +1 Worldspine Wurm 4 Empyrial Archangel 3 Woodfall Primus 4 Progenitus From c912f2d28b41f8f0fe470c8307f933ea20c9bda1 Mon Sep 17 00:00:00 2001 From: swordshine Date: Mon, 4 Mar 2013 00:33:10 +0000 Subject: [PATCH 44/48] - Converted Wormfang Turtle to choosecard effect (its triggered ability does not have a target) --- res/cardsfolder/w/wormfang_turtle.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/res/cardsfolder/w/wormfang_turtle.txt b/res/cardsfolder/w/wormfang_turtle.txt index 737dead43d1..3a451757459 100644 --- a/res/cardsfolder/w/wormfang_turtle.txt +++ b/res/cardsfolder/w/wormfang_turtle.txt @@ -2,10 +2,12 @@ Name:Wormfang Turtle ManaCost:2 U Types:Creature Nightmare Turtle Beast PT:2/4 -T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters the battlefield, exile a land you control. +T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigChooseExile | TriggerDescription$ When CARDNAME enters the battlefield, exile a land you control. T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigReturn | TriggerDescription$ When CARDNAME leaves the battlefield, return the exiled card to the battlefield under its owner's control. -SVar:TrigExile:AB$ChangeZone | Cost$ 0 | Origin$ Battlefield | Destination$ Exile | TargetMin$ 1 | ValidTgts$ Land.YouCtrl | TgtPrompt$ Choose target land you control | RememberTargets$ True | ForgetOtherTargets$ True -SVar:TrigReturn:AB$ChangeZone | Cost$ 0 | Defined$ Remembered | Origin$ Exile | Destination$ Battlefield +SVar:TrigChooseExile:AB$ ChooseCard | Cost$ 0 | Choices$ Land.YouCtrl | Mandatory$ True | Amount$ 1 | ChoiceTitle$ Choose a land to exile | SubAbility$ DBExile +SVar:DBExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | Defined$ ChosenCard | RememberChanged$ True +SVar:TrigReturn:AB$ ChangeZone | Cost$ 0 | Defined$ Remembered | Origin$ Exile | Destination$ Battlefield | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:Rarity:Uncommon SVar:Picture:http://www.wizards.com/global/images/magic/general/wormfang_turtle.jpg SetInfo:JUD|Uncommon|http://magiccards.info/scans/en/ju/60.jpg From 7e83d92cd9d7436f26346b3b5751fd5e77cff90c Mon Sep 17 00:00:00 2001 From: swordshine Date: Mon, 4 Mar 2013 00:37:00 +0000 Subject: [PATCH 45/48] - Added Death by Dragons and Carpet of Flowers --- .gitattributes | 2 ++ res/cardsfolder/c/carpet_of_flowers.txt | 18 ++++++++++++++++++ res/cardsfolder/d/death_by_dragons.txt | 8 ++++++++ src/main/java/forge/Card.java | 4 ---- src/main/java/forge/game/player/Player.java | 4 ++++ 5 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 res/cardsfolder/c/carpet_of_flowers.txt create mode 100644 res/cardsfolder/d/death_by_dragons.txt diff --git a/.gitattributes b/.gitattributes index a2d664be4c6..bdc3671daee 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1489,6 +1489,7 @@ res/cardsfolder/c/carnival_hellsteed.txt -text res/cardsfolder/c/carnival_of_souls.txt svneol=native#text/plain res/cardsfolder/c/carnivorous_plant.txt svneol=native#text/plain res/cardsfolder/c/carnophage.txt svneol=native#text/plain +res/cardsfolder/c/carpet_of_flowers.txt -text res/cardsfolder/c/carrier_pigeons.txt svneol=native#text/plain res/cardsfolder/c/carrion.txt svneol=native#text/plain res/cardsfolder/c/carrion_ants.txt svneol=native#text/plain @@ -2387,6 +2388,7 @@ res/cardsfolder/d/deadwood_treefolk.txt svneol=native#text/plain res/cardsfolder/d/dearly_departed.txt -text res/cardsfolder/d/death_baron.txt svneol=native#text/plain res/cardsfolder/d/death_bomb.txt svneol=native#text/plain +res/cardsfolder/d/death_by_dragons.txt -text res/cardsfolder/d/death_charmer.txt svneol=native#text/plain res/cardsfolder/d/death_cloud.txt svneol=native#text/plain res/cardsfolder/d/death_cultist.txt svneol=native#text/plain diff --git a/res/cardsfolder/c/carpet_of_flowers.txt b/res/cardsfolder/c/carpet_of_flowers.txt new file mode 100644 index 00000000000..c5f865847d9 --- /dev/null +++ b/res/cardsfolder/c/carpet_of_flowers.txt @@ -0,0 +1,18 @@ +Name:Carpet of Flowers +ManaCost:G +Types:Enchantment +T:Mode$ Phase | Phase$ Main1,Main2 | ValidPlayer$ You | CheckSVar$ CarpetX | SVarCompare$ EQ0 | OptionalDecider$ You | TriggerZones$ Battlefield | Execute$ TrigMana | TriggerDescription$ At the beginning of each of your main phases, if you haven't added mana to your mana pool with this ability this turn, you may add up to X mana of any one color to your mana pool, where X is the number of Islands target opponent controls. +SVar:TrigMana:AB$ Pump | Cost$ 0 | ValidTgts$ Opponent | TgtPrompt$ Select target opponent, you may add X mana, where X is the number of Islands target opponent controls | RememberObjects$ Targeted | SubAbility$ ChooseNumber +SVar:ChooseNumber:DB$ ChooseNumber | Min$ 0 | Max$ NumManaMax | References$ NumManaMax | ListTitle$ Choose the amount of mana | SubAbility$ DBMana +SVar:DBMana:DB$ Mana | Amount$ X | Produced$ Any | SubAbility$ CheckPlus +SVar:CheckPlus:DB$ StoreSVar | SVar$ CarpetX | Type$ Number | Expression$ 1 | SubAbility$ DBCleanup +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +T:Mode$ Phase | Phase$ End of Turn | Execute$ TrigReset | Static$ True +SVar:TrigReset:AB$ StoreSVar | Cost$ 0 | SVar$ CarpetX | Type$ Number | Expression$ 0 +SVar:X:Count$ChosenNumber +SVar:NumManaMax:Count$Valid Island.RememberedPlayerCtrl +SVar:CarpetX:Number$0 +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/carpet_of_flowers.jpg +SetInfo:USG|Uncommon|http://magiccards.info/scans/en/us/240.jpg +Oracle:At the beginning of each of your main phases, if you haven't added mana to your mana pool with this ability this turn, you may add up to X mana of any one color to your mana pool, where X is the number of Islands target opponent controls. diff --git a/res/cardsfolder/d/death_by_dragons.txt b/res/cardsfolder/d/death_by_dragons.txt new file mode 100644 index 00000000000..938370d0f49 --- /dev/null +++ b/res/cardsfolder/d/death_by_dragons.txt @@ -0,0 +1,8 @@ +Name:Death by Dragons +ManaCost:4 R R +Types:Sorcery +A:SP$ Token | Cost$ 4 R R | ValidTgts$ Player | TgtPrompt$ Select target player who would not get a token | AITgts$ Opponent | RememberTargets$ True | TokenAmount$ 1 | TokenName$ Dragon | TokenTypes$ Creature,Dragon | TokenOwner$ Player.IsNotRemembered | TokenColors$ Red | TokenPower$ 5 | TokenToughness$ 5 | TokenKeywords$ Flying | StackDescription$ SpellDescription | SubAbility$ DBCleanup | SpellDescription$ Each player other than target player puts a 5/5 red Dragon creature token with flying onto the battlefield. +SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True +SVar:Picture:http://www.wizards.com/global/images/magic/general/death_by_dragons.jpg +SetInfo:COM|Uncommon|http://magiccards.info/scans/en/cmd/118.jpg +Oracle:Each player other than target player puts a 5/5 red Dragon creature token with flying onto the battlefield. diff --git a/src/main/java/forge/Card.java b/src/main/java/forge/Card.java index 5888ad491ae..b279ff9bcbf 100644 --- a/src/main/java/forge/Card.java +++ b/src/main/java/forge/Card.java @@ -6876,10 +6876,6 @@ public class Card extends GameEntity implements Comparable { for (final Object rem : source.getRemembered()) { if (rem instanceof Card) { final Card card = (Card) rem; - System.out.println(this + " vs " + card); - System.out.println(this.getOwner().equals(card.getOwner())); - System.out.println(this.getOwner()); - System.out.println(card.getOwner()); if (!this.getOwner().equals(card.getOwner())) { return false; } diff --git a/src/main/java/forge/game/player/Player.java b/src/main/java/forge/game/player/Player.java index 48f6eab88a4..d2d3d7d9688 100644 --- a/src/main/java/forge/game/player/Player.java +++ b/src/main/java/forge/game/player/Player.java @@ -2522,6 +2522,10 @@ public abstract class Player extends GameEntity implements Comparable { if (!source.getRemembered().contains(this)) { return false; } + } else if (property.equals("IsNotRemembered")) { + if (source.getRemembered().contains(this)) { + return false; + } } else if (property.startsWith("EnchantedBy")) { if (!this.getEnchantedBy().contains(source)) { return false; From 3fcb3a9d1c2f66bae573d062a59c058ec19badcd Mon Sep 17 00:00:00 2001 From: myk Date: Mon, 4 Mar 2013 03:09:32 +0000 Subject: [PATCH 46/48] add serrasmurf's Ravnica world --- .../world/ravnica/challenges/quest4001.dck | 34 ++++++++++++++++ .../world/ravnica/challenges/quest4002.dck | 34 ++++++++++++++++ .../world/ravnica/challenges/quest4003.dck | 38 ++++++++++++++++++ .../world/ravnica/challenges/quest4004.dck | 39 +++++++++++++++++++ .../world/ravnica/challenges/quest4005.dck | 35 +++++++++++++++++ .../world/ravnica/challenges/quest4006.dck | 35 +++++++++++++++++ .../world/ravnica/challenges/quest4007.dck | 35 +++++++++++++++++ .../world/ravnica/challenges/quest4008.dck | 37 ++++++++++++++++++ .../world/ravnica/challenges/quest4009.dck | 35 +++++++++++++++++ .../world/ravnica/challenges/quest4010.dck | 37 ++++++++++++++++++ res/quest/world/ravnica/duels/Agrus 2.dck | 27 +++++++++++++ res/quest/world/ravnica/duels/Aurelia 2.dck | 26 +++++++++++++ res/quest/world/ravnica/duels/Aurelia 3.dck | 28 +++++++++++++ .../world/ravnica/duels/Azorius2006 1.dck | 34 ++++++++++++++++ .../world/ravnica/duels/Azorius2012 1.dck | 34 ++++++++++++++++ .../ravnica/duels/Bep van Klaveren 3.dck | 27 +++++++++++++ .../world/ravnica/duels/Borborygmos 2.dck | 30 ++++++++++++++ .../world/ravnica/duels/Borborygmos 3.dck | 25 ++++++++++++ res/quest/world/ravnica/duels/Boros2005.dck | 31 +++++++++++++++ res/quest/world/ravnica/duels/Boros2013.dck | 38 ++++++++++++++++++ res/quest/world/ravnica/duels/Caprio 2.dck | 29 ++++++++++++++ .../duels/Der Rattenfanger von Hameln 2.dck | 25 ++++++++++++ .../world/ravnica/duels/Ghost Council 2.dck | 28 +++++++++++++ .../world/ravnica/duels/Ghost Council 3.dck | 32 +++++++++++++++ .../world/ravnica/duels/Golgari2005 1.dck | 35 +++++++++++++++++ res/quest/world/ravnica/duels/Gruul2006 1.dck | 36 +++++++++++++++++ res/quest/world/ravnica/duels/Isperia 2.dck | 29 ++++++++++++++ res/quest/world/ravnica/duels/Isperia 3.dck | 31 +++++++++++++++ res/quest/world/ravnica/duels/Izzet2012 1.dck | 36 +++++++++++++++++ res/quest/world/ravnica/duels/Jarad 2.dck | 27 +++++++++++++ res/quest/world/ravnica/duels/Kraj 3.dck | 26 +++++++++++++ res/quest/world/ravnica/duels/Lyzolda 2.dck | 31 +++++++++++++++ res/quest/world/ravnica/duels/Lyzolda 3.dck | 29 ++++++++++++++ .../world/ravnica/duels/Niv-Mizzet 3.dck | 28 +++++++++++++ .../world/ravnica/duels/Orzhov2006 1.dck | 34 ++++++++++++++++ .../ravnica/duels/Rakdos the defiler 2.dck | 25 ++++++++++++ res/quest/world/ravnica/duels/Savra 3.dck | 26 +++++++++++++ .../world/ravnica/duels/Selesnya2005 1.dck | 32 +++++++++++++++ .../world/ravnica/duels/Selesnya2012 1.dck | 36 +++++++++++++++++ res/quest/world/ravnica/duels/Simic2013 1.dck | 37 ++++++++++++++++++ .../duels/Sisters of Stone Death 3.dck | 26 +++++++++++++ .../world/ravnica/duels/Sus Antigoon.dck | 30 ++++++++++++++ res/quest/world/ravnica/duels/Szadek 2.dck | 30 ++++++++++++++ res/quest/world/ravnica/duels/Teysa 2.dck | 27 +++++++++++++ res/quest/world/ravnica/duels/Token 2.dck | 27 +++++++++++++ res/quest/world/ravnica/duels/Tolsimir 2.dck | 27 +++++++++++++ res/quest/world/ravnica/duels/Trostani 2.dck | 33 ++++++++++++++++ res/quest/world/ravnica/duels/Ulasht 2.dck | 28 +++++++++++++ res/quest/world/ravnica/duels/Zegana 3.dck | 31 +++++++++++++++ res/quest/world/worlds.txt | 1 + 50 files changed, 1531 insertions(+) create mode 100644 res/quest/world/ravnica/challenges/quest4001.dck create mode 100644 res/quest/world/ravnica/challenges/quest4002.dck create mode 100644 res/quest/world/ravnica/challenges/quest4003.dck create mode 100644 res/quest/world/ravnica/challenges/quest4004.dck create mode 100644 res/quest/world/ravnica/challenges/quest4005.dck create mode 100644 res/quest/world/ravnica/challenges/quest4006.dck create mode 100644 res/quest/world/ravnica/challenges/quest4007.dck create mode 100644 res/quest/world/ravnica/challenges/quest4008.dck create mode 100644 res/quest/world/ravnica/challenges/quest4009.dck create mode 100644 res/quest/world/ravnica/challenges/quest4010.dck create mode 100644 res/quest/world/ravnica/duels/Agrus 2.dck create mode 100644 res/quest/world/ravnica/duels/Aurelia 2.dck create mode 100644 res/quest/world/ravnica/duels/Aurelia 3.dck create mode 100644 res/quest/world/ravnica/duels/Azorius2006 1.dck create mode 100644 res/quest/world/ravnica/duels/Azorius2012 1.dck create mode 100644 res/quest/world/ravnica/duels/Bep van Klaveren 3.dck create mode 100644 res/quest/world/ravnica/duels/Borborygmos 2.dck create mode 100644 res/quest/world/ravnica/duels/Borborygmos 3.dck create mode 100644 res/quest/world/ravnica/duels/Boros2005.dck create mode 100644 res/quest/world/ravnica/duels/Boros2013.dck create mode 100644 res/quest/world/ravnica/duels/Caprio 2.dck create mode 100644 res/quest/world/ravnica/duels/Der Rattenfanger von Hameln 2.dck create mode 100644 res/quest/world/ravnica/duels/Ghost Council 2.dck create mode 100644 res/quest/world/ravnica/duels/Ghost Council 3.dck create mode 100644 res/quest/world/ravnica/duels/Golgari2005 1.dck create mode 100644 res/quest/world/ravnica/duels/Gruul2006 1.dck create mode 100644 res/quest/world/ravnica/duels/Isperia 2.dck create mode 100644 res/quest/world/ravnica/duels/Isperia 3.dck create mode 100644 res/quest/world/ravnica/duels/Izzet2012 1.dck create mode 100644 res/quest/world/ravnica/duels/Jarad 2.dck create mode 100644 res/quest/world/ravnica/duels/Kraj 3.dck create mode 100644 res/quest/world/ravnica/duels/Lyzolda 2.dck create mode 100644 res/quest/world/ravnica/duels/Lyzolda 3.dck create mode 100644 res/quest/world/ravnica/duels/Niv-Mizzet 3.dck create mode 100644 res/quest/world/ravnica/duels/Orzhov2006 1.dck create mode 100644 res/quest/world/ravnica/duels/Rakdos the defiler 2.dck create mode 100644 res/quest/world/ravnica/duels/Savra 3.dck create mode 100644 res/quest/world/ravnica/duels/Selesnya2005 1.dck create mode 100644 res/quest/world/ravnica/duels/Selesnya2012 1.dck create mode 100644 res/quest/world/ravnica/duels/Simic2013 1.dck create mode 100644 res/quest/world/ravnica/duels/Sisters of Stone Death 3.dck create mode 100644 res/quest/world/ravnica/duels/Sus Antigoon.dck create mode 100644 res/quest/world/ravnica/duels/Szadek 2.dck create mode 100644 res/quest/world/ravnica/duels/Teysa 2.dck create mode 100644 res/quest/world/ravnica/duels/Token 2.dck create mode 100644 res/quest/world/ravnica/duels/Tolsimir 2.dck create mode 100644 res/quest/world/ravnica/duels/Trostani 2.dck create mode 100644 res/quest/world/ravnica/duels/Ulasht 2.dck create mode 100644 res/quest/world/ravnica/duels/Zegana 3.dck diff --git a/res/quest/world/ravnica/challenges/quest4001.dck b/res/quest/world/ravnica/challenges/quest4001.dck new file mode 100644 index 00000000000..b0915a5e3fc --- /dev/null +++ b/res/quest/world/ravnica/challenges/quest4001.dck @@ -0,0 +1,34 @@ +[quest] +id=4001 +OpponentName=Trostani +AILife=30 +Repeat=true +Wins=20 +Card Reward=2 multicolor rares;Temple Garden|RAV +Credit Reward=200 +AIExtras=Loxodon Gatekeeper +[metadata] +Name=quest4001 +Title=Ramp it up +Difficulty=hard +Description=Always one step behind.. +Icon=Trostani.jpg +Deck Type=constructed +[main] +3 Angel of Serenity|RTR +3 Armada Wurm|RTR +4 Birds of Paradise|RAV +3 Carven Caryatid|RAV +4 Civic Wayfinder|RAV +4 Condemn|DIS +4 Faith's Fetters|RAV +4 Farseek|RAV +10 Forest|RTR +8 Plains|RTR +4 Selesnya Guildgate|RTR +4 Temple Garden|RTR +3 Trostani, Selesnya's Voice|RTR +2 Worldspine Wurm|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/challenges/quest4002.dck b/res/quest/world/ravnica/challenges/quest4002.dck new file mode 100644 index 00000000000..bad62c928ea --- /dev/null +++ b/res/quest/world/ravnica/challenges/quest4002.dck @@ -0,0 +1,34 @@ +[quest] +id=4002 +OpponentName=Rakdos, Lord of Riots +AILife=40 +Repeat=true +Wins=20 +Card Reward=2 multicolor rares;Blood Crypt|DIS +Credit Reward=200 +HumanExtras=Pariah's Shield|Rakdos Signet +AIExtras=Rakdos, Lord of Riots +[metadata] +Name=quest4002 +Title=Rakdos, Lord of Riots +Difficulty=hard +Description=Big Fellas +Icon=Rakdos.jpg +Deck Type=constructed +[main] +4 Blood Crypt|RTR +4 Char|RAV +4 Crypt Champion|DIS +4 Dark Confidant|RAV +2 Hellkite Tyrant|GTC +4 Hellraiser Goblin|GTC +2 Lord of the Void|GTC +9 Mountain|RTR +2 Molten Primordial|GTC +2 Sepulchral Primordial|GTC +4 Rakdos Guildgate|RTR +4 Seal of Fire|DIS +2 Smog Elemental|GTC +9 Swamp|RTR +4 Rakdos's Return|RTR +[sideboard] diff --git a/res/quest/world/ravnica/challenges/quest4003.dck b/res/quest/world/ravnica/challenges/quest4003.dck new file mode 100644 index 00000000000..1d5405701f3 --- /dev/null +++ b/res/quest/world/ravnica/challenges/quest4003.dck @@ -0,0 +1,38 @@ +[quest] +id=4001 +OpponentName=Isperia +AILife=30 +Repeat=true +Wins=20 +Card Reward=2 multicolor rares;duplicate card;Hallowed Fountain|DIS +Credit Reward=200 +HumanExtras=Leyline of the Meek|Drowned Rusalka +AIExtras=Dovescape +[metadata] +Name=quest4003 +Title=Isperia +Difficulty=hard +Description=The dove from above +Icon=Iseria.jpg +Deck Type=constructed +[main] +1 Angel of Serenity|RTR +4 Azorius Guildgate|RTR +4 Cyclonic Rift|RTR +3 Droning Bureaucrats|GPT +2 Faith's Fetters|RAV +4 Hallowed Fountain|RTR +9 Island|RTR +1 Isperia, Supreme Judge|RTR +3 Jace, Architect of Thought|RTR +9 Plains|RTR +3 Pride of the Clouds|DIS +4 Sphinx's Revelation|RTR +4 Supreme Verdict|RTR +3 Twilight Drover|RAV +4 Veteran Armorer|RAV +1 Diluvian Primordial|GTC +1 Grand Arbiter Augustin IV|DIS +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/challenges/quest4004.dck b/res/quest/world/ravnica/challenges/quest4004.dck new file mode 100644 index 00000000000..6eb9b0f2878 --- /dev/null +++ b/res/quest/world/ravnica/challenges/quest4004.dck @@ -0,0 +1,39 @@ +[quest] +id=4004 +OpponentName=Ghost Council +AILife=30 +Repeat=true +Wins=20 +Card Reward=2 multicolor rares;Godless Shrine|GPT +Credit Reward=200 +AIExtras=Debtors' Knell +[metadata] +Name=quest4004 +Title=Ghost Council +Difficulty=hard +Description=Whether it's heaven or hell, those who believe can live forever +Icon=Ghost Council.jpg +Deck Type=constructed +[main] +2 Angel of Despair|COM +2 Basilica Guards|GTC +4 Condemn|DIS +1 Deathpact Angel|GTC +4 Delirium Skeins|DIS +2 Dimir House Guard|RAV +2 Volatile Rig|RTR +2 Ghost Council of Orzhova|GPT +4 Godless Shrine|GTC +4 High Priest of Penance|GTC +2 Last Gasp|RAV +2 Merciless Eviction|GTC +4 Mortify|GPT +2 Obzedat, Ghost Council|GTC +4 Orzhov Guildgate|GTC +8 Plains|RTR +1 Skeletal Vampire|GPT +8 Swamp|RTR +2 Underworld Connections|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/challenges/quest4005.dck b/res/quest/world/ravnica/challenges/quest4005.dck new file mode 100644 index 00000000000..e4e48276297 --- /dev/null +++ b/res/quest/world/ravnica/challenges/quest4005.dck @@ -0,0 +1,35 @@ +[quest] +id=4005 +OpponentName=Aurelia +AILife=20 +Repeat=true +Wins=20 +Card Reward=2 multicolor rares;Sacred Foundry|RAV +Credit Reward=200 +AIExtras=Assemble the Legion +[metadata] +Name=quest4005 +Title=Aurelia +Difficulty=hard +Description=Ein, Zwei, Polizei +Icon=Aurelia.jpg +Deck Type=constructed +[main] +2 Angel of Serenity|RTR +4 Boros Guildgate|GTC +4 Concordia Pegasus|RTR +4 Faith's Fetters|RAV +3 Firemane Angel|RAV +2 Foundry Champion|GTC +4 Lightning Helix|RAV +2 Seal of Fire|DIS +4 Mizzium Mortars|RTR +8 Mountain|RTR +8 Plains|RTR +4 Sacred Foundry|GTC +4 Stoic Ephemera|DIS +3 Sunhome Guildmage|GTC +4 Wakestone Gargoyle|DIS +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/challenges/quest4006.dck b/res/quest/world/ravnica/challenges/quest4006.dck new file mode 100644 index 00000000000..92e8ec91ddb --- /dev/null +++ b/res/quest/world/ravnica/challenges/quest4006.dck @@ -0,0 +1,35 @@ +[quest] +id=4006 +OpponentName=Lazav +AILife=30 +Repeat=true +Wins=20 +Card Reward=2 multicolor rares;Watery Grave|RAV +Credit Reward=200 +HumanExtras=Dimir Doppelganger +AIExtras=Szadek, Lord of Secrets +[metadata] +Name=quest4006 +Title=Lazav +Difficulty=hard +Description=Milldly annoying.. +Icon=Lazav.jpg +Deck Type=constructed +[main] +4 Darkblast|RAV +4 Last Gasp|RAV +4 Dimir Guildgate|GTC +4 Glimpse the Unthinkable|RAV +8 Island|RTR +2 Mind Grind|GTC +4 Muddle the Mixture|RAV +2 Psychic Spiral|RTR +4 Remand|RAV +4 Compulsive Research|RAV +4 Spell Snare|DIS +8 Swamp|RTR +4 Watery Grave|GTC +4 Wight of Precinct Six|GTC +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/challenges/quest4007.dck b/res/quest/world/ravnica/challenges/quest4007.dck new file mode 100644 index 00000000000..841226acea8 --- /dev/null +++ b/res/quest/world/ravnica/challenges/quest4007.dck @@ -0,0 +1,35 @@ +[quest] +id=4007 +OpponentName=Momir Vig +AILife=30 +Repeat=true +Wins=20 +Card Reward=2 multicolor rares;Breeding Pool|DIS +Credit Reward=200 +HumanExtras=Vigean Hydropon|Thrull Parasite +AIExtras=Momir Vig, Simic Visionary|Doubling Season +[metadata] +Name=quest4007 +Title=Momir Vig +Difficulty=hard +Description=Double trouble +Icon=Momir.jpg +Deck Type=constructed +[main] +4 Breeding Pool|GTC +4 Brushstrider|RTR +4 Cloudfin Raptor|GTC +4 Drakewing Krasis|GTC +4 Elusive Krasis|GTC +4 Experiment One|GTC +9 Forest|RTR +9 Island|RTR +2 Simic Guildgate|GTC +2 Remand|RAV +3 Shambleshark|GTC +3 Simic Charm|GTC +4 Spell Snare|DIS +4 Zameck Guildmage|GTC +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/challenges/quest4008.dck b/res/quest/world/ravnica/challenges/quest4008.dck new file mode 100644 index 00000000000..da67b950ff7 --- /dev/null +++ b/res/quest/world/ravnica/challenges/quest4008.dck @@ -0,0 +1,37 @@ +[quest] +id=4008 +OpponentName=Borborygmos +AILife=30 +Repeat=true +Wins=20 +Card Reward=99 Pit Fight;2 multicolor rares;Stomping Ground|GPT +Credit Reward=200 +HumanExtras=Crown of Convergence|Martial Law +AIExtras=Guild Feud +[metadata] +Name=quest4008 +Title=Borborygmos +Difficulty=hard +Description=Fightclub anyone? +Icon=Borborygmos.jpg +Deck Type=constructed +[main] +4 Domri Rade|GTC +4 Birds of Paradise|M12 +2 Borborygmos|GPT +2 Borborygmos Enraged|GTC +4 Carven Caryatid|RAV +8 Forest|RTR +4 Gruul Guildgate|GTC +2 Gruul Ragebeast|GTC +4 Indrik Stomphowler|DIS +2 Molten Primordial|GTC +8 Mountain|RTR +4 Sprouting Phytohydra|DIS +4 Stomping Ground|GTC +2 Sylvan Primordial|GTC +4 Wasteland Viper|GTC +2 Worldspine Wurm|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/challenges/quest4009.dck b/res/quest/world/ravnica/challenges/quest4009.dck new file mode 100644 index 00000000000..832d397b377 --- /dev/null +++ b/res/quest/world/ravnica/challenges/quest4009.dck @@ -0,0 +1,35 @@ +[quest] +id=4009 +OpponentName=Niv-Mizzet +AILife=30 +Repeat=true +Wins=20 +Card Reward=2 multicolor rares;Steam Vents|GPT +Credit Reward=200 +HumanExtras=Minister of Impediments +AIExtras=Goblin Electromancer|Guttersnipe +[metadata] +Name=quest4009 +Title=Niv-Mizzet +Difficulty=hard +Description=Instant karma is gonna get you +Icon=Niv-Mizzet.jpg +Deck Type=constructed +[main] +4 Cackling Flames|DIS +4 Char|RAV +4 Compulsive Research|RAV +2 Cyclonic Rift|RTR +4 Electrolyze|COM +4 Train of Thought|GPT +3 Goblin Electromancer|RTR +3 Guttersnipe|RTR +8 Island|RTR +4 Izzet Guildgate|RTR +4 Pyromatics|GPT +4 Mizzium Mortars|RTR +8 Mountain|RTR +4 Steam Vents|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/challenges/quest4010.dck b/res/quest/world/ravnica/challenges/quest4010.dck new file mode 100644 index 00000000000..1badf7c6bf4 --- /dev/null +++ b/res/quest/world/ravnica/challenges/quest4010.dck @@ -0,0 +1,37 @@ +[quest] +id=4010 +OpponentName=Jarad +AILife=30 +Repeat=true +Wins=20 +Card Reward=2 multicolor rares;Overgrown Tomb|RAV +Credit Reward=200 +HumanExtras=Trained Caracal +AIExtras=Jarad, Golgari Lich Lord|Savra, Queen of the Golgari +[metadata] +Name=quest4010 +Title=Jarad +Difficulty=hard +Description=Glorified Sacrifice +Icon=Jarad.jpg +Deck Type=constructed +[main] +4 Abrupt Decay|RTR +4 Birds of Paradise|M12 +2 Crypt Champion|DIS +3 Dimir House Guard|RAV +1 Drooling Groodion|RAV +6 Forest|RTR +4 Golgari Guildgate|RTR +2 Golgari Guildmage|COM +4 Grave-Shell Scarab|RAV +4 Grisly Salvage|RTR +4 Overgrown Tomb|RTR +4 Plagued Rusalka|GPT +4 Putrefy|RAV +4 Shambling Shell|RAV +4 Skeletal Vampire|GPT +6 Swamp|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Agrus 2.dck b/res/quest/world/ravnica/duels/Agrus 2.dck new file mode 100644 index 00000000000..008d504d2e3 --- /dev/null +++ b/res/quest/world/ravnica/duels/Agrus 2.dck @@ -0,0 +1,27 @@ +[duel] +[metadata] +Name=Agrus 2 +Title=Agrus +Icon=Agrus.jpg +Difficulty=medium +Description=Ein, Zwei, Polizei +Deck Type=constructed +[main] +4 Ash Zealot|RTR +2 Boros Charm|GTC +4 Boros Elite|GTC +4 Boros Recruit|RAV +2 Five-Alarm Fire|GTC +4 Foundry Street Denizen|GTC +4 Legion Loyalist|GTC +4 Lightning Helix|RAV +10 Mountain|RTR +8 Plains|RTR +2 Proclamation of Rebirth|DIS +4 Sacred Foundry|GTC +4 Seal of Fire|DIS +2 Skyknight Legionnaire|GTC +2 Wojek Halberdiers|GTC +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Aurelia 2.dck b/res/quest/world/ravnica/duels/Aurelia 2.dck new file mode 100644 index 00000000000..d7a0f516c2f --- /dev/null +++ b/res/quest/world/ravnica/duels/Aurelia 2.dck @@ -0,0 +1,26 @@ +[duel] +[metadata] +Name=Aurelia 2 +Title=Aurelia 2 +Icon=Aurelia.jpg +Difficulty=medium +Description=Ein, Zwei, Polizei +Deck Type=constructed +[main] +2 Angel of Serenity|RTR +4 Boros Guildgate|GTC +4 Concordia Pegasus|RTR +4 Faith's Fetters|RAV +3 Firemane Angel|RAV +4 Foundry Champion|GTC +4 Lightning Helix|RAV +4 Mizzium Mortars|RTR +8 Mountain|RTR +8 Plains|RTR +4 Sacred Foundry|GTC +4 Stoic Ephemera|DIS +3 Sunhome Guildmage|GTC +4 Wakestone Gargoyle|DIS +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Aurelia 3.dck b/res/quest/world/ravnica/duels/Aurelia 3.dck new file mode 100644 index 00000000000..526961d6951 --- /dev/null +++ b/res/quest/world/ravnica/duels/Aurelia 3.dck @@ -0,0 +1,28 @@ +[duel] +[metadata] +Name=Aurelia 3 +Title=Aurelia 3 +Icon=Aurelia.jpg +Difficulty=hard +Description=Ein, Zwei, Polizei +Deck Type=constructed +[main] +4 Ash Zealot|RTR +4 Boros Charm|GTC +4 Boros Elite|GTC +4 Boros Guildgate|GTC +2 Boros Reckoner|GTC +2 Demonfire|DIS +3 Firemane Avenger|GTC +3 Flame-Kin Zealot|RAV +4 Lightning Helix|RAV +8 Mountain|RTR +8 Plains|RTR +4 Precinct Captain|RTR +4 Sacred Foundry|GTC +4 Seal of Fire|DIS +3 Wojek Halberdiers|GTC +[sideboard] +[planes] +[schemes] + diff --git a/res/quest/world/ravnica/duels/Azorius2006 1.dck b/res/quest/world/ravnica/duels/Azorius2006 1.dck new file mode 100644 index 00000000000..a665859bd4e --- /dev/null +++ b/res/quest/world/ravnica/duels/Azorius2006 1.dck @@ -0,0 +1,34 @@ +[duel] +[metadata] +Name=Azorius2006 1 +Title=Azorius 2006 +Icon=Azorius-precon.jpg +Difficulty=easy +Description=Precon deck +Deck Type=constructed +[main] +2 Azorius First-Wing|DIS +1 Azorius Guildmage|DIS +3 Beacon Hawk|DIS +2 Benevolent Ancestor|RAV +1 Faith's Fetters|RAV +1 Halcyon Glaze|RAV +10 Island|RTR +1 Isperia the Inscrutable|DIS +2 Minister of Impediments|DIS +4 Mistral Charger|DIS +2 Ocular Halo|DIS +1 Paladin of Prahv|DIS +1 Palliation Accord|DIS +13 Plains|RTR +2 Plumes of Peace|DIS +1 Prahv, Spires of Order|DIS +1 Sinstriker's Will|GPT +2 Sky Hussar|DIS +4 Stoic Ephemera|DIS +1 To Arms!|GPT +4 Wakestone Gargoyle|DIS +1 Zephyr Spirit|RAV +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Azorius2012 1.dck b/res/quest/world/ravnica/duels/Azorius2012 1.dck new file mode 100644 index 00000000000..9eeb9d03ee3 --- /dev/null +++ b/res/quest/world/ravnica/duels/Azorius2012 1.dck @@ -0,0 +1,34 @@ +[duel] +[metadata] +Name=Azorius2012 1 +Title=Azorius 2012 +Icon=Azorius-precon.jpg +Difficulty=easy +Description=Precon deck +Deck Type=constructed +[main] +1 Archon of the Triumvirate|RTR +2 Arrest|RTR +2 Azorius Arrester|RTR +1 Azorius Guildgate|RTR +1 Azorius Justiciar|RTR +2 Azorius Keyrune|RTR +2 Bazaar Krovod|RTR +4 Concordia Pegasus|RTR +2 Dramatic Rescue|RTR +1 Inaction Injunction|RTR +12 Island|RTR +3 Lyev Skyknight|RTR +1 New Prahv Guildmage|RTR +12 Plains|RTR +1 Righteous Authority|RTR +1 Skyline Predator|RTR +1 Soulsworn Spirit|RTR +3 Stealer of Secrets|RTR +3 Swift Justice|RTR +1 Tablet of the Guilds|RTR +2 Trained Caracal|RTR +2 Vassal Soul|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Bep van Klaveren 3.dck b/res/quest/world/ravnica/duels/Bep van Klaveren 3.dck new file mode 100644 index 00000000000..c6d5f9d18e9 --- /dev/null +++ b/res/quest/world/ravnica/duels/Bep van Klaveren 3.dck @@ -0,0 +1,27 @@ +[duel] +[metadata] +Name=Bep van Klaveren 3 +Title=Bep van Klaveren +Icon=Bep.jpg +Difficulty=hard +Description=The Dutch Windmill +Deck Type=constructed +[main] +2 Darkblast|RAV +4 Dimir Guildgate|GTC +4 Glimpse the Unthinkable|RAV +8 Island|RTR +4 Grisly Spectacle|GTC +2 Mind Grind|GTC +4 Muddle the Mixture|RAV +2 Psychic Spiral|RTR +4 Remand|RAV +4 Dimir Infiltrator|RAV +8 Swamp|RTR +4 Watery Grave|GTC +2 Paranoid Delusions|GTC +4 Wight of Precinct Six|GTC +4 Compulsive Research|RAV +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Borborygmos 2.dck b/res/quest/world/ravnica/duels/Borborygmos 2.dck new file mode 100644 index 00000000000..ac869b74204 --- /dev/null +++ b/res/quest/world/ravnica/duels/Borborygmos 2.dck @@ -0,0 +1,30 @@ +[duel] +[metadata] +Name=Borborygmos 2 +Title=Borborygmos 2 +Icon=Borborygmos.jpg +Difficulty=medium +Description=Temper, Temper +Deck Type=constructed +[main] +4 Gyre Sage|GTC +4 Birds of Paradise|M12 +2 Borborygmos|GPT +1 Borborygmos Enraged|GTC +4 Carven Caryatid|RAV +8 Forest|RTR +2 Gruul Ragebeast|GTC +4 Farseek|RAV +4 Gruul Guildgate|GTC +2 Indrik Stomphowler|DIS +1 Molten Primordial|GTC +8 Mountain|RTR +4 Ground Assault|GTC +2 Sprouting Phytohydra|DIS +4 Stomping Ground|GTC +1 Sylvan Primordial|GTC +4 Wasteland Viper|GTC +1 Worldspine Wurm|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Borborygmos 3.dck b/res/quest/world/ravnica/duels/Borborygmos 3.dck new file mode 100644 index 00000000000..334f1fb3aad --- /dev/null +++ b/res/quest/world/ravnica/duels/Borborygmos 3.dck @@ -0,0 +1,25 @@ +[duel] +[metadata] +Name=Borborygmos 3 +Title=Borborygmos 3 +Icon=Borborygmos.jpg +Difficulty=hard +Description=Temper, Temper +Deck Type=constructed +[main] +4 Burning-Tree Emissary|GTC +4 Burning-Tree Shaman|GPT +4 Char|RAV +2 Demonfire|DIS +4 Experiment One|GTC +12 Forest|M10 +4 Ghor-Clan Rampager|GTC +4 Giant Solifuge|GPT +8 Mountain|RTR +2 Scab-Clan Mauler|GPT +4 Domri Rade|GTC +4 Stomping Ground|GTC +4 Wasteland Viper|GTC +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Boros2005.dck b/res/quest/world/ravnica/duels/Boros2005.dck new file mode 100644 index 00000000000..12cbf378a77 --- /dev/null +++ b/res/quest/world/ravnica/duels/Boros2005.dck @@ -0,0 +1,31 @@ +[duel] +[metadata] +Name=Boros2005 1 +Title=Boros 2005 +Icon=Boros-precon.jpg +Difficulty=easy +Description=Precon deck +Deck Type=constructed +[main] +1 Agrus Kos, Wojek Veteran|RAV +2 Bathe in Light|COM +1 Boros Guildmage|COM +3 Boros Recruit|RAV +2 Boros Swiftblade|RAV +1 Cyclopean Snare|RAV +4 Dogpile|RAV +2 Flame-Kin Zealot|RAV +2 Greater Forgeling|RAV +4 Lightning Helix|RAV +11 Mountain|RTR +2 Nightguard Patrol|RAV +2 Ordruun Commando|RAV +12 Plains|RTR +3 Skyknight Legionnaire|GTC +1 Sunhome, Fortress of the Legion|RAV +3 Thundersong Trumpeter|RAV +2 Viashino Slasher|RAV +2 War-Torch Goblin|RAV +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Boros2013.dck b/res/quest/world/ravnica/duels/Boros2013.dck new file mode 100644 index 00000000000..da449d8b97e --- /dev/null +++ b/res/quest/world/ravnica/duels/Boros2013.dck @@ -0,0 +1,38 @@ +[duel] +[metadata] +Name=Boros2013 1 +Title=Boros 2013 +Icon=Boros-precon.jpg +Difficulty=easy +Description=Precon deck +Deck Type=constructed +[main] +1 Act of Treason|GTC +2 Aerial Maneuver|GTC +1 Armored Transport|GTC +3 Arrows of Justice|GTC +1 Bomber Corps|GTC +3 Boros Elite|GTC +1 Boros Guildgate|GTC +2 Boros Keyrune|GTC +1 Court Street Denizen|GTC +2 Daring Skyjek|GTC +3 Ember Beast|GTC +1 Firefist Striker|GTC +1 Firemane Avenger|GTC +2 Fortress Cyclops|GTC +1 Foundry Champion|GTC +1 Mark for Death|GTC +12 Mountain|RTR +1 Mugging|GTC +1 Ordruun Veteran|GTC +12 Plains|RTR +1 Righteous Charge|GTC +1 Shielded Passage|GTC +2 Skyknight Legionnaire|GTC +1 Sunhome Guildmage|GTC +2 Warmind Infantry|GTC +3 Wojek Halberdiers|GTC +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Caprio 2.dck b/res/quest/world/ravnica/duels/Caprio 2.dck new file mode 100644 index 00000000000..e9421bba5d0 --- /dev/null +++ b/res/quest/world/ravnica/duels/Caprio 2.dck @@ -0,0 +1,29 @@ +[duel] +[metadata] +Name=Caprio 2 +Title=Caprio +Icon=Caprio.jpg +Difficulty=medium +Description=Catch me if you can.. +Deck Type=constructed +[main] +4 Compulsive Research|RAV +4 Cyclonic Rift|RTR +4 Muddle the Mixture|RAV +4 Dimir Guildgate|GTC +1 Duskmantle Seer|GTC +4 Hunted Horror|RAV +4 Hunted Phantasm|RAV +4 Illness in the Ranks|GTC +8 Island|RTR +1 Jace, Architect of Thought|RTR +4 Hatching Plans|GPT +4 Leyline of Singularity|GPT +1 Mimeofacture|GPT +1 Stinkweed Imp|RAV +1 Dimir House Guard|RAV +8 Swamp|RTR +4 Watery Grave|GTC +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Der Rattenfanger von Hameln 2.dck b/res/quest/world/ravnica/duels/Der Rattenfanger von Hameln 2.dck new file mode 100644 index 00000000000..89716c9a5dc --- /dev/null +++ b/res/quest/world/ravnica/duels/Der Rattenfanger von Hameln 2.dck @@ -0,0 +1,25 @@ +[duel] +[metadata] +Name=Der Rattenfanger von Hameln 2 +Title=Der Rattenfanger von Hameln +Icon=Hameln.jpg +Difficulty=medium +Description=Ratata +Deck Type=constructed +[main] +4 Blood Crypt|RTR +4 Drainpipe Vermin|RTR +4 Gobhobbler Rats|DIS +4 Gutter Skulk|GTC +4 Hellhole Rats|DIS +8 Mountain|RTR +4 Ogre Slumlord|GTC +4 Pack Rat|RTR +4 Rakdos Guildgate|RTR +4 Ratcatcher|DIS +4 Seal of Fire|DIS +4 Last Gasp|RAV +8 Swamp|RTR +[sideboard] +[planes] +[schemes] diff --git a/res/quest/world/ravnica/duels/Ghost Council 2.dck b/res/quest/world/ravnica/duels/Ghost Council 2.dck new file mode 100644 index 00000000000..2c89f82535f --- /dev/null +++ b/res/quest/world/ravnica/duels/Ghost Council 2.dck @@ -0,0 +1,28 @@ +[duel] +[metadata] +Name=Ghost Council 2 +Title=Ghost Council 2 +Icon=Ghost Council.jpg +Difficulty=medium +Description=Whether it's heaven or hell, those who believe can live forever +Deck Type=constructed +[main] +3 Blind Hunter|GPT +1 Blind Obedience|GTC +4 Castigate|GPT +4 Cry of Contrition|GPT +4 Drainpipe Vermin|RTR +2 Ghost Council of Orzhova|GPT +4 Godless Shrine|GTC +4 Orzhov Guildgate|GTC +4 Orzhov Euthanist|GPT +1 Orzhova, the Church of Deals|GPT +4 Plagued Rusalka|GPT +7 Plains|RTR +2 Proclamation of Rebirth|DIS +8 Swamp|RTR +4 Syndic of Tithes|GTC +4 Thrull Parasite|GTC +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Ghost Council 3.dck b/res/quest/world/ravnica/duels/Ghost Council 3.dck new file mode 100644 index 00000000000..6143ed5ec1e --- /dev/null +++ b/res/quest/world/ravnica/duels/Ghost Council 3.dck @@ -0,0 +1,32 @@ +[duel] +[metadata] +Name=Ghost Council 3 +Title=Ghost Council 3 +Icon=Ghost Council.jpg +Difficulty=hard +Description=Whether it's heaven or hell, those who believe can live forever +Deck Type=constructed +[main] +2 Angel of Despair|COM +2 Basilica Guards|GTC +3 Condemn|M11 +2 Crypt Ghast|GTC +1 Deathpact Angel|GTC +2 Debtors' Knell|GPT +1 Dimir House Guard|RAV +4 Godless Shrine|GTC +4 High Priest of Penance|GTC +3 Last Gasp|RAV +2 Merciless Eviction|GTC +4 Mortify|COM +2 Obzedat, Ghost Council|GTC +2 Order of the Stars|GPT +4 Orzhov Guildgate|GTC +8 Plains|RTR +1 Skeletal Vampire|GPT +2 Stinkweed Imp|RAV +8 Swamp|RTR +3 Underworld Connections|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Golgari2005 1.dck b/res/quest/world/ravnica/duels/Golgari2005 1.dck new file mode 100644 index 00000000000..b58c62abd9e --- /dev/null +++ b/res/quest/world/ravnica/duels/Golgari2005 1.dck @@ -0,0 +1,35 @@ +[duel] +[metadata] +Name=Golgari2005 1 +Title=Golgari 2005 +Icon=Golgari-precon.jpg +Difficulty=easy +Description=Precon deck +Deck Type=constructed +[main] +3 Darkblast|RAV +2 Drooling Groodion|RAV +2 Elves of Deep Shadow|RAV +1 Elvish Skysweeper|RAV +12 Forest|RTR +2 Golgari Brownscale|RAV +1 Golgari Grave-Troll|RAV +1 Golgari Guildmage|COM +2 Golgari Rotwurm|RAV +3 Greater Mossdog|RAV +2 Infectious Host|RAV +2 Last Gasp|RAV +1 Moldervine Cloak|RAV +1 Necromantic Thirst|RAV +2 Putrefy|RAV +2 Recollect|10E +1 Rolling Spoil|RAV +1 Savra, Queen of the Golgari|RAV +2 Shambling Shell|RAV +2 Stinkweed Imp|RAV +12 Swamp|RTR +1 Vigor Mortis|RAV +2 Woodwraith Strangler|RAV +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Gruul2006 1.dck b/res/quest/world/ravnica/duels/Gruul2006 1.dck new file mode 100644 index 00000000000..ba672483007 --- /dev/null +++ b/res/quest/world/ravnica/duels/Gruul2006 1.dck @@ -0,0 +1,36 @@ +[duel] +[metadata] +Name=Gruul2006 1 +Title=Gruul 2006 +Icon=Gruul-precon.jpg +Difficulty=easy +Description=Precon deck +Deck Type=constructed +[main] +1 Battering Wurm|GPT +3 Beastmaster's Magemark|GPT +3 Bloodscale Prowler|GPT +1 Borborygmos|GPT +2 Dowsing Shaman|PC2 +2 Dryad Sophisticate|GPT +3 Fencer's Magemark|GPT +2 Fists of Ironwood|COM +12 Forest|RTR +2 Gatherer of Graces|GPT +1 Gruul Guildmage|GPT +1 Gruul Nodorog|GPT +2 Gruul Scrapper|GPT +1 Indentured Oaf|RAV +11 Mountain|RTR +1 Scab-Clan Mauler|GPT +1 Scorched Rusalka|GPT +1 Skarrg, the Rage Pits|PC2 +2 Skarrgan Skybreaker|GPT +2 Sparkmage Apprentice|M10 +3 Streetbreaker Wurm|GPT +1 Wild Cantor|GPT +1 Wildsize|GPT +1 Wurmweaver Coil|GPT +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Isperia 2.dck b/res/quest/world/ravnica/duels/Isperia 2.dck new file mode 100644 index 00000000000..7005927f8cd --- /dev/null +++ b/res/quest/world/ravnica/duels/Isperia 2.dck @@ -0,0 +1,29 @@ +[duel] +[metadata] +Name=Isperia 2 +Title=Isperia 2 +Icon=Isperia.jpg +Difficulty=medium +Description=Fly baby +Deck Type=constructed +[main] +4 Azorius Charm|RTR +2 Azorius Herald|DIS +2 Civic Saber|RTR +4 Compulsive Research|RAV +4 Dramatic Rescue|RTR +4 Hallowed Fountain|RTR +4 Azorius Guildgate|RTR +8 Island|RTR +4 Lyev Skyknight|RTR +4 Mistral Charger|DIS +8 Plains|RTR +2 Pride of the Clouds|DIS +2 Snapping Drake|RAV +2 Skymark Roc|RTR +4 Spell Snare|DIS +1 Azorius Guildmage|DIS +1 New Prahv Guildmage|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Isperia 3.dck b/res/quest/world/ravnica/duels/Isperia 3.dck new file mode 100644 index 00000000000..37b999102b7 --- /dev/null +++ b/res/quest/world/ravnica/duels/Isperia 3.dck @@ -0,0 +1,31 @@ +[duel] +[metadata] +Name=Isperia 3 +Title=Isperia 3 +Icon=Isperia.jpg +Difficulty=hard +Description=a tiny bit controllish +Deck Type=constructed +[main] +2 Angel of Serenity|RTR +2 Azorius Charm|RTR +4 Azorius Guildgate|RTR +1 Cerulean Sphinx|RAV +3 Compulsive Research|RAV +2 Condemn|M11 +3 Court Hussar|DIS +2 Detention Sphere|RTR +2 Faith's Fetters|RAV +4 Hallowed Fountain|RTR +9 Island|RTR +2 Azorius Herald|DIS +2 Jace, Architect of Thought|RTR +2 Muddle the Mixture|RAV +9 Plains|RTR +1 Pride of the Clouds|DIS +4 Remand|RAV +2 Sphinx's Revelation|RTR +4 Supreme Verdict|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Izzet2012 1.dck b/res/quest/world/ravnica/duels/Izzet2012 1.dck new file mode 100644 index 00000000000..4f359957a63 --- /dev/null +++ b/res/quest/world/ravnica/duels/Izzet2012 1.dck @@ -0,0 +1,36 @@ +[duel] +[metadata] +Name=Izzet2012 1 +Title=Izzet 2012 +Icon=Izzet-precon.jpg +Difficulty=easy +Description=Precon deck +Deck Type=constructed +[main] +3 Annihilating Fire|RTR +2 Blistercoil Weird|RTR +1 Blustersquall|RTR +3 Cobblebrute|RTR +1 Downsize|RTR +2 Electrickery|RTR +1 Explosive Impact|RTR +2 Goblin Electromancer|RTR +2 Goblin Rally|RTR +2 Guttersnipe|RTR +1 Hypersonic Dragon|RTR +12 Island|RTR +1 Izzet Guildgate|RTR +2 Izzet Keyrune|RTR +2 Sparkmage Apprentice|RAV +2 Surveilling Sprite|RAV +1 Mizzium Mortars|RTR +12 Mountain|RTR +1 Nivix Guildmage|RTR +1 Pursuit of Flight|RTR +3 Runewing|RTR +1 Teleportal|RTR +1 Tenement Crasher|RTR +1 Thoughtflare|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Jarad 2.dck b/res/quest/world/ravnica/duels/Jarad 2.dck new file mode 100644 index 00000000000..d477915cee8 --- /dev/null +++ b/res/quest/world/ravnica/duels/Jarad 2.dck @@ -0,0 +1,27 @@ +[duel] +[metadata] +Name=Jarad 2 +Title=Jarad +Icon=Jarad.jpg +Difficulty=medium +Description=Dead? Undead? Make up your mind! +Deck Type=constructed +[main] +3 Bloodbond March|RAV +4 Darkblast|RAV +3 Dimir House Guard|RAV +4 Elves of Deep Shadow|RAV +8 Forest|RTR +2 Golgari Grave-Troll|RAV +4 Golgari Guildgate|RTR +4 Grisly Salvage|RTR +1 Jarad's Orders|RTR +3 Jarad, Golgari Lich Lord|RTR +4 Lotleth Troll|RTR +4 Overgrown Tomb|RTR +4 Slitherhead|RTR +4 Stinkweed Imp|RAV +8 Swamp|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Kraj 3.dck b/res/quest/world/ravnica/duels/Kraj 3.dck new file mode 100644 index 00000000000..31efa0e690c --- /dev/null +++ b/res/quest/world/ravnica/duels/Kraj 3.dck @@ -0,0 +1,26 @@ +[duel] +[metadata] +Name=Kraj 3 +Title=Experiment Kraj +Icon=Kraj.jpg +Difficulty=hard +Description=Darwin, eat your heart out +Deck Type=constructed +[main] +4 Breeding Pool|GTC +4 Brushstrider|RTR +4 Cloudfin Raptor|GTC +4 Drakewing Krasis|GTC +4 Elusive Krasis|GTC +4 Experiment One|GTC +9 Forest|RTR +9 Island|RTR +2 Simic Guildgate|GTC +2 Remand|RAV +3 Shambleshark|GTC +3 Simic Charm|GTC +4 Spell Snare|DIS +4 Zameck Guildmage|GTC +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Lyzolda 2.dck b/res/quest/world/ravnica/duels/Lyzolda 2.dck new file mode 100644 index 00000000000..13c7b7632cb --- /dev/null +++ b/res/quest/world/ravnica/duels/Lyzolda 2.dck @@ -0,0 +1,31 @@ +[duel] +[metadata] +Name=Lyzolda 2 +Title=Lyzolda 2 +Icon=Lyzolda.jpg +Difficulty=medium +Description=Big Fellas +Deck Type=constructed +[main] +2 Bloodfray Giant|RTR +2 Carnival Hellsteed|RTR +2 Cobblebrute|RTR +3 Desecration Demon|RTR +3 Guild Feud|RTR +2 Hammerfist Giant|RAV +1 Hellhole Rats|DIS +3 Hellraiser Goblin|GTC +1 Hunted Dragon|RAV +4 Last Gasp|RAV +1 Lord of the Void|GTC +10 Mountain|RTR +4 Rakdos Guildgate|RTR +4 Rakdos Keyrune|RTR +4 Seal of Fire|DIS +1 Smog Elemental|GTC +1 Stalking Vengeance|DIS +2 Street Spasm|RTR +10 Swamp|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Lyzolda 3.dck b/res/quest/world/ravnica/duels/Lyzolda 3.dck new file mode 100644 index 00000000000..779b593af26 --- /dev/null +++ b/res/quest/world/ravnica/duels/Lyzolda 3.dck @@ -0,0 +1,29 @@ +[duel] +[metadata] +Name=Lyzolda 3 +Title=Lyzolda 3 +Icon=Lyzolda.jpg +Difficulty=hard +Description=Burn, burn, yes you're gonna burn +Deck Type=constructed +[main] +4 Ash Zealot|RTR +4 Blood Crypt|RTR +4 Char|RAV +4 Dark Confidant|RAV +2 Demonfire|DIS +2 Foundry Street Denizen|GTC +2 Gore-House Chainwalker|RTR +4 Hellhole Flailer|RTR +9 Mountain|RAV +2 Rakdos Guildgate|RTR +4 Rakdos Cackler|RTR +4 Rakdos Shred-Freak|RTR +4 Seal of Fire|DIS +3 Skullcrack|GTC +1 Rakdos Guildmage|DIS +1 Rix Maadi Guildmage|RTR +9 Swamp|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Niv-Mizzet 3.dck b/res/quest/world/ravnica/duels/Niv-Mizzet 3.dck new file mode 100644 index 00000000000..979bd3e3f4d --- /dev/null +++ b/res/quest/world/ravnica/duels/Niv-Mizzet 3.dck @@ -0,0 +1,28 @@ +[duel] +[metadata] +Name=Niv-Mizzet 3 +Title=Niv-Mizzet 3 +Icon=Niv-Mizzet.jpg +Difficulty=hard +Description=Instant karma is gonna get you +Deck Type=constructed +[main] +4 Compulsive Research|RAV +1 Diluvian Primordial|GTC +4 Electrolyze|COM +4 Frostburn Weird|RTR +4 Spell Snare|DIS +2 Hypersonic Dragon|RTR +9 Island|RTR +4 Izzet Guildgate|RTR +3 Jace, Architect of Thought|RTR +4 Mizzium Mortars|RTR +9 Mountain|RTR +2 Niv-Mizzet, Dracogenius|RTR +1 Niv-Mizzet, the Firemind|GPT +4 Remand|RAV +4 Steam Vents|RTR +3 Steamcore Weird|GPT +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Orzhov2006 1.dck b/res/quest/world/ravnica/duels/Orzhov2006 1.dck new file mode 100644 index 00000000000..0f50acdbdc5 --- /dev/null +++ b/res/quest/world/ravnica/duels/Orzhov2006 1.dck @@ -0,0 +1,34 @@ +[duel] +[metadata] +Name=Orzhov2006 1 +Title=Orzhov 2006 +Icon=Orzhov-precon.jpg +Difficulty=easy +Description=Precon deck +Deck Type=constructed +[main] +2 Agent of Masks|GPT +1 Belfry Spirit|GPT +2 Blind Hunter|GPT +2 Castigate|GPT +2 Hissing Miasma|GPT +2 Infectious Host|RAV +2 Mortify|COM +2 Mourning Thrull|GPT +2 Orzhov Euthanist|GPT +1 Orzhov Guildmage|COM +1 Orzhova, the Church of Deals|GPT +2 Ostiary Thrull|GPT +2 Pillory of the Sleepless|GPT +4 Plagued Rusalka|GPT +11 Plains|RTR +2 Poisonbelly Ogre|GPT +2 Shrieking Grotesque|GPT +1 Skeletal Vampire|GPT +2 Souls of the Faultless|GPT +2 Strands of Undeath|RAV +12 Swamp|RTR +1 Teysa, Orzhov Scion|GPT +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Rakdos the defiler 2.dck b/res/quest/world/ravnica/duels/Rakdos the defiler 2.dck new file mode 100644 index 00000000000..42ad605525c --- /dev/null +++ b/res/quest/world/ravnica/duels/Rakdos the defiler 2.dck @@ -0,0 +1,25 @@ +[duel] +[metadata] +Name=Rakdos the defiler 2 +Title=Rakdos the Defiler +Icon=Rakdos.jpg +Difficulty=medium +Description=Blood, Sweat & Tears +Deck Type=constructed +[main] +4 Blood Crypt|RTR +4 Char|RAV +4 Dreadbore|RTR +4 Grave Betrayal|RTR +4 Mizzium Mortars|RTR +9 Mountain|RTR +4 Rakdos Guildgate|RTR +4 Rakdos's Return|RTR +9 Swamp|RTR +4 Underworld Connections|RTR +4 Wight of Precinct Six|GTC +4 Mind Rot|RTR +2 Seal of Fire|DIS +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Savra 3.dck b/res/quest/world/ravnica/duels/Savra 3.dck new file mode 100644 index 00000000000..ec57e5336ef --- /dev/null +++ b/res/quest/world/ravnica/duels/Savra 3.dck @@ -0,0 +1,26 @@ +[duel] +[metadata] +Name=Savra 3 +Title=Savra +Icon=Savra.jpg +Difficulty=hard +Description=Controllish +Deck Type=constructed +[main] +4 Abrupt Decay|RTR +4 Birds of Paradise|M12 +4 Last Gasp|RAV +2 Elves of Deep Shadow|RAV +8 Forest|RTR +4 Golgari Guildgate|RTR +3 Dreg Mangler|RTR +4 Overgrown Tomb|RTR +4 Putrefy|RAV +4 Skeletal Vampire|GPT +8 Swamp|RTR +3 Trestle Troll|RTR +4 Underworld Connections|RTR +4 Vraska the Unseen|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Selesnya2005 1.dck b/res/quest/world/ravnica/duels/Selesnya2005 1.dck new file mode 100644 index 00000000000..89122b9e6bb --- /dev/null +++ b/res/quest/world/ravnica/duels/Selesnya2005 1.dck @@ -0,0 +1,32 @@ +[duel] +[metadata] +Name=Selesnya2005 1 +Title=Selesnya 2005 +Icon=Selesnya-precon.jpg +Difficulty=easy +Description=Precon deck +Deck Type=constructed +[main] +2 Centaur Safeguard|RAV +2 Conclave Phalanx|RAV +1 Conclave's Blessing|RAV +1 Dowsing Shaman|RAV +4 Elvish Skysweeper|RAV +4 Fists of Ironwood|RAV +12 Forest|M10 +12 Forest|RTR +3 Gather Courage|RAV +11 Plains|RTR +3 Root-Kin Ally|RAV +2 Scatter the Seeds|RAV +1 Scion of the Wild|RAV +2 Selesnya Evangel|RAV +1 Selesnya Guildmage|RAV +4 Siege Wurm|RAV +1 Tolsimir Wolfblood|RAV +4 Transguild Courier|DIS +1 Vitu-Ghazi, the City-Tree|RAV +1 Watchwolf|RAV +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Selesnya2012 1.dck b/res/quest/world/ravnica/duels/Selesnya2012 1.dck new file mode 100644 index 00000000000..cc332829b20 --- /dev/null +++ b/res/quest/world/ravnica/duels/Selesnya2012 1.dck @@ -0,0 +1,36 @@ +[duel] +[metadata] +Name=Selesnya2012 1 +Title=Selesnya 2012 +Icon=Selesnya-precon.jpg +Difficulty=easy +Description=Precon deck +Deck Type=constructed +[main] +1 Axebane Stag|RTR +1 Brushstrider|RTR +2 Call of the Conclave|RTR +4 Centaur Healer|RTR +3 Centaur's Herald|RTR +2 Chorus of Might|RTR +1 Coursers' Accord|RTR +1 Druid's Deliverance|RTR +2 Eyes in the Skies|RTR +12 Forest|RTR +1 Grove of the Guardian|RTR +1 Heroes' Reunion|RTR +2 Phantom General|RTR +11 Plains|RTR +1 Risen Sanctuary|RTR +1 Rootborn Defenses|RTR +2 Rubbleback Rhino|RTR +2 Savage Surge|RTR +1 Selesnya Guildgate|RTR +2 Selesnya Keyrune|RTR +3 Seller of Songbirds|RTR +2 Trostani's Judgment|RTR +1 Vitu-Ghazi Guildmage|RTR +1 Wayfaring Temple|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Simic2013 1.dck b/res/quest/world/ravnica/duels/Simic2013 1.dck new file mode 100644 index 00000000000..7facef9c8d9 --- /dev/null +++ b/res/quest/world/ravnica/duels/Simic2013 1.dck @@ -0,0 +1,37 @@ +[duel] +[metadata] +Name=Simic2013 1 +Title=Simic 2013 +Icon=Simic-precon.jpg +Difficulty=easy +Description=Precon deck +Deck Type=constructed +[main] +2 Adaptive Snapjaw|GTC +2 Cloudfin Raptor|GTC +4 Crocanura|GTC +1 Crowned Ceratok|GTC +2 Drakewing Krasis|GTC +1 Elusive Krasis|GTC +3 Agoraphobia|GTC +1 Fathom Mage|GTC +2 Forced Adaptation|GTC +12 Forest|RTR +1 Frilled Oculus|GTC +1 Hindervines|GTC +13 Island|RTR +1 Ivy Lane Denizen|GTC +4 Kraken Hatchling|M13 +1 Leyline Phantom|GTC +1 Merfolk of the Depths|GTC +1 Sapphire Drake|GTC +2 Shambleshark|GTC +1 Simic Guildgate|GTC +2 Simic Keyrune|GTC +1 Sleep|M13 +2 Unexpected Results|GTC +1 Urban Evolution|GTC +1 Zameck Guildmage|GTC +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Sisters of Stone Death 3.dck b/res/quest/world/ravnica/duels/Sisters of Stone Death 3.dck new file mode 100644 index 00000000000..7725574c453 --- /dev/null +++ b/res/quest/world/ravnica/duels/Sisters of Stone Death 3.dck @@ -0,0 +1,26 @@ +[duel] +[metadata] +Name=Sisters of Stone Death 3 +Title=Sisters of Stone Death +Icon=Sisters of Stone Death.jpg +Difficulty=hard +Description=Some creatures that really want to eat you +Deck Type=constructed +[main] +4 Birds of Paradise|M12 +3 Deadbridge Goliath|RTR +3 Desecration Demon|RTR +4 Dreg Mangler|RTR +4 Elves of Deep Shadow|RAV +8 Forest|RTR +4 Golgari Guildgate|RTR +4 Abrupt Decay|RTR +4 Lotleth Troll|RTR +4 Overgrown Tomb|RTR +3 Sewer Shambler|RTR +3 Shambling Shell|RAV +4 Slitherhead|RTR +8 Swamp|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Sus Antigoon.dck b/res/quest/world/ravnica/duels/Sus Antigoon.dck new file mode 100644 index 00000000000..6d4facc6760 --- /dev/null +++ b/res/quest/world/ravnica/duels/Sus Antigoon.dck @@ -0,0 +1,30 @@ +[duel] +[metadata] +Name=Sus Antigoon 2 +Title=Sus Antigoon +Icon=Sus Antigoon.jpg +Difficulty=medium +Description=Your Ghost +Deck Type=constructed +[main] +1 Clinging Darkness|RAV +2 Dark Confidant|RAV +4 Dutiful Thrull|GTC +4 Ethereal Armor|RTR +2 Gift of Orzhova|GTC +4 Godless Shrine|GTC +4 Grim Roustabout|RTR +1 Guardian's Magemark|GPT +1 Necromancer's Magemark|GPT +4 Orzhov Guildgate|GTC +4 Pillory of the Sleepless|GPT +8 Plains|RTR +2 Precinct Captain|RTR +4 Shadow Lance|GPT +2 Sphere of Safety|RTR +1 Stab Wound|RTR +8 Swamp|RTR +4 Underworld Connections|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Szadek 2.dck b/res/quest/world/ravnica/duels/Szadek 2.dck new file mode 100644 index 00000000000..4e4766225df --- /dev/null +++ b/res/quest/world/ravnica/duels/Szadek 2.dck @@ -0,0 +1,30 @@ +[duel] +[metadata] +Name=Szadek 2 +Title=Szadek +Icon=Szadek.jpg +Difficulty=medium +Description=Lucipher +Deck Type=constructed +[main] +2 Cyclonic Rift|RTR +2 Daggerdrome Imp|RTR +4 Last Gasp|RAV +4 Dimir Guildgate|GTC +4 Dimir Infiltrator|RAV +8 Island|RTR +2 Last Thoughts|GTC +2 Muddle the Mixture|RAV +4 Cloudfin Raptor|GTC +2 Remand|RAV +4 Shadow Slice|GTC +2 Stolen Identity|GTC +2 Surveilling Sprite|RAV +8 Swamp|RTR +2 Thrill-Kill Assassin|RTR +2 Undercity Plague|GTC +4 Watery Grave|GTC +2 Deathcult Rogue|GTC +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Teysa 2.dck b/res/quest/world/ravnica/duels/Teysa 2.dck new file mode 100644 index 00000000000..6b07cba1130 --- /dev/null +++ b/res/quest/world/ravnica/duels/Teysa 2.dck @@ -0,0 +1,27 @@ +[duel] +[metadata] +Name=Teysa 2 +Title=Teysa +Icon=Teysa.jpg +Difficulty=medium +Description=Please let me play my combo +Deck Type=constructed +[main] +4 Belfry Spirit|GPT +2 Blind Hunter|GPT +2 Dimir House Guard|RAV +4 Eyes in the Skies|RTR +2 Ghost Council of Orzhova|GPT +4 Godless Shrine|GTC +4 Knight Watch|GTC +2 Ogre Slumlord|GTC +4 Orzhov Guildgate|GTC +8 Plains|RTR +4 Precinct Captain|RTR +4 Skeletal Vampire|GPT +8 Swamp|RTR +4 Teysa, Orzhov Scion|GPT +4 Twilight Drover|RAV +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Token 2.dck b/res/quest/world/ravnica/duels/Token 2.dck new file mode 100644 index 00000000000..0689df7defd --- /dev/null +++ b/res/quest/world/ravnica/duels/Token 2.dck @@ -0,0 +1,27 @@ +[duel] +[metadata] +Name=Token 2 +Title=Token +Icon=Token.jpg +Difficulty=medium +Description=Tokens'r'us +Deck Type=constructed +[main] +4 Birds of Paradise|RAV +4 Call of the Conclave|RTR +2 Collective Blessing|RTR +4 Fists of Ironwood|RAV +7 Forest|RTR +4 Glare of Subdual|RAV +2 Hour of Reckoning|RAV +4 Leyline of the Meek|GPT +7 Plains|RTR +4 Scatter the Seeds|RAV +4 Seed Spark|RAV +4 Selesnya Charm|RTR +4 Selesnya Guildgate|RTR +4 Temple Garden|RTR +2 Vitu-Ghazi, the City-Tree|RAV +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Tolsimir 2.dck b/res/quest/world/ravnica/duels/Tolsimir 2.dck new file mode 100644 index 00000000000..a6d1e81d4a0 --- /dev/null +++ b/res/quest/world/ravnica/duels/Tolsimir 2.dck @@ -0,0 +1,27 @@ +[duel] +[metadata] +Name=Tolsimir 2 +Title=Tolsimir +Icon=Tolsimir.jpg +Difficulty=medium +Description=Creatures'r'us +Deck Type=constructed +[main] +4 Call of the Conclave|RTR +4 Centaur Healer|RTR +4 Dryad Militant|RTR +8 Forest|RTR +3 Giant Growth|RTR +4 Loxodon Hierarch|RAV +4 Loxodon Smiter|RTR +8 Plains|RTR +2 Selesnya Guildmage|RAV +4 Selesnya Guildgate|RTR +4 Temple Garden|RTR +2 Tolsimir Wolfblood|RAV +4 Vinelasher Kudzu|RAV +4 Watchwolf|RAV +1 Vitu-Ghazi Guildmage|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Trostani 2.dck b/res/quest/world/ravnica/duels/Trostani 2.dck new file mode 100644 index 00000000000..120c050acea --- /dev/null +++ b/res/quest/world/ravnica/duels/Trostani 2.dck @@ -0,0 +1,33 @@ +[duel] +[metadata] +Name=Trostani 2 +Title=Trostani +Icon=Trostani.jpg +Difficulty=medium +Description=Ramp it up +Deck Type=constructed +[main] +1 Angel of Serenity|RTR +1 Armada Wurm|RTR +1 Autochthon Wurm|RAV +4 Birds of Paradise|RAV +1 Blazing Archon|RAV +4 Carven Caryatid|RAV +4 Civic Wayfinder|RAV +4 Gyre Sage|GTC +4 Farseek|RAV +10 Forest|RTR +1 Luminate Primordial|GTC +1 Oathsworn Giant|RAV +1 Palisade Giant|RTR +8 Plains|RTR +1 Primordial Sage|RAV +2 Selesnya Keyrune|RTR +4 Selesnya Guildgate|RTR +1 Sylvan Primordial|GTC +4 Temple Garden|RTR +2 Trostani, Selesnya's Voice|RTR +1 Worldspine Wurm|RTR +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Ulasht 2.dck b/res/quest/world/ravnica/duels/Ulasht 2.dck new file mode 100644 index 00000000000..bb3e2a5107e --- /dev/null +++ b/res/quest/world/ravnica/duels/Ulasht 2.dck @@ -0,0 +1,28 @@ +[duel] +[metadata] +Name=Ulasht 2 +Title=Ulasht +Icon=Ulasht.jpg +Difficulty=medium +Description=Temper, Temper +Deck Type=constructed +[main] +2 Burning-Tree Emissary|GTC +8 Forest|RTR +4 Ghor-Clan Rampager|GTC +10 Mountain|RTR +4 Mugging|GTC +2 Razortip Whip|GTC +4 Scab-Clan Mauler|GPT +4 Seal of Fire|DIS +2 Skarrg, the Rage Pits|PC2 +2 Skarrgan Firebird|GPT +4 Skarrgan Pit-Skulk|GPT +2 Skarrgan Skybreaker|GPT +4 Stomping Ground|GTC +4 Wasteland Viper|GTC +2 Ulasht, the Hate Seed|GPT +2 Domri Rade|GTC +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/ravnica/duels/Zegana 3.dck b/res/quest/world/ravnica/duels/Zegana 3.dck new file mode 100644 index 00000000000..0a8568eda5d --- /dev/null +++ b/res/quest/world/ravnica/duels/Zegana 3.dck @@ -0,0 +1,31 @@ +[duel] +[metadata] +Name=Zegana 3 +Title=Zegana +Icon=Zegana.jpg +Difficulty=hard +Description=Darwin, eat your heart out +Deck Type=constructed +[main] +4 Birds of Paradise|M12 +4 Breeding Pool|GTC +2 Civic Wayfinder|10E +2 Coiling Oracle|DIS +4 Crocanura|GTC +4 Experiment One|GTC +4 Farseek|M13 +5 Forest|RTR +4 Island|RTR +2 Master Biomancer|GTC +2 Mystic Genesis|GTC +1 Novijen, Heart of Progress|DIS +3 Patagia Viper|DIS +4 Prime Speaker Zegana|GTC +4 Simic Charm|GTC +4 Simic Guildgate|GTC +3 Trygon Predator|DIS +2 Vigean Hydropon|DIS +2 Zameck Guildmage|GTC +[sideboard] +[planes] +[schemes] \ No newline at end of file diff --git a/res/quest/world/worlds.txt b/res/quest/world/worlds.txt index 5a31138a0dd..807d24e92e6 100644 --- a/res/quest/world/worlds.txt +++ b/res/quest/world/worlds.txt @@ -1,3 +1,4 @@ Name:Main world Name:Shandalar|Dir:shandalar|Sets:2ED, ARN, ATQ, 3ED, LEG, DRK, 4ED|Banned:Chaos Orb; Falling Star Name:Jamuraa|Dir:jamuraa|Sets:5ED, ARN, MIR, VIS, WTH|Banned:Chaos Orb; Falling Star +Name:Ravnica|Dir:ravnica|Sets:RAV, GPT, DIS, RTR, GTC|Banned:Chaos Orb; Falling Star From eaf3429ceac60257747dcc4ea63645e200f5b17a Mon Sep 17 00:00:00 2001 From: Sol Date: Mon, 4 Mar 2013 03:33:01 +0000 Subject: [PATCH 47/48] - Inform the human which turn position he's in during the Mulligan Input --- .../java/forge/control/input/InputMulligan.java | 17 +++++++++++++---- src/main/java/forge/game/GameState.java | 15 +++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/main/java/forge/control/input/InputMulligan.java b/src/main/java/forge/control/input/InputMulligan.java index 85c82714684..6939ff93c8c 100644 --- a/src/main/java/forge/control/input/InputMulligan.java +++ b/src/main/java/forge/control/input/InputMulligan.java @@ -62,10 +62,19 @@ public class InputMulligan extends Input { ButtonUtil.setButtonText("No", "Yes"); ButtonUtil.enableAllFocusOk(); - final String str = - (Singletons.getModel().getGame().getPhaseHandler().getPlayerTurn().equals(Singletons.getControl().getPlayer()) - ? "You're going first. " : "The computer is going first. "); - CMatchUI.SINGLETON_INSTANCE.showMessage(str + "Do you want to Mulligan?"); + GameState game = Singletons.getModel().getGame(); + Player startingPlayer = game.getPhaseHandler().getPlayerTurn(); + Player localPlayer = Singletons.getControl().getPlayer(); + + StringBuilder sb = new StringBuilder(); + sb.append(startingPlayer.getName()).append(" is going first. "); + + if (!startingPlayer.equals(localPlayer)) { + sb.append("You are going ").append(game.getOrdinalPosition(localPlayer, startingPlayer)).append(". "); + } + + sb.append("Do you want to Mulligan?"); + CMatchUI.SINGLETON_INSTANCE.showMessage(sb.toString()); } /** {@inheritDoc} */ diff --git a/src/main/java/forge/game/GameState.java b/src/main/java/forge/game/GameState.java index 9854253bdf4..ebe30d10398 100644 --- a/src/main/java/forge/game/GameState.java +++ b/src/main/java/forge/game/GameState.java @@ -478,6 +478,21 @@ public class GameState { return roIngamePlayers.get(iPlayer); } + + public String getOrdinalPosition(Player player, Player startingPlayer) { + int startPosition = roIngamePlayers.indexOf(startingPlayer); + int position = roIngamePlayers.indexOf(player) + startPosition + 1; + String[] sufixes = new String[] { "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" }; + switch (position % 100) { + case 11: + case 12: + case 13: + return position + "th"; + default: + return position + sufixes[position % 10]; + + } + } /** * Only game knows how to get suitable players out of just connected clients. From 46fa85528f0c95744b5429d133d5ed83cd909174 Mon Sep 17 00:00:00 2001 From: Sol Date: Mon, 4 Mar 2013 03:56:04 +0000 Subject: [PATCH 48/48] - Adding the three "Opponent Chooses" modal spells from Alliances. If the Human casts one, the AI will currently choose the "least harmful" fork of the mode for now, this is a static "decision". --- .gitattributes | 3 ++ res/cardsfolder/f/fatal_lore.txt | 11 +++++++ res/cardsfolder/l/library_of_lat_nam.txt | 11 +++++++ res/cardsfolder/m/misfortune.txt | 13 ++++++++ .../java/forge/card/ability/ai/CharmAi.java | 22 +++++++++++--- .../card/ability/effects/CharmEffect.java | 30 +++++++++++++++---- 6 files changed, 81 insertions(+), 9 deletions(-) create mode 100644 res/cardsfolder/f/fatal_lore.txt create mode 100644 res/cardsfolder/l/library_of_lat_nam.txt create mode 100644 res/cardsfolder/m/misfortune.txt diff --git a/.gitattributes b/.gitattributes index bdc3671daee..7055ffbc1a9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3469,6 +3469,7 @@ res/cardsfolder/f/fastbond.txt svneol=native#text/plain res/cardsfolder/f/fatal_attraction.txt svneol=native#text/plain res/cardsfolder/f/fatal_blow.txt svneol=native#text/plain res/cardsfolder/f/fatal_frenzy.txt svneol=native#text/plain +res/cardsfolder/f/fatal_lore.txt -text res/cardsfolder/f/fatal_mutation.txt svneol=native#text/plain res/cardsfolder/f/fatestitcher.txt svneol=native#text/plain res/cardsfolder/f/fathom_mage.txt -text @@ -5975,6 +5976,7 @@ res/cardsfolder/l/liability.txt svneol=native#text/plain res/cardsfolder/l/liberate.txt svneol=native#text/plain res/cardsfolder/l/liberated_dwarf.txt svneol=native#text/plain res/cardsfolder/l/library_of_alexandria.txt svneol=native#text/plain +res/cardsfolder/l/library_of_lat_nam.txt -text res/cardsfolder/l/library_of_leng.txt -text res/cardsfolder/l/lich.txt svneol=native#text/plain res/cardsfolder/l/lich_lord_of_unx.txt svneol=native#text/plain @@ -6684,6 +6686,7 @@ res/cardsfolder/m/mischievous_poltergeist.txt svneol=native#text/plain res/cardsfolder/m/mischievous_quanar.txt -text res/cardsfolder/m/misers_cage.txt svneol=native#text/plain res/cardsfolder/m/misery_charm.txt svneol=native#text/plain +res/cardsfolder/m/misfortune.txt -text res/cardsfolder/m/misfortunes_gain.txt svneol=native#text/plain res/cardsfolder/m/misguided_rage.txt svneol=native#text/plain res/cardsfolder/m/mishra.txt -text diff --git a/res/cardsfolder/f/fatal_lore.txt b/res/cardsfolder/f/fatal_lore.txt new file mode 100644 index 00000000000..1bd8c60fafb --- /dev/null +++ b/res/cardsfolder/f/fatal_lore.txt @@ -0,0 +1,11 @@ +Name:Fatal Lore +ManaCost:2 B B +Types:Sorcery +A:SP$ Charm | Cost$ 2 B B | Chooser$ Opponent | Choices$ DrawThree,DestroyAndDraw | SpellDescription$ An opponent chooses one - You draw three cards; or you destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated. +SVar:DrawThree:DB$ Draw | NumCards$ 3 | Defined$ You | SpellDescription$ You draw three cards. +SVar:DestroyAndDraw:DB$ Destroy | ValidTgts$ Creature.ChosenCtrl | TgtPrompt$ Select target creature | TargetMin$ 0 | TargetMax$ 2 | NoRegen$ True | SpellDescription$ You destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated. | SubAbility$ ChooserDraws +SVar:ChooserDraws:DB$ Draw | NumCards$ 3 | Defined$ ChosenPlayer +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/fatal_lore.jpg +SetInfo:ALL|Rare|http://magiccards.info/scans/en/ai/7.jpg +Oracle:An opponent chooses one - You draw three cards; or you destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated. diff --git a/res/cardsfolder/l/library_of_lat_nam.txt b/res/cardsfolder/l/library_of_lat_nam.txt new file mode 100644 index 00000000000..42ec77fb039 --- /dev/null +++ b/res/cardsfolder/l/library_of_lat_nam.txt @@ -0,0 +1,11 @@ +Name:Library of Lat-Nam +ManaCost:4 U +Types:Sorcery +A:SP$ Charm | Cost$ 4 U | Chooser$ Opponent | Choices$ SlowDraw,Tutor | SpellDescription$ An opponent chooses one - You draw three cards at the beginning of the next turn's upkeep; or you search your library for a card, put that card into your hand, then shuffle your library. +SVar:SlowDraw:DB$ Draw | NumCards$ 3 | Defined$ You | NextUpkeep$ True | SpellDescription$ You draw three cards at the beginning of the next turn's upkeep +SVar:Tutor:DB$ ChangeZone | Origin$ Library | Destination$ Hand | ChangeType$ Card | ChangeNum$ 1 | Mandatory$ True | SpellDescription$ You search your library for a card, put that card into your hand, then shuffle your library. +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/library_of_lat_nam.jpg +SetInfo:6ED|Rare|http://magiccards.info/scans/en/6e/78.jpg +SetInfo:ALL|Rare|http://magiccards.info/scans/en/ai/47.jpg +Oracle:An opponent chooses one - You draw three cards at the beginning of the next turn's upkeep; or you search your library for a card, put that card into your hand, then shuffle your library. diff --git a/res/cardsfolder/m/misfortune.txt b/res/cardsfolder/m/misfortune.txt new file mode 100644 index 00000000000..1713d479166 --- /dev/null +++ b/res/cardsfolder/m/misfortune.txt @@ -0,0 +1,13 @@ +Name:Misfortune +ManaCost:1 B R G +Types:Sorcery +A:SP$ Charm | Cost$ 1 B R G | Chooser$ Opponent | Choices$ Fortune,Misfortune | SpellDescription$ An opponent chooses one - You put a +1/+1 counter on each creature you control and gain 4 life; or you put a -1/-1 counter on each creature that player controls and Misfortune deals 4 damage to him or her. +SVar:Fortune:DB$ PutCounterAll | ValidCards$ Creature.YouCtrl | CounterType$ P1P1 | CounterNum$ 1 | SubAbility$ DBGainLife | SpellDescription$ Put a +1/+1 counter on each creature you control. You gain 4 life. | SubAbility$ DBGainLife +SVar:DBGainLife:DB$ GainLife | LifeAmount$ 4 +SVar:Misfortune:DB$ PutCounterAll | ValidCards$ Creature.ChosenCtrl | CounterType$ M1M1 | CounterNum$ 1 | SubAbility$ DBLoseLife | SpellDescription$ you put a -1/-1 counter on each creature that player controls and Misfortune deals 4 damage to him or her. | SubAbility$ DBDamage +SVar:DBDamage:DB$ DealDamage | Defined$ ChosenPlayer | NumDmg$ 4 +SVar:ChooserDraws:DB$ Draw | NumCards$ 3 | Defined$ ChosenPlayer +SVar:RemAIDeck:True +SVar:Picture:http://www.wizards.com/global/images/magic/general/misfortune.jpg +SetInfo:ALL|Rare|http://magiccards.info/scans/en/ai/194.jpg +Oracle:An opponent chooses one - You put a +1/+1 counter on each creature you control and gain 4 life; or you put a -1/-1 counter on each creature that player controls and Misfortune deals 4 damage to him or her. diff --git a/src/main/java/forge/card/ability/ai/CharmAi.java b/src/main/java/forge/card/ability/ai/CharmAi.java index fcf44b20ee0..bcdc1f4715d 100644 --- a/src/main/java/forge/card/ability/ai/CharmAi.java +++ b/src/main/java/forge/card/ability/ai/CharmAi.java @@ -4,11 +4,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -import forge.card.ability.SpellAbilityAi; -import forge.card.ability.effects.CharmEffect; +import org.apache.commons.lang.math.RandomUtils; +import forge.card.ability.SpellAbilityAi;import forge.card.ability.effects.CharmEffect; import forge.card.spellability.AbilitySub; import forge.card.spellability.SpellAbility; import forge.game.player.AIPlayer; +import forge.game.player.Player; import forge.util.MyRandom; public class CharmAi extends SpellAbilityAi { @@ -22,7 +23,7 @@ public class CharmAi extends SpellAbilityAi { boolean timingRight = sa.isTrigger(); //is there a reason to play the charm now? List chooseFrom = CharmEffect.makePossibleOptions(sa); - List chosenList = chooseOptionsAi(ai, timingRight, chooseFrom, num, min); + List chosenList = chooseOptionsAi(ai, timingRight, chooseFrom, num, min, false); if (chosenList == null || chosenList.isEmpty()) { return false; @@ -32,9 +33,17 @@ public class CharmAi extends SpellAbilityAi { return r.nextFloat() <= Math.pow(.6667, sa.getActivationsThisTurn()); } - public static List chooseOptionsAi(final AIPlayer ai, boolean playNow, List choices, int num, int min) { + public static List chooseOptionsAi(final AIPlayer ai, boolean playNow, List choices, int num, int min, boolean opponentChoser) { List chosenList = new ArrayList(); + if (opponentChoser) { + // This branch is for "An Opponent chooses" Charm spells from Alliances + // Current just choose the first available spell, which seem generally less disastrous for the AI. + //return choices.subList(0, 1); + return choices.subList(1, choices.size()); + } + + for (int i = 0; i < num; i++) { AbilitySub thisPick = null; for (SpellAbility sub : choices) { @@ -57,4 +66,9 @@ public class CharmAi extends SpellAbilityAi { } return chosenList.size() >= min ? chosenList : null; } + + public static Player determineOpponentChooser(AIPlayer ai, SpellAbility sa, List opponents) { + return opponents.get(RandomUtils.nextInt(opponents.size())); + } + } diff --git a/src/main/java/forge/card/ability/effects/CharmEffect.java b/src/main/java/forge/card/ability/effects/CharmEffect.java index d1051a7e301..bddf06f663c 100644 --- a/src/main/java/forge/card/ability/effects/CharmEffect.java +++ b/src/main/java/forge/card/ability/effects/CharmEffect.java @@ -50,17 +50,37 @@ public class CharmEffect extends SpellAbilityEffect { final List choices = makePossibleOptions(sa); List chosen = null; - + Card source = sa.getSourceCard(); Player activator = sa.getActivatingPlayer(); - if (activator.isHuman()) { + Player chooser = sa.getActivatingPlayer(); + if (sa.hasParam("Chooser")) { + // Three modal cards require you to choose a player to make the modal choice' + // Two of these also reference the chosen player during the spell effect + String choose = sa.getParam("Chooser"); + List opponents = activator.getOpponents(); + int numOpps = opponents.size(); + if (numOpps == 1) { + chooser = opponents.get(0); + } else { + if (activator.isComputer()) { + chooser = CharmAi.determineOpponentChooser((AIPlayer)activator, sa, opponents); + } else { + chooser = GuiChoose.one("Choose an opponent", opponents); + } + } + source.setChosenPlayer(chooser); + } + + if (chooser.isHuman()) { + String modeTitle = String.format("%s activated %s - Choose a mode", activator, source); chosen = new ArrayList(); for (int i = 0; i < num; i++) { AbilitySub a; if (i < min) { - a = GuiChoose.one("Choose a mode", choices); + a = GuiChoose.one(modeTitle, choices); } else { - a = GuiChoose.oneOrNone("Choose a mode", choices); + a = GuiChoose.oneOrNone(modeTitle, choices); } if (null == a) { break; @@ -70,7 +90,7 @@ public class CharmEffect extends SpellAbilityEffect { chosen.add(a); } } else { - chosen = CharmAi.chooseOptionsAi((AIPlayer)activator, sa.isTrigger(), choices, num, min); + chosen = CharmAi.chooseOptionsAi((AIPlayer)chooser, sa.isTrigger(), choices, num, min, !chooser.equals(activator)); } chainAbilities(sa, chosen);