diff --git a/.gitattributes b/.gitattributes
index 70d86008c4f..e1133c8ec6a 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -826,6 +826,7 @@ forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorQues
forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorQuestDraftingProcess.java -text
forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorQuestLimited.java -text
forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorVariant.java -text
+forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorWinstonProcess.java -text
forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CProbabilities.java -text
forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CStatistics.java -text
forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/DeckController.java -text
@@ -886,10 +887,12 @@ forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/AvatarSelector.jav
forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuConstructed.java -text
forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuDraft.java -text
forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuSealed.java -text
+forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuWinston.java -text
forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/ConstructedGameMenu.java -text
forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/VSubmenuConstructed.java -text
forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/VSubmenuDraft.java -text
forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/VSubmenuSealed.java -text
+forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/VSubmenuWinston.java -text
forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/package-info.java -text
forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuAvatars.java -text
forge-gui-desktop/src/main/java/forge/screens/home/settings/CSubmenuDownloaders.java -text
@@ -16407,6 +16410,8 @@ forge-gui/src/main/java/forge/limited/LimitedPoolType.java -text
forge-gui/src/main/java/forge/limited/ReadDraftRankings.java -text
forge-gui/src/main/java/forge/limited/SealedCardPoolGenerator.java svneol=native#text/plain
forge-gui/src/main/java/forge/limited/SealedDeckBuilder.java svneol=native#text/plain
+forge-gui/src/main/java/forge/limited/WinstonDraft.java -text
+forge-gui/src/main/java/forge/limited/WinstonDraftAI.java -text
forge-gui/src/main/java/forge/limited/package-info.java svneol=native#text/plain
forge-gui/src/main/java/forge/match/MatchConstants.java -text
forge-gui/src/main/java/forge/match/input/ButtonUtil.java -text
diff --git a/forge-game/src/main/java/forge/game/GameType.java b/forge-game/src/main/java/forge/game/GameType.java
index 203a082f1f0..3186b2c9283 100644
--- a/forge-game/src/main/java/forge/game/GameType.java
+++ b/forge-game/src/main/java/forge/game/GameType.java
@@ -11,6 +11,7 @@ public enum GameType {
// deck composition rules, isPoolRestricted, can sideboard between matches
Sealed (DeckFormat.Limited, true, true, true, "Sealed"),
Draft (DeckFormat.Limited, true, true, true, "Draft"),
+ Winston (DeckFormat.Limited, true, true, true, "Winston"),
Gauntlet (DeckFormat.Limited, true, true, true, "Gauntlet"),
Quest (DeckFormat.QuestDeck, true, true, false, "Quest"),
QuestDraft (DeckFormat.Limited, true, true, true, "Quest Draft"),
diff --git a/forge-gui-desktop/src/main/java/forge/gui/framework/EDocID.java b/forge-gui-desktop/src/main/java/forge/gui/framework/EDocID.java
index 987e78bc41f..f8371e0fff7 100644
--- a/forge-gui-desktop/src/main/java/forge/gui/framework/EDocID.java
+++ b/forge-gui-desktop/src/main/java/forge/gui/framework/EDocID.java
@@ -12,6 +12,7 @@ import forge.screens.home.quest.*;
import forge.screens.home.sanctioned.VSubmenuConstructed;
import forge.screens.home.sanctioned.VSubmenuDraft;
import forge.screens.home.sanctioned.VSubmenuSealed;
+import forge.screens.home.sanctioned.VSubmenuWinston;
import forge.screens.home.settings.VSubmenuAvatars;
import forge.screens.home.settings.VSubmenuDownloaders;
import forge.screens.home.settings.VSubmenuPreferences;
@@ -59,6 +60,7 @@ public enum EDocID { /** */
HOME_CONSTRUCTED (VSubmenuConstructed.SINGLETON_INSTANCE), /** */
HOME_DRAFT (VSubmenuDraft.SINGLETON_INSTANCE), /** */
HOME_SEALED (VSubmenuSealed.SINGLETON_INSTANCE), /** */
+ HOME_WINSTON (VSubmenuWinston.SINGLETON_INSTANCE), /** */
HOME_RELEASE_NOTES (VSubmenuReleaseNotes.SINGLETON_INSTANCE),
REPORT_MESSAGE (VPrompt.SINGLETON_INSTANCE), /** */
diff --git a/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java b/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java
index c5978b4065f..6cb6470eb40 100644
--- a/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java
+++ b/forge-gui-desktop/src/main/java/forge/itemmanager/DeckManager.java
@@ -237,6 +237,10 @@ public final class DeckManager extends ItemManager {
screen = FScreen.DECK_EDITOR_DRAFT;
editorCtrl = new CEditorLimited(FModel.getDecks().getDraft(), screen);
break;
+ case Winston:
+ screen = FScreen.DECK_EDITOR_DRAFT;
+ editorCtrl = new CEditorLimited(FModel.getDecks().getWinston(), screen);
+ break;
default:
return;
diff --git a/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorWinstonProcess.java b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorWinstonProcess.java
new file mode 100644
index 00000000000..2e7fd713ec3
--- /dev/null
+++ b/forge-gui-desktop/src/main/java/forge/screens/deckeditor/controllers/CEditorWinstonProcess.java
@@ -0,0 +1,394 @@
+/*
+ * Forge: Play Magic: the Gathering.
+ * Copyright (C) 2011 Forge Team
+ *
+ * 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.screens.deckeditor.controllers;
+
+import forge.Singletons;
+import forge.UiCommand;
+import forge.card.MagicColor;
+import forge.deck.CardPool;
+import forge.deck.Deck;
+import forge.deck.DeckGroup;
+import forge.deck.DeckSection;
+import forge.model.FModel;
+import forge.screens.deckeditor.CDeckEditorUI;
+import forge.screens.deckeditor.views.VAllDecks;
+import forge.screens.deckeditor.views.VCurrentDeck;
+import forge.screens.deckeditor.views.VDeckgen;
+import forge.gui.framework.DragCell;
+import forge.gui.framework.FScreen;
+import forge.screens.home.sanctioned.CSubmenuWinston;
+import forge.toolbox.FOptionPane;
+import forge.itemmanager.CardManager;
+import forge.itemmanager.ItemManagerConfig;
+import forge.item.PaperCard;
+import forge.limited.BoosterDraft;
+import forge.limited.IBoosterDraft;
+import forge.limited.WinstonDraft;
+import forge.properties.ForgePreferences.FPref;
+import forge.util.ItemPool;
+import forge.util.MyRandom;
+
+import java.util.Map.Entry;
+
+/**
+ * Updates the deck editor UI as necessary draft selection mode.
+ *
+ *
(C at beginning of class name denotes a control class.)
+ *
+ * @author Forge
+ * @version $Id: CEditorDraftingProcess.java 24872 2014-02-17 07:35:47Z drdev $
+ */
+public class CEditorWinstonProcess extends ACEditorBase {
+ private IBoosterDraft boosterDraft;
+
+ private String ccAddLabel = "Add card";
+ private String ccAdd4Label = "Add card";
+ private Runnable ccAddCommand = null;
+ private Runnable ccAdd4Command = null;
+
+ private String ccTakeLabel = "Take pile";
+ private String ccPassLabel = "Pass pile";
+
+ private DragCell allDecksParent = null;
+ private DragCell deckGenParent = null;
+ private boolean saved = false;
+
+ //========== Constructor
+
+ /**
+ * Updates the deck editor UI as necessary draft selection mode.
+ */
+ public CEditorWinstonProcess() {
+ super(FScreen.DRAFTING_PROCESS);
+
+ final CardManager catalogManager = new CardManager(false);
+ final CardManager deckManager = new CardManager(false);
+
+ //hide filters and options panel so more of pack is visible by default
+ catalogManager.setHideViewOptions(1, true);
+
+ deckManager.setCaption("Draft Picks");
+
+ catalogManager.setAlwaysNonUnique(true);
+ deckManager.setAlwaysNonUnique(true);
+
+ this.setCatalogManager(catalogManager);
+ this.setDeckManager(deckManager);
+ }
+
+ /**
+ * Show gui.
+ *
+ * @param inBoosterDraft
+ * the in_booster draft
+ */
+ public final void showGui(final IBoosterDraft inBoosterDraft) {
+ this.boosterDraft = inBoosterDraft;
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.deckeditor.ACEditorBase#onAddItems()
+ */
+ @Override
+ protected void onAddItems(Iterable> items, boolean toAlternate) {
+ // This doesn't actually do anything, need to use buttons to interact
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.deckeditor.ACEditorBase#onRemoveItems()
+ */
+ @Override
+ protected void onRemoveItems(Iterable> items, boolean toAlternate) {
+ }
+
+ @Override
+ protected void buildAddContextMenu(EditorContextMenuBuilder cmb) {
+ cmb.addMoveItems("Draft", null);
+ }
+
+ @Override
+ protected void buildRemoveContextMenu(EditorContextMenuBuilder cmb) {
+ // no valid remove options
+ }
+
+ /**
+ *
+ * showChoices.
+ *
+ *
+ * @param list
+ * a {@link ItemPool} object.
+ */
+ private void showChoices(final ItemPool list) {
+ int packNumber = ((BoosterDraft) boosterDraft).getCurrentBoosterIndex() + 1;
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("Remaining: ");
+ sb.append(((WinstonDraft)boosterDraft).getDeckSize());
+ sb.append(" AI Cards: ");
+ sb.append(((WinstonDraft)boosterDraft).getAIDraftSize());
+ sb.append(" Pile");
+ sb.append(" ");
+ sb.append(packNumber);
+ sb.append(" - Cards");
+
+ this.getCatalogManager().setCaption(sb.toString());
+ this.getCatalogManager().setPool(list);
+
+ this.getDeckManager().refresh();
+ } // showChoices()
+
+ /**
+ *
+ * getPlayersDeck.
+ *
+ *
+ * @return a {@link forge.deck.Deck} object.
+ */
+ private Deck getPlayersDeck() {
+ final Deck deck = new Deck();
+
+ // add sideboard to deck
+ deck.getOrCreate(DeckSection.Sideboard).addAll(this.getDeckManager().getPool());
+
+ final String landSet = IBoosterDraft.LAND_SET_CODE[0].getCode();
+ final boolean isZendikarSet = landSet.equals("ZEN"); // we want to generate one kind of Zendikar lands at a time only
+ final boolean zendikarSetMode = MyRandom.getRandom().nextBoolean();
+
+ final int landsCount = 10;
+
+ for(String landName : MagicColor.Constant.BASIC_LANDS) {
+ int numArt = FModel.getMagicDb().getCommonCards().getArtCount(landName, landSet);
+ int minArtIndex = isZendikarSet ? (zendikarSetMode ? 1 : 5) : 1;
+ int maxArtIndex = isZendikarSet ? minArtIndex + 3 : numArt;
+
+ if (FModel.getPreferences().getPrefBoolean(FPref.UI_RANDOM_ART_IN_POOLS)) {
+
+ for (int i = minArtIndex; i <= maxArtIndex; i++) {
+ deck.get(DeckSection.Sideboard).add(landName, landSet, i, numArt > 1 ? landsCount : 30);
+ }
+ } else {
+ deck.get(DeckSection.Sideboard).add(landName, landSet, 30);
+ }
+ }
+
+ return deck;
+ } // getPlayersDeck()
+
+ /**
+ *
+ * saveDraft.
+ *
+ */
+ private void saveDraft() {
+ String s = FOptionPane.showInputDialog("Save this draft as:", "Save Draft", FOptionPane.QUESTION_ICON);
+
+ // Cancel button will be null; OK will return string.
+ // Must check for null value first, then string length.
+ // Recurse, if either null or empty string.
+ if (s == null || s.length() == 0) {
+ saveDraft();
+ return;
+ }
+
+ // Check for overwrite case
+ for (DeckGroup d : FModel.getDecks().getWinston()) {
+ if (s.equalsIgnoreCase(d.getName())) {
+ if (!FOptionPane.showConfirmDialog(
+ "There is already a deck named '" + s + "'. Overwrite?",
+ "Overwrite Deck?", false)) {
+ // If no overwrite, recurse.
+ saveDraft();
+ return;
+ }
+ break;
+ }
+ }
+
+ saved = true;
+
+ // TODO For pile drafts, only one other draft deck is made
+
+ // Construct computer's decks and save draft
+ final Deck[] computer = this.boosterDraft.getDecks();
+
+ final DeckGroup finishedDraft = new DeckGroup(s);
+ finishedDraft.setHumanDeck((Deck) this.getPlayersDeck().copyTo(s));
+ finishedDraft.addAiDecks(computer);
+
+ FModel.getDecks().getWinston().add(finishedDraft);
+ CSubmenuWinston.SINGLETON_INSTANCE.update();
+ FScreen.DRAFTING_PROCESS.close();
+
+ //open draft pool in Draft Deck Editor right away
+ Singletons.getControl().setCurrentScreen(FScreen.DECK_EDITOR_DRAFT);
+ CDeckEditorUI.SINGLETON_INSTANCE.setEditorController(new CEditorLimited(FModel.getDecks().getWinston(), FScreen.DECK_EDITOR_DRAFT));
+ CDeckEditorUI.SINGLETON_INSTANCE.getCurrentEditorController().getDeckController().load(null, s);
+ }
+
+ //========== Overridden from ACEditorBase
+
+ @Override
+ protected CardLimit getCardLimit() {
+ return CardLimit.None;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see forge.gui.deckeditor.ACEditorBase#getController()
+ */
+ @Override
+ public DeckController getDeckController() {
+ return null;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see forge.gui.deckeditor.ACEditorBase#updateView()
+ */
+ @Override
+ public void resetTables() {
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see forge.gui.deckeditor.ACEditorBase#show(forge.Command)
+ */
+ @Override
+ public void update() {
+ this.getCatalogManager().setup(ItemManagerConfig.DRAFT_PACK);
+ this.getDeckManager().setup(ItemManagerConfig.DRAFT_POOL);
+
+ ccAddLabel = this.getBtnAdd().getText();
+
+ if (this.getDeckManager().getPool() == null) { //avoid showing next choice or resetting pool if just switching back to Draft screen
+ this.getDeckManager().setPool((Iterable) null);
+ this.showChoices(this.boosterDraft.nextChoice());
+ }
+ else {
+ this.showChoices(this.getCatalogManager().getPool());
+ }
+
+ this.getBtnRemove().setVisible(false);
+ this.getBtnRemove4().setVisible(false);
+
+ this.getBtnAdd().setText(ccTakeLabel);
+ this.getBtnAdd4().setText(ccPassLabel);
+ // Link the buttons to the appropriate functions
+
+ this.ccAddCommand = this.getBtnAdd().getCommand();
+ this.ccAdd4Command = this.getBtnAdd4().getCommand();
+
+ this.getBtnAdd().setCommand(new UiCommand() {
+ @Override
+ public void run() {
+ CEditorWinstonProcess.this.takePile();
+ }
+ });
+ this.getBtnAdd4().setCommand(new UiCommand() {
+ @Override
+ public void run() {
+ CEditorWinstonProcess.this.passPile();
+ }
+ });
+
+ deckGenParent = removeTab(VDeckgen.SINGLETON_INSTANCE);
+ allDecksParent = removeTab(VAllDecks.SINGLETON_INSTANCE);
+
+ // set catalog table to single-selection only mode
+ //getCatalogManager().setAllowMultipleSelections(false);
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.deckeditor.controllers.ACEditorBase#canSwitchAway()
+ */
+ @Override
+ public boolean canSwitchAway(boolean isClosing) {
+ if (isClosing && !saved) {
+ String userPrompt =
+ "This will end the current draft and you will not be able to resume.\n\n" +
+ "Leave anyway?";
+ return FOptionPane.showConfirmDialog(userPrompt, "Leave Draft?", "Leave", "Cancel", false);
+ }
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.deckeditor.controllers.ACEditorBase#resetUIChanges()
+ */
+ @Override
+ public void resetUIChanges() {
+ //Restore button names
+ this.getBtnAdd().setText(ccAddLabel);
+ this.getBtnAdd4().setText(ccAdd4Label);
+ this.getBtnAdd().setCommand(this.ccAddCommand);
+ this.getBtnAdd4().setCommand(this.ccAdd4Command);
+
+ //Re-add buttons
+ this.getBtnRemove().setVisible(true);
+ this.getBtnRemove4().setVisible(true);
+
+ VCurrentDeck.SINGLETON_INSTANCE.getPnlHeader().setVisible(true);
+
+ //Re-add tabs
+ if (deckGenParent != null) {
+ deckGenParent.addDoc(VDeckgen.SINGLETON_INSTANCE);
+ }
+ if (allDecksParent != null) {
+ allDecksParent.addDoc(VAllDecks.SINGLETON_INSTANCE);
+ }
+
+ // set catalog table back to free-selection mode
+ getCatalogManager().setAllowMultipleSelections(true);
+ }
+
+ private void takePile() {
+ CardPool pool = ((WinstonDraft)boosterDraft).takeActivePile(true);
+ // Add pool to deck
+ this.getDeckManager().getPool().addAll(pool);
+
+ // get next booster pack
+ if (this.boosterDraft.hasNextChoice()) {
+ CardPool newPool = this.boosterDraft.nextChoice();
+ if (newPool != null) {
+ this.showChoices(newPool);
+ return;
+ }
+ }
+ // If we get here, there's no choices left. Finish the draft and then save it
+ this.boosterDraft.finishedDrafting();
+ this.saveDraft();
+ }
+
+ private void passPile() {
+ CardPool pool = ((WinstonDraft)boosterDraft).passActivePile(true);
+
+ if (pool != null) {
+ // Passed the third pile, draw the top card of the deck
+ this.getDeckManager().getPool().addAll(pool);
+ }
+ CardPool newPool = this.boosterDraft.nextChoice();
+ if (newPool != null) {
+ this.showChoices(newPool);
+ }
+ }
+}
+
diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/EMenuItem.java b/forge-gui-desktop/src/main/java/forge/screens/home/EMenuItem.java
index b1f8144a485..6fd25e48d35 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/home/EMenuItem.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/home/EMenuItem.java
@@ -10,6 +10,7 @@ public enum EMenuItem { /** */
CONSTRUCTED, /** */
LIMITED_DRAFT, /** */
LIMITED_SEALED, /** */
+ LIMITED_WINSTON,
QUEST_CHALLENGES, /** */
QUEST_DUELS, /** */
diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/VHomeUI.java b/forge-gui-desktop/src/main/java/forge/screens/home/VHomeUI.java
index 085176ca173..bff888cea50 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/home/VHomeUI.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/home/VHomeUI.java
@@ -31,6 +31,7 @@ import forge.screens.home.quest.*;
import forge.screens.home.sanctioned.VSubmenuConstructed;
import forge.screens.home.sanctioned.VSubmenuDraft;
import forge.screens.home.sanctioned.VSubmenuSealed;
+import forge.screens.home.sanctioned.VSubmenuWinston;
import forge.screens.home.settings.VSubmenuAvatars;
import forge.screens.home.settings.VSubmenuDownloaders;
import forge.screens.home.settings.VSubmenuPreferences;
@@ -115,6 +116,7 @@ public enum VHomeUI implements IVTopLevelUI {
allSubmenus.add(VSubmenuConstructed.SINGLETON_INSTANCE);
allSubmenus.add(VSubmenuDraft.SINGLETON_INSTANCE);
allSubmenus.add(VSubmenuSealed.SINGLETON_INSTANCE);
+ //allSubmenus.add(VSubmenuWinston.SINGLETON_INSTANCE);
allSubmenus.add(VSubmenuDuels.SINGLETON_INSTANCE);
allSubmenus.add(VSubmenuChallenges.SINGLETON_INSTANCE);
diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuDraft.java b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuDraft.java
index 794ffa2156b..9a3888251a9 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuDraft.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuDraft.java
@@ -75,7 +75,7 @@ public enum CSubmenuDraft implements ICDoc {
*/
@Override
public void update() {
- final VSubmenuDraft view = VSubmenuDraft.SINGLETON_INSTANCE;
+ final VSubmenuDraft view = VSubmenuDraft.SINGLETON_INSTANCE;
final JButton btnStart = view.getBtnStart();
view.getLstDecks().setPool(DeckProxy.getDraftDecks(FModel.getDecks().getDraft()));
diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuWinston.java b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuWinston.java
new file mode 100644
index 00000000000..7b4c5f97fa5
--- /dev/null
+++ b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/CSubmenuWinston.java
@@ -0,0 +1,162 @@
+package forge.screens.home.sanctioned;
+
+import forge.GuiBase;
+import forge.UiCommand;
+import forge.Singletons;
+import forge.deck.Deck;
+import forge.deck.DeckGroup;
+import forge.game.GameType;
+import forge.game.player.RegisteredPlayer;
+import forge.gui.GuiChoose;
+import forge.gui.SOverlayUtils;
+import forge.interfaces.IGuiBase;
+import forge.model.FModel;
+import forge.screens.deckeditor.CDeckEditorUI;
+import forge.deck.DeckProxy;
+import forge.screens.deckeditor.controllers.CEditorWinstonProcess;
+import forge.gui.framework.FScreen;
+import forge.gui.framework.ICDoc;
+import forge.toolbox.FOptionPane;
+import forge.itemmanager.ItemManagerConfig;
+import forge.limited.LimitedPoolType;
+import forge.limited.WinstonDraft;
+import forge.properties.ForgePreferences.FPref;
+
+import javax.swing.*;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Controls the draft submenu in the home UI.
+ *
+ *
(C at beginning of class name denotes a control class.)
+ *
+ */
+@SuppressWarnings("serial")
+public enum CSubmenuWinston implements ICDoc {
+ /** */
+ SINGLETON_INSTANCE;
+
+ private final UiCommand cmdDeckSelect = new UiCommand() {
+ @Override
+ public void run() {
+ VSubmenuWinston.SINGLETON_INSTANCE.getBtnStart().setEnabled(true);
+ }
+ };
+
+ /* (non-Javadoc)
+ * @see forge.control.home.IControlSubmenu#update()
+ */
+ @Override
+ public void initialize() {
+ final VSubmenuWinston view = VSubmenuWinston.SINGLETON_INSTANCE;
+
+ view.getLstDecks().setSelectCommand(cmdDeckSelect);
+
+ view.getBtnBuildDeck().setCommand(new UiCommand() {
+ @Override
+ public void run() {
+ setupDraft();
+ }
+ });
+
+ view.getBtnStart().addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(final ActionEvent e) {
+ startGame(GameType.Winston);
+ }
+ });
+ }
+
+ /* (non-Javadoc)
+ * @see forge.control.home.IControlSubmenu#update()
+ */
+ @Override
+ public void update() {
+ final VSubmenuWinston view = VSubmenuWinston.SINGLETON_INSTANCE;
+ final JButton btnStart = view.getBtnStart();
+
+ view.getLstDecks().setPool(DeckProxy.getWinstonDecks(FModel.getDecks().getWinston()));
+ view.getLstDecks().setup(ItemManagerConfig.WINSTON_DECKS);
+
+ if (!view.getLstDecks().getPool().isEmpty()) {
+ btnStart.setEnabled(true);
+ }
+
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override public void run() {
+ if (btnStart.isEnabled()) {
+ view.getBtnStart().requestFocusInWindow();
+ } else {
+ view.getBtnBuildDeck().requestFocusInWindow();
+ }
+ }
+ });
+ }
+
+ private void startGame(final GameType gameType) {
+ final DeckProxy humanDeck = VSubmenuWinston.SINGLETON_INSTANCE.getLstDecks().getSelectedItem();
+ final int aiIndex = 0;
+
+ if (humanDeck == null) {
+ FOptionPane.showErrorDialog("No deck selected for human.\n(You may need to build a new deck)", "No Deck");
+ return;
+ }
+
+ if (FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY)) {
+ String errorMessage = gameType.getDecksFormat().getDeckConformanceProblem(humanDeck.getDeck());
+ if (null != errorMessage) {
+ FOptionPane.showErrorDialog("Your deck " + errorMessage + " Please edit or choose a different deck.", "Invalid Deck");
+ return;
+ }
+ }
+
+ SwingUtilities.invokeLater(new Runnable() {
+ @Override
+ public void run() {
+ SOverlayUtils.startGameOverlay();
+ SOverlayUtils.showOverlay();
+ }
+ });
+
+ DeckGroup opponentDecks = FModel.getDecks().getWinston().get(humanDeck.getName());
+ Deck aiDeck = opponentDecks.getAiDecks().get(aiIndex);
+ if (aiDeck == null) {
+ throw new IllegalStateException("Draft: Computer deck is null!");
+ }
+
+ IGuiBase fc = GuiBase.getInterface();
+ List starter = new ArrayList();
+ starter.add(new RegisteredPlayer(humanDeck.getDeck()).setPlayer(fc.getGuiPlayer()));
+ starter.add(new RegisteredPlayer(aiDeck).setPlayer(fc.createAiPlayer()));
+
+ Singletons.getControl().startMatch(GameType.Winston, starter);
+ }
+
+ /** */
+ private void setupDraft() {
+ // Determine what kind of booster draft to run
+ final LimitedPoolType poolType = GuiChoose.oneOrNone("Choose Draft Format", LimitedPoolType.values());
+ if (poolType == null) { return; }
+
+ WinstonDraft draft = WinstonDraft.createDraft(poolType);
+ if (draft == null) { return; }
+
+ final CEditorWinstonProcess draftController = new CEditorWinstonProcess();
+ draftController.showGui(draft);
+
+ Singletons.getControl().setCurrentScreen(FScreen.DRAFTING_PROCESS);
+ CDeckEditorUI.SINGLETON_INSTANCE.setEditorController(draftController);
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.framework.ICDoc#getCommandOnSelect()
+ */
+ @Override
+ public UiCommand getCommandOnSelect() {
+ return null;
+ }
+}
diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/VSubmenuWinston.java b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/VSubmenuWinston.java
new file mode 100644
index 00000000000..480fe3cf123
--- /dev/null
+++ b/forge-gui-desktop/src/main/java/forge/screens/home/sanctioned/VSubmenuWinston.java
@@ -0,0 +1,177 @@
+package forge.screens.home.sanctioned;
+
+import forge.game.GameType;
+import forge.gui.framework.DragCell;
+import forge.gui.framework.DragTab;
+import forge.gui.framework.EDocID;
+import forge.itemmanager.DeckManager;
+import forge.itemmanager.ItemManagerContainer;
+import forge.screens.home.*;
+import forge.screens.home.VHomeUI.PnlDisplay;
+import forge.toolbox.*;
+import net.miginfocom.swing.MigLayout;
+
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * Assembles Swing components of draft submenu singleton.
+ *
+ *
(V at beginning of class name denotes a view class.)
+ */
+public enum VSubmenuWinston implements IVSubmenu {
+ /** */
+ SINGLETON_INSTANCE;
+
+ // Fields used with interface IVDoc
+ private DragCell parentCell;
+ private final DragTab tab = new DragTab("Winston Draft");
+
+ /** */
+ private final LblHeader lblTitle = new LblHeader("Sanctioned Format: Winston Draft");
+
+ private final JPanel pnlStart = new JPanel();
+ private final StartButton btnStart = new StartButton();
+
+ private final DeckManager lstDecks = new DeckManager(GameType.Winston);
+ private final JList lstAI = new FList();
+
+ private final JLabel lblInfo = new FLabel.Builder()
+ .fontAlign(SwingConstants.LEFT).fontSize(16).fontStyle(Font.BOLD)
+ .text("Build or select a deck").build();
+
+ private final FLabel lblDir1 = new FLabel.Builder()
+ .text("In Winston Draft mode, two players draft 6 packs of cards by piles.")
+ .fontSize(12).build();
+
+ private final FLabel lblDir2 = new FLabel.Builder()
+ .text("Build a deck from the cards you choose. The AI will do the same.")
+ .fontSize(12).build();
+
+ private final FLabel lblDir3 = new FLabel.Builder()
+ .text("Then, play against the AI opponent you drafted against.")
+ .fontSize(12).build();
+
+ private final FLabel btnBuildDeck = new FLabel.ButtonBuilder().text("New Winston Draft Game").fontSize(16).build();
+
+ /**
+ * Constructor.
+ */
+ private VSubmenuWinston() {
+ lstAI.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ btnStart.setEnabled(false);
+
+ lblTitle.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));
+ lstDecks.setCaption("Winston Draft Decks");
+
+ pnlStart.setLayout(new MigLayout("insets 0, gap 0, wrap 2"));
+ pnlStart.setOpaque(false);
+ pnlStart.add(btnStart);
+ }
+
+ /* (non-Javadoc)
+ * @see forge.view.home.IViewSubmenu#getGroup()
+ */
+ @Override
+ public EMenuGroup getGroupEnum() {
+ return EMenuGroup.SANCTIONED;
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.home.IVSubmenu#getMenuTitle()
+ */
+ @Override
+ public String getMenuTitle() {
+ return "Winston Draft";
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.home.IVSubmenu#getItemEnum()
+ */
+ @Override
+ public EDocID getItemEnum() {
+ return EDocID.HOME_WINSTON;
+ }
+
+ /** @return {@link forge.gui.toolbox.FLabel} */
+ public FLabel getBtnBuildDeck() {
+ return this.btnBuildDeck;
+ }
+
+ /** @return {@link javax.swing.JButton} */
+ public JButton getBtnStart() {
+ return this.btnStart;
+ }
+
+ /** @return {@link forge.gui.toolbox.itemmanager.DeckManager} */
+ public DeckManager getLstDecks() {
+ return lstDecks;
+ }
+
+ //========== Overridden from IVDoc
+
+ /* (non-Javadoc)
+ * @see forge.view.home.IViewSubmenu#populate()
+ */
+ @Override
+ public void populate() {
+ PnlDisplay pnlDisplay = VHomeUI.SINGLETON_INSTANCE.getPnlDisplay();
+ pnlDisplay.removeAll();
+ pnlDisplay.setLayout(new MigLayout("insets 0, gap 0, wrap, ax right"));
+ pnlDisplay.add(lblTitle, "w 80%!, h 40px!, gap 0 0 15px 15px, ax right");
+
+ pnlDisplay.add(lblInfo, "w 80%!, h 30px!, gap 0 10% 20px 5px");
+ pnlDisplay.add(lblDir1, "gap 0 0 0 5px");
+ pnlDisplay.add(lblDir2, "gap 0 0 0 5px");
+ pnlDisplay.add(lblDir3, "gap 0 0 0 20px");
+
+ pnlDisplay.add(btnBuildDeck, "w 250px!, h 30px!, ax center, gap 0 10% 0 20px");
+ pnlDisplay.add(new ItemManagerContainer(lstDecks), "w 80%!, gap 0 10% 0 0, pushy, growy");
+
+ pnlDisplay.add(pnlStart, "gap 0 10% 50px 50px, ax center");
+
+ pnlDisplay.repaint();
+ pnlDisplay.revalidate();
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.framework.IVDoc#getDocumentID()
+ */
+ @Override
+ public EDocID getDocumentID() {
+ return EDocID.HOME_WINSTON;
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.framework.IVDoc#getTabLabel()
+ */
+ @Override
+ public DragTab getTabLabel() {
+ return tab;
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.framework.IVDoc#setParentCell(forge.gui.framework.DragCell)
+ */
+ @Override
+ public void setParentCell(final DragCell cell0) {
+ this.parentCell = cell0;
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.framework.IVDoc#getParentCell()
+ */
+ @Override
+ public DragCell getParentCell() {
+ return parentCell;
+ }
+
+ /* (non-Javadoc)
+ * @see forge.gui.framework.IVDoc#getLayoutControl()
+ */
+ @Override
+ public CSubmenuWinston getLayoutControl() {
+ return CSubmenuWinston.SINGLETON_INSTANCE;
+ }
+}
diff --git a/forge-gui-desktop/src/test/java/forge/BoosterDraftTest.java b/forge-gui-desktop/src/test/java/forge/BoosterDraftTest.java
index 3928a752a73..3c3b5c43e48 100644
--- a/forge-gui-desktop/src/test/java/forge/BoosterDraftTest.java
+++ b/forge-gui-desktop/src/test/java/forge/BoosterDraftTest.java
@@ -105,4 +105,9 @@ public class BoosterDraftTest implements IBoosterDraft {
public void finishedDrafting() {
}
+
+ @Override
+ public boolean isPileDraft() {
+ return false;
+ }
}
diff --git a/forge-gui/src/main/java/forge/deck/DeckProxy.java b/forge-gui/src/main/java/forge/deck/DeckProxy.java
index d9b0d1a3607..43f1e4c1186 100644
--- a/forge-gui/src/main/java/forge/deck/DeckProxy.java
+++ b/forge-gui/src/main/java/forge/deck/DeckProxy.java
@@ -416,6 +416,15 @@ public class DeckProxy implements InventoryItem {
return decks;
}
+ @SuppressWarnings("unchecked")
+ public static Iterable getWinstonDecks(IStorage draft) {
+ ArrayList decks = new ArrayList();
+ for (DeckGroup d : draft) {
+ decks.add(new DeckProxy(d, "Winston", ((Function)(Object)DeckGroup.FN_HUMAN_DECK), GameType.Winston, draft));
+ }
+ return decks;
+ }
+
public static final Predicate IS_WHITE = new Predicate() {
@Override
public boolean apply(final DeckProxy deck) {
diff --git a/forge-gui/src/main/java/forge/itemmanager/ItemManagerConfig.java b/forge-gui/src/main/java/forge/itemmanager/ItemManagerConfig.java
index 8e575d39bae..15f28188b30 100644
--- a/forge-gui/src/main/java/forge/itemmanager/ItemManagerConfig.java
+++ b/forge-gui/src/main/java/forge/itemmanager/ItemManagerConfig.java
@@ -58,6 +58,8 @@ public enum ItemManagerConfig {
null, null, 3, 0),
SEALED_DECKS(SColumnUtil.getDecksDefaultColumns(true, false), false, false, false,
null, null, 3, 0),
+ WINSTON_DECKS(SColumnUtil.getDecksDefaultColumns(true, false), false, false, false,
+ null, null, 3, 0),
QUEST_DECKS(SColumnUtil.getDecksDefaultColumns(true, false), false, false, false,
null, null, 3, 0),
PRECON_DECKS(SColumnUtil.getDecksDefaultColumns(false, false), false, false, false,
diff --git a/forge-gui/src/main/java/forge/limited/BoosterDraft.java b/forge-gui/src/main/java/forge/limited/BoosterDraft.java
index cd829617229..fc725744d7e 100644
--- a/forge-gui/src/main/java/forge/limited/BoosterDraft.java
+++ b/forge-gui/src/main/java/forge/limited/BoosterDraft.java
@@ -50,31 +50,35 @@ import java.util.Map.Entry;
* Booster Draft Format.
*
*/
-public final class BoosterDraft implements IBoosterDraft {
+public class BoosterDraft implements IBoosterDraft {
private final BoosterDraftAI draftAI = new BoosterDraftAI();
private static final int N_PLAYERS = 8;
public static final String FILE_EXT = ".draft";
- private int nextBoosterGroup = 0;
+ protected int nextBoosterGroup = 0;
private int currentBoosterSize = 0;
private int currentBoosterPick = 0;
private List> pack; // size 8
/** The draft picks. */
private final Map draftPicks = new TreeMap();
- private final LimitedPoolType draftFormat;
+ protected LimitedPoolType draftFormat;
- private final List>> product = new ArrayList>>();
+ protected final List>> product = new ArrayList>>();
public static BoosterDraft createDraft(final LimitedPoolType draftType) {
BoosterDraft draft = new BoosterDraft(draftType);
+ if (!draft.generateProduct()) { return null; }
+ return draft;
+ }
- switch (draftType) {
+ protected boolean generateProduct() {
+ switch (this.draftFormat) {
case Full: // Draft from all cards in Forge
Supplier> s = new UnOpenedProduct(SealedProduct.Template.genericBooster);
for (int i = 0; i < 3; i++) {
- draft.product.add(s);
+ this.product.add(s);
}
IBoosterDraft.LAND_SET_CODE[0] = CardEdition.Predicates.getRandomSetWithAllBasicLands(FModel.getMagicDb().getEditions());
break;
@@ -82,7 +86,7 @@ public final class BoosterDraft implements IBoosterDraft {
case Block: // Draft from cards by block or set
case FantasyBlock:
List blocks = new ArrayList();
- IStorage storage = draftType == LimitedPoolType.Block
+ IStorage storage = this.draftFormat == LimitedPoolType.Block
? FModel.getBlocks() : FModel.getFantasyBlocks();
for (CardBlock b : storage) {
@@ -92,12 +96,12 @@ public final class BoosterDraft implements IBoosterDraft {
}
final CardBlock block = SGuiChoose.oneOrNone("Choose Block", blocks);
- if (block == null) { return null; }
+ if (block == null) { return false; }
final CardEdition[] cardSets = block.getSets();
if (cardSets.length == 0) {
SOptionPane.showErrorDialog(block.toString() + " does not contain any set combinations.");
- return null;
+ return false;
}
final Stack sets = new Stack();
@@ -115,18 +119,18 @@ public final class BoosterDraft implements IBoosterDraft {
if (sets.size() > 1) {
final Object p = SGuiChoose.oneOrNone("Choose Set Combination", getSetCombos(sets));
- if (p == null) { return null; }
+ if (p == null) { return false; }
final String[] pp = p.toString().split("/");
for (int i = 0; i < nPacks; i++) {
- draft.product.add(block.getBooster(pp[i]));
+ this.product.add(block.getBooster(pp[i]));
}
}
else {
IUnOpenedProduct product1 = block.getBooster(sets.get(0));
for (int i = 0; i < nPacks; i++) {
- draft.product.add(product1);
+ this.product.add(product1);
}
}
@@ -134,29 +138,28 @@ public final class BoosterDraft implements IBoosterDraft {
break;
case Custom:
- final List myDrafts = draft.loadCustomDrafts();
+ final List myDrafts = this.loadCustomDrafts();
if (myDrafts.isEmpty()) {
SOptionPane.showMessageDialog("No custom draft files found.");
}
else {
final CustomLimited customDraft = SGuiChoose.oneOrNone("Choose Custom Draft", myDrafts);
- if (customDraft == null) { return null; }
+ if (customDraft == null) { return false; }
- draft.setupCustomDraft(customDraft);
+ this.setupCustomDraft(customDraft);
}
break;
default:
- throw new NoSuchElementException("Draft for mode " + draftType + " has not been set up!");
+ throw new NoSuchElementException("Draft for mode " + this.draftFormat + " has not been set up!");
}
- draft.pack = draft.get8BoosterPack();
- return draft;
+ this.pack = this.get8BoosterPack();
+ return true;
}
-
- public static BoosterDraft createDraft(final LimitedPoolType draftType, final CardBlock block, final String[] boosters) {
-
+
+ public static BoosterDraft createDraft(final LimitedPoolType draftType, final CardBlock block, final String[] boosters) {
BoosterDraft draft = new BoosterDraft(draftType);
final int nPacks = boosters.length;
@@ -169,18 +172,20 @@ public final class BoosterDraft implements IBoosterDraft {
draft.pack = draft.get8BoosterPack();
return draft;
-
}
+ protected BoosterDraft() {
+ this.draftFormat = LimitedPoolType.Full;
+ }
/**
*
* Constructor for BoosterDraft_1.
*
- *
+ *
* @param draftType
* a {@link java.lang.String} object.
*/
- private BoosterDraft(final LimitedPoolType draftType) {
+ protected BoosterDraft(final LimitedPoolType draftType) {
this.draftAI.setBd(this);
this.draftFormat = draftType;
}
@@ -233,7 +238,7 @@ public final class BoosterDraft implements IBoosterDraft {
* nextChoice.
*
*
- * @return a {@link forge.CardList} object.
+ * @return a {@link forge.deck.CardPool} object.
*/
@Override
public CardPool nextChoice() {
@@ -252,7 +257,7 @@ public final class BoosterDraft implements IBoosterDraft {
* get8BoosterPack.
*
*
- * @return an array of {@link forge.CardList} objects.
+ * @return an array of {@link forge.deck.CardPool} objects.
*/
public List> get8BoosterPack() {
if (this.nextBoosterGroup >= this.product.size()) {
@@ -284,7 +289,7 @@ public final class BoosterDraft implements IBoosterDraft {
return this.draftAI.getDecks();
}
- private void computerChoose() {
+ protected void computerChoose() {
final int iHumansBooster = this.getCurrentBoosterIndex();
int iPlayer = 0;
for (int i = 1; i < this.pack.size(); i++) {
@@ -377,6 +382,11 @@ public final class BoosterDraft implements IBoosterDraft {
HttpUtil.upload(ForgeConstants.URL_DRAFT_UPLOAD + "?fmt=" + draftFormat, outDraftData);
}
+ @Override
+ public boolean isPileDraft() {
+ return false;
+ }
+
private static List getSetCombos(final List setz) {
String[] sets = setz.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
List setCombos = new ArrayList();
diff --git a/forge-gui/src/main/java/forge/limited/BoosterDraftAI.java b/forge-gui/src/main/java/forge/limited/BoosterDraftAI.java
index f2103f56dba..97a07e76de2 100644
--- a/forge-gui/src/main/java/forge/limited/BoosterDraftAI.java
+++ b/forge-gui/src/main/java/forge/limited/BoosterDraftAI.java
@@ -45,11 +45,11 @@ public class BoosterDraftAI {
/**
* Constant nDecks=7.
*/
- private static final int N_DECKS = 7;
+ protected static final int N_DECKS = 7;
// holds all the cards for each of the computer's decks
- private final List> deck = new ArrayList>();
- private final ArrayList playerColors = new ArrayList();
+ protected final List> deck = new ArrayList>();
+ protected final ArrayList playerColors = new ArrayList();
// roughly equivalent to 25 ranks in a core set, or 15 ranks in a small set
private static final double TAKE_BEST_THRESHOLD = 0.1;
@@ -63,7 +63,7 @@ public class BoosterDraftAI {
* List of CardPrinted
* @param player
* a int.
- * @return a {@link forge.CardList} object.
+ * @return a {@link forge.item.PaperCard} object.
*/
public PaperCard choose(final List chooseFrom, final int player) {
if (ForgePreferences.DEV_MODE) {
diff --git a/forge-gui/src/main/java/forge/limited/DeckColors.java b/forge-gui/src/main/java/forge/limited/DeckColors.java
index fda524518b2..b902879c317 100644
--- a/forge-gui/src/main/java/forge/limited/DeckColors.java
+++ b/forge-gui/src/main/java/forge/limited/DeckColors.java
@@ -22,6 +22,8 @@ import forge.card.MagicColor;
import forge.card.mana.ManaCost;
import forge.item.IPaperCard;
+import java.util.List;
+
/**
* Created by IntelliJ IDEA. User: dhudson Date: 6/24/11 Time: 8:42 PM To change
* this template use File | Settings | File Templates.
@@ -64,6 +66,14 @@ class DeckColors {
}
}
+ public void setColorsByList(List colors) {
+ colorMask = 0;
+ for (Byte col : colors) {
+ colorMask |= col;
+ }
+ chosen = null;
+ }
+
public boolean canChoseMoreColors() {
return getChosenColors().countColors() < MAX_COLORS;
diff --git a/forge-gui/src/main/java/forge/limited/IBoosterDraft.java b/forge-gui/src/main/java/forge/limited/IBoosterDraft.java
index e0af1085c94..268ffb68a17 100644
--- a/forge-gui/src/main/java/forge/limited/IBoosterDraft.java
+++ b/forge-gui/src/main/java/forge/limited/IBoosterDraft.java
@@ -76,4 +76,6 @@ public interface IBoosterDraft {
*/
void finishedDrafting();
+ boolean isPileDraft();
+
}
diff --git a/forge-gui/src/main/java/forge/limited/WinstonDraft.java b/forge-gui/src/main/java/forge/limited/WinstonDraft.java
new file mode 100644
index 00000000000..28fa75181ba
--- /dev/null
+++ b/forge-gui/src/main/java/forge/limited/WinstonDraft.java
@@ -0,0 +1,178 @@
+package forge.limited;
+
+import com.google.common.base.Predicates;
+import com.google.common.base.Supplier;
+import com.google.common.collect.Iterables;
+import forge.deck.CardPool;
+import forge.deck.Deck;
+import forge.item.IPaperCard;
+import forge.item.PaperCard;
+import forge.quest.data.GameFormatQuest;
+import forge.util.MyRandom;
+
+import java.util.*;
+
+public class WinstonDraft extends BoosterDraft {
+ private WinstonDraftAI draftAI = null;
+ private static int NUM_PILES = 3;
+ private static int NUM_PLAYERS = 2;
+
+ private Stack deck; // main deck where all cards
+ private List> piles; // 3 piles to draft from
+
+ public static WinstonDraft createDraft(final LimitedPoolType draftType) {
+ WinstonDraft draft = new WinstonDraft(draftType);
+ if (!draft.generateProduct()) {
+ return null;
+ }
+ draft.initializeWinstonDraft();
+ return draft;
+ }
+
+ private WinstonDraft(LimitedPoolType draftType) {
+ draftFormat = draftType;
+ draftAI = new WinstonDraftAI();
+
+ }
+
+ private void initializeWinstonDraft() {
+ this.deck = new Stack();
+ for (int i = 0; i < this.product.size(); i++) {
+ Supplier> supply = this.product.get(i);
+ for(int j = 0; j < NUM_PLAYERS; j++) {
+ // Remove Basic Lands from draft for simplicity
+ for (PaperCard paperCard : Iterables.filter(supply.get(), Predicates.not(PaperCard.Predicates.Presets.IS_BASIC_LAND))) {
+ this.deck.add(paperCard);
+ }
+ }
+ }
+ Collections.shuffle(this.deck, MyRandom.getRandom());
+
+ // Create three Winston piles, adding the top card from the Winston deck to start each pile
+ this.piles = new ArrayList<>();
+ for(int i = 0; i < NUM_PILES; i++) {
+ List pile = new ArrayList();
+ pile.add(this.deck.pop());
+ this.piles.add(pile);
+ }
+
+ this.nextBoosterGroup = 0;
+
+ draftAI.setDraft(this);
+
+ if (MyRandom.percentTrue(50)) {
+ // 50% chance of the AI picking the first card in a Winston Draft
+ //this.computerChoose();
+ }
+ }
+
+ @Override
+ public CardPool nextChoice() {
+ // This is called for two reasons: Skipping a pile, and getting the next one in line
+ // Or taking a pile and getting reset back to the first non-empty pile
+ int nextPile = -1;
+ for(int i = nextBoosterGroup; i < this.piles.size(); i++) {
+ if (this.piles.get(i).size() > 0) {
+ nextPile = i;
+ break;
+ }
+ }
+
+ if (nextPile < 0 || nextPile > this.piles.size())
+ return null;
+
+ nextBoosterGroup = nextPile;
+
+ return getPoolByPile(nextBoosterGroup);
+ }
+
+ public CardPool getActivePool() {
+ return getPoolByPile(this.nextBoosterGroup);
+ }
+
+ private CardPool getPoolByPile(int i) {
+ CardPool result = new CardPool();
+ result.addAllFlat(this.piles.get(i));
+ return result;
+ }
+
+ public void computerChoose() {
+ nextBoosterGroup = 0;
+ draftAI.choose();
+ }
+
+ public void refillPile(List pile) {
+ if (this.deck.size() > 0)
+ pile.add(this.deck.pop());
+ }
+
+ public int getNextChoice(int startPile) {
+ for(int i = startPile; i < NUM_PILES; i++) {
+ if (this.piles.get(i).size() > 0)
+ return i;
+ }
+ // All piles are empty, so draft is about to end.
+ return -1;
+ }
+
+ public boolean hasNextChoice() {
+ return getNextChoice(0) >= 0;
+ }
+
+ public boolean isLastPileAndEmptyDeck(int pile) {
+ return this.deck.size() == 0 && getNextChoice(pile+1) >= 0;
+ }
+
+ public int getCurrentBoosterIndex() {
+ return nextBoosterGroup;
+ }
+
+ public CardPool takeActivePile(boolean humanAction) {
+ CardPool pool = getPoolByPile(this.nextBoosterGroup);
+
+ this.piles.get(this.nextBoosterGroup).clear();
+ this.refillPile(this.piles.get(this.nextBoosterGroup));
+ this.nextBoosterGroup = 0;
+ if (humanAction)
+ computerChoose();
+ return pool;
+ }
+
+ public CardPool passActivePile(boolean humanAction) {
+ this.refillPile(this.piles.get(this.nextBoosterGroup));
+ this.nextBoosterGroup++;
+ if (this.nextBoosterGroup >= this.piles.size()) {
+ CardPool pool = new CardPool();
+ if (this.deck.size() > 0)
+ pool.add(this.deck.pop());
+ this.nextBoosterGroup = 0;
+ if (humanAction)
+ computerChoose();
+ return pool;
+ }
+ return null;
+ }
+
+ public int getNumPiles() {
+ return NUM_PILES;
+ }
+
+ @Override
+ public Deck[] getDecks() {
+ this.determineAIDeckColors();
+ return this.draftAI.getDecks();
+ }
+
+ public void determineAIDeckColors() {
+ this.draftAI.determineDeckColor();
+ }
+
+ @Override
+ public boolean isPileDraft() {
+ return true;
+ }
+
+ public int getDeckSize() { return this.deck.size(); }
+
+ public int getAIDraftSize() { return this.draftAI.getAIDraftSize(); }
+}
diff --git a/forge-gui/src/main/java/forge/limited/WinstonDraftAI.java b/forge-gui/src/main/java/forge/limited/WinstonDraftAI.java
new file mode 100644
index 00000000000..e71f7bc1dbc
--- /dev/null
+++ b/forge-gui/src/main/java/forge/limited/WinstonDraftAI.java
@@ -0,0 +1,114 @@
+package forge.limited;
+
+import forge.card.ColorSet;
+import forge.card.MagicColor;
+import forge.deck.CardPool;
+import forge.game.card.CardColor;
+import forge.item.PaperCard;
+import forge.util.MyRandom;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class WinstonDraftAI extends BoosterDraftAI{
+
+ private WinstonDraft draft = null;
+ private static final int N_DECKS = 1;
+ private ArrayList colorPreference = new ArrayList<>();
+
+ public WinstonDraft getDraft() {
+ return draft;
+ }
+
+ public void setDraft(WinstonDraft draft) {
+ this.draft = draft;
+ }
+
+ public WinstonDraftAI() {
+ this.deck.clear();
+ this.playerColors.clear();
+ for (int i = 0; i < N_DECKS; i++) {
+ this.deck.add(new ArrayList());
+ this.playerColors.add(new DeckColors());
+ }
+ }
+
+ public void determineDeckColor() {
+ // Turn colorPreference into playerColors
+ int count[] = tallyDeckColors();
+ // Just take the three best colors, but maybe sometimes only take best two
+ this.playerColors.get(0).setColorsByList(colorPreference.subList(0, 3));
+ }
+
+ public void choose() {
+ boolean takenPile = true;
+ CardPool acquire = null;
+ while(takenPile) {
+ CardPool pool = draft.getActivePool();
+ // Determine if the current pool is worth taking
+ // For now, each card in a pile is worth 10 points. Compare versus a d100 roll
+ String desc = "Pile " + (draft.getCurrentBoosterIndex()+1);
+ int value = pool.countAll() * 10;
+ // If this is the last pile, and the deck is empty, definitely take the pile!
+ boolean takePile = MyRandom.percentTrue(value) || draft.isLastPileAndEmptyDeck(draft.getCurrentBoosterIndex());
+
+ if (takePile) {
+ acquire = draft.takeActivePile(false);
+ } else {
+ acquire = draft.passActivePile(false);
+ desc = "Top of Deck";
+ }
+ if (acquire != null) {
+ System.out.println("AI taking " + desc + "(" + acquire.countAll() + " cards).");
+ takenPile = false;
+ }
+ }
+ if (acquire != null) {
+ this.deck.get(0).addAll(acquire.toFlatList());
+ //tallyDeckColors();
+ }
+ }
+
+ private int[] tallyDeckColors() {
+ int[] colorCount = new int[5];
+
+ for(PaperCard pc : this.deck.get(0)) {
+ ColorSet colors = pc.getRules().getColor();
+ if (colors.hasWhite())
+ colorCount[0]++;
+ if (colors.hasBlue())
+ colorCount[1]++;
+ if (colors.hasBlack())
+ colorCount[2]++;
+ if (colors.hasRed())
+ colorCount[3]++;
+ if (colors.hasGreen())
+ colorCount[4]++;
+ }
+
+ // Just keep order or should I keep order/value pairs?
+ colorPreference.clear();
+ for(int i = 0; i < colorCount.length; i++) {
+ // Sort colors in order.
+ Byte col = MagicColor.WUBRG[i];
+ int spot = 0;
+ for (int j = 0; j < i; j++) {
+ if (colorCount[i] > colorCount[j]) {
+ // If new color has more than the current slot, we need to add into that slot
+ // And push all remaining colors further down
+ break;
+ }
+ spot++;
+ }
+ colorPreference.add(spot, col);
+ }
+ // Is this the right order?
+ return colorCount;
+ }
+
+ public int getAIDraftSize() {
+ return this.deck.get(0).size();
+ }
+}
diff --git a/forge-gui/src/main/java/forge/model/CardCollections.java b/forge-gui/src/main/java/forge/model/CardCollections.java
index f1d7764a6fa..2ec1b02aace 100644
--- a/forge-gui/src/main/java/forge/model/CardCollections.java
+++ b/forge-gui/src/main/java/forge/model/CardCollections.java
@@ -37,6 +37,7 @@ public class CardCollections {
private final IStorage constructed;
private final IStorage draft;
private final IStorage sealed;
+ private final IStorage winston;
private final IStorage cube;
private final IStorage scheme;
private final IStorage plane;
@@ -53,11 +54,11 @@ public class CardCollections {
this.constructed = new StorageImmediatelySerialized("Constructed decks", new DeckStorage(new File(ForgeConstants.DECK_CONSTRUCTED_DIR), true), true);
this.draft = new StorageImmediatelySerialized("Draft deck sets", new DeckGroupSerializer(new File(ForgeConstants.DECK_DRAFT_DIR)));
this.sealed = new StorageImmediatelySerialized("Sealed deck sets", new DeckGroupSerializer(new File(ForgeConstants.DECK_SEALED_DIR)));
+ this.winston = new StorageImmediatelySerialized("Winston draft deck sets", new DeckGroupSerializer(new File(ForgeConstants.DECK_WINSTON_DIR)));
this.cube = new StorageImmediatelySerialized("Cubes", new DeckStorage(new File(ForgeConstants.DECK_CUBE_DIR)));
this.scheme = new StorageImmediatelySerialized("Archenemy decks", new DeckStorage(new File(ForgeConstants.DECK_SCHEME_DIR)));
this.plane = new StorageImmediatelySerialized("Planechase decks", new DeckStorage(new File(ForgeConstants.DECK_PLANE_DIR)));
this.commander = new StorageImmediatelySerialized("Commander decks", new DeckStorage(new File(ForgeConstants.DECK_COMMANDER_DIR)));
-
sw.stop();
System.out.printf("Read decks (%d ms): %d constructed, %d sealed, %d draft, %d cubes, %d scheme, %d planar, %d commander.%n", sw.getTime(), constructed.size(), sealed.size(), draft.size(), cube.size(), scheme.size(), plane.size(),commander.size());
// int sum = constructed.size() + sealed.size() + draft.size() + cube.size() + scheme.size() + plane.size();
@@ -85,6 +86,10 @@ public class CardCollections {
return this.draft;
}
+ public final IStorage getWinston() {
+ return this.winston;
+ }
+
/**
* Gets the cubes.
*
diff --git a/forge-gui/src/main/java/forge/properties/ForgeConstants.java b/forge-gui/src/main/java/forge/properties/ForgeConstants.java
index 101bceab668..a199c129788 100644
--- a/forge-gui/src/main/java/forge/properties/ForgeConstants.java
+++ b/forge-gui/src/main/java/forge/properties/ForgeConstants.java
@@ -102,6 +102,7 @@ public final class ForgeConstants {
public static final String DECK_BASE_DIR = USER_DIR + "decks/";
public static final String DECK_CONSTRUCTED_DIR = DECK_BASE_DIR + "constructed/";
public static final String DECK_DRAFT_DIR = DECK_BASE_DIR + "draft/";
+ public static final String DECK_WINSTON_DIR = DECK_BASE_DIR + "winston/";
public static final String DECK_SEALED_DIR = DECK_BASE_DIR + "sealed/";
public static final String DECK_SCHEME_DIR = DECK_BASE_DIR + "scheme/";
public static final String DECK_PLANE_DIR = DECK_BASE_DIR + "planar/";