diff --git a/forge-core/src/main/java/forge/card/CardEdition.java b/forge-core/src/main/java/forge/card/CardEdition.java index d644d129850..3b16eb02eda 100644 --- a/forge-core/src/main/java/forge/card/CardEdition.java +++ b/forge-core/src/main/java/forge/card/CardEdition.java @@ -213,6 +213,10 @@ public final class CardEdition implements Comparable { // immutable return whiteBorder; } + public boolean isLargeSet() { + return cards.length > 200; + } + public int getCntBoosterPictures() { return boosterArts; } diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/quest/CSubmenuQuestDraft.java b/forge-gui-desktop/src/main/java/forge/screens/home/quest/CSubmenuQuestDraft.java index aa531afccce..f5901e577ef 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/home/quest/CSubmenuQuestDraft.java +++ b/forge-gui-desktop/src/main/java/forge/screens/home/quest/CSubmenuQuestDraft.java @@ -1,20 +1,6 @@ package forge.screens.home.quest; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.JRadioButton; -import javax.swing.SwingUtilities; - import com.google.common.collect.ImmutableList; - import forge.GuiBase; import forge.Singletons; import forge.UiCommand; @@ -32,11 +18,11 @@ import forge.item.BoosterPack; import forge.item.PaperCard; import forge.itemmanager.DeckManager; import forge.limited.BoosterDraft; -import forge.model.CardBlock; import forge.model.FModel; import forge.properties.ForgePreferences.FPref; import forge.quest.QuestDraftUtils; import forge.quest.QuestEventDraft; +import forge.quest.QuestEventDraft.QuestDraftFormat; import forge.quest.QuestUtil; import forge.quest.data.QuestAchievements; import forge.screens.deckeditor.CDeckEditorUI; @@ -51,6 +37,12 @@ import forge.toolbox.FSkin; import forge.toolbox.FSkin.SkinImage; import forge.toolbox.JXButtonPanel; +import javax.swing.*; +import java.awt.event.*; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; + /** * Controls the quest draft submenu in the home UI. * @@ -184,7 +176,7 @@ public enum CSubmenuQuestDraft implements ICDoc { final int totalPacks = prizes.boosterPacks.size(); int currentPack = 0; - while (prizes.boosterPacks.size() > 0) { + while (!prizes.boosterPacks.isEmpty()) { final BoosterPack pack = prizes.boosterPacks.remove(0); currentPack++; @@ -211,7 +203,7 @@ public enum CSubmenuQuestDraft implements ICDoc { final List cards = new ArrayList<>(); - while (prizes.boosterPacks.size() > 0) { + while (!prizes.boosterPacks.isEmpty()) { final BoosterPack pack = prizes.boosterPacks.remove(0); cards.addAll(pack.getCards()); } @@ -306,11 +298,21 @@ public enum CSubmenuQuestDraft implements ICDoc { if (achievements != null) { - final CardBlock block = GuiChoose.oneOrNone("Choose Draft Format", QuestEventDraft.getAvailableBlocks(FModel.getQuest())); + List formats = QuestEventDraft.getAvailableFormats(FModel.getQuest()); - if (block != null) { + if (formats.isEmpty()) { + FOptionPane.showErrorDialog( + "You do not have any draft-able sets unlocked!\n" + + "Come back later when you've unlocked more sets.", + "No Available Drafts"); + return; + } - achievements.spendDraftToken(block); + final QuestDraftFormat format = GuiChoose.oneOrNone("Choose Draft Format", formats); + + if (format != null) { + + achievements.spendDraftToken(format); update(); VSubmenuQuestDraft.SINGLETON_INSTANCE.populate(); @@ -516,6 +518,8 @@ public enum CSubmenuQuestDraft implements ICDoc { private void startDraft() { if (drafting) { + FOptionPane.showErrorDialog("You are currently in a draft.\n" + + "You should leave or finish that draft before starting another."); return; } @@ -575,6 +579,12 @@ public enum CSubmenuQuestDraft implements ICDoc { return; } + if (QuestDraftUtils.matchInProgress) { + FOptionPane.showErrorDialog("There is already a match in progress.\n" + + "Please wait for the current round to end before attempting to continue."); + return; + } + gui = GuiBase.getInterface().getNewGuiGame(); QuestDraftUtils.startNextMatch(gui); diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/QuestDraftWinLose.java b/forge-gui-desktop/src/main/java/forge/screens/match/QuestDraftWinLose.java index 64571fcf8c6..f1ea8165725 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/QuestDraftWinLose.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/QuestDraftWinLose.java @@ -16,13 +16,10 @@ */ package forge.screens.match; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; - import com.google.common.collect.ImmutableList; - import forge.assets.FSkinProp; import forge.game.GameView; +import forge.game.player.PlayerView; import forge.match.NextGameDecision; import forge.model.FModel; import forge.quest.QuestController; @@ -32,6 +29,9 @@ import forge.screens.home.quest.VSubmenuQuestDraft; import forge.toolbox.FOptionPane; import forge.toolbox.FSkin; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + /** *

* QuestWinLose. @@ -46,9 +46,6 @@ public class QuestDraftWinLose extends ControlWinLose { /** * Instantiates a new quest win lose handler. - * - * @param view0 ViewWinLose object - * @param match2 */ public QuestDraftWinLose(final ViewWinLose view0, final GameView game0, final CMatchUI matchUI) { super(view0, game0, matchUI); @@ -71,7 +68,6 @@ public class QuestDraftWinLose extends ControlWinLose { if (lastGame.isMatchOver()) { final String winner = lastGame.getWinningPlayerName(); - quest.getAchievements().getCurrentDraft().setWinner(winner); quest.save(); } @@ -107,9 +103,29 @@ public class QuestDraftWinLose extends ControlWinLose { public void actionPerformed(final ActionEvent e) { if (warningString == null || FOptionPane.showOptionDialog(warningString, warningCaption, FSkin.getImage(FSkinProp.ICO_WARNING).scale(2), ImmutableList.of("Yes", "No"), 1) == 0) { - matchUI.getGameController().nextGameDecision(NextGameDecision.QUIT); - QuestDraftUtils.matchInProgress = false; - QuestDraftUtils.continueMatches(matchUI); + if (warningString != null) { + PlayerView humanPlayer = null; + for (PlayerView playerView : matchUI.getLocalPlayers()) { + humanPlayer = playerView; + } + for (PlayerView playerView : lastGame.getPlayers()) { + if (humanPlayer == null) { + throw new IllegalStateException("Forfeit tournament button was pressed in a match without human players."); + } + if (playerView != humanPlayer) { + quest.getAchievements().getCurrentDraft().setWinner(playerView.getName()); + quest.save(); + CSubmenuQuestDraft.SINGLETON_INSTANCE.update(); + VSubmenuQuestDraft.SINGLETON_INSTANCE.populate(); + } + } + //The player is probably not interested in watching more AI matches. + QuestDraftUtils.cancelFurtherMatches(); + } else { + matchUI.getGameController().nextGameDecision(NextGameDecision.QUIT); + QuestDraftUtils.matchInProgress = false; + QuestDraftUtils.continueMatches(matchUI); + } } } }); diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/QuestWinLose.java b/forge-gui-desktop/src/main/java/forge/screens/match/QuestWinLose.java index cb8349d6a41..c5442f3001c 100644 --- a/forge-gui-desktop/src/main/java/forge/screens/match/QuestWinLose.java +++ b/forge-gui-desktop/src/main/java/forge/screens/match/QuestWinLose.java @@ -5,12 +5,12 @@ * 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 . */ @@ -28,16 +28,15 @@ import forge.screens.home.quest.CSubmenuDuels; * Processes win/lose presentation for Quest events. This presentation is * displayed by WinLoseFrame. Components to be added to pnlCustom in * WinLoseFrame should use MigLayout. - * + * */ public class QuestWinLose extends ControlWinLose { private final QuestWinLoseController controller; /** * Instantiates a new quest win lose handler. - * + * * @param view0 ViewWinLose object - * @param match2 */ public QuestWinLose(final ViewWinLose view0, final GameView game0, final CMatchUI matchUI) { super(view0, game0, matchUI); @@ -51,7 +50,7 @@ public class QuestWinLose extends ControlWinLose { *

* Checks conditions of win and fires various reward display methods * accordingly. - * + * * @return true, if successful */ @Override @@ -66,7 +65,7 @@ public class QuestWinLose extends ControlWinLose { *

* When "quit" button is pressed, this method adjusts quest data as * appropriate and saves. - * + * */ @Override public final void actionOnQuit() { diff --git a/forge-gui/src/main/java/forge/quest/QuestDraftUtils.java b/forge-gui/src/main/java/forge/quest/QuestDraftUtils.java index caea7dbc302..6275b8abe10 100644 --- a/forge-gui/src/main/java/forge/quest/QuestDraftUtils.java +++ b/forge-gui/src/main/java/forge/quest/QuestDraftUtils.java @@ -1,8 +1,5 @@ package forge.quest; -import java.util.ArrayList; -import java.util.List; - import forge.GuiBase; import forge.deck.Deck; import forge.deck.DeckGroup; @@ -17,14 +14,17 @@ import forge.player.GamePlayerUtil; import forge.properties.ForgePreferences.FPref; import forge.util.storage.IStorage; +import java.util.ArrayList; +import java.util.List; + public class QuestDraftUtils { - private static final List matchups = new ArrayList(); + private static final List matchups = new ArrayList<>(); public static boolean matchInProgress = false; private static boolean waitForUserInput = false; public static void completeDraft(final DeckGroup finishedDraft) { - final List aiDecks = new ArrayList(finishedDraft.getAiDecks()); + final List aiDecks = new ArrayList<>(finishedDraft.getAiDecks()); finishedDraft.getAiDecks().clear(); for (int i = 0; i < aiDecks.size(); i++) { @@ -49,8 +49,40 @@ public class QuestDraftUtils { return null; } + private static int getPreviousMatchup(final int position) { + switch (position) { + case 0: + case 1: + return 0; + case 2: + case 3: + return 2; + case 4: + case 5: + return 4; + case 6: + case 7: + return 6; + case 8: + return 0; + case 9: + return 2; + case 10: + return 4; + case 11: + return 6; + case 12: + return 8; + case 13: + return 10; + case 14: + return 12; + } + return -1; + } + public static void startNextMatch(final IGuiGame gui) { - if (matchups.size() > 0) { + if (!matchups.isEmpty()) { return; } @@ -68,38 +100,69 @@ public class QuestDraftUtils { } } - switch (currentSet) { - case 7: - addMatchup(0, 1, draft); - addMatchup(2, 3, draft); - addMatchup(4, 5, draft); - addMatchup(6, 7, draft); - break; - case 8: - addMatchup(2, 3, draft); - addMatchup(4, 5, draft); - addMatchup(6, 7, draft); - break; - case 9: - addMatchup(4, 5, draft); - addMatchup(6, 7, draft); - break; - case 10: - addMatchup(6, 7, draft); - break; - case 11: - addMatchup(8, 9, draft); - addMatchup(10, 11, draft); - break; - case 12: - addMatchup(10, 11, draft); - break; - case 13: - addMatchup(12, 13, draft); - break; - case 14: - default: - return; + int latestSet = currentSet; + //Choose the start of each matchup; it's always even (0v1 2v3 4v5) + if (latestSet % 2 == 1) { + latestSet--; + } + + //Fill in any missing spots in previous brackets + boolean foundMatchups = false; + for (int i = 0; i <= latestSet && i <= 14; i += 2) { + if (currentStandings[i].equals(QuestEventDraft.UNDETERMINED) && !currentStandings[i + 1].equals(QuestEventDraft.UNDETERMINED)) { + int previousMatchup = getPreviousMatchup(i); + addMatchup(previousMatchup, previousMatchup + 1, draft); + foundMatchups = true; + } else if (!currentStandings[i].equals(QuestEventDraft.UNDETERMINED) && currentStandings[i + 1].equals(QuestEventDraft.UNDETERMINED)) { + int previousMatchup = getPreviousMatchup(i + 1); + addMatchup(previousMatchup, previousMatchup + 1, draft); + foundMatchups = true; + } else if (currentStandings[i].equals(QuestEventDraft.UNDETERMINED) && currentStandings[i + 1].equals(QuestEventDraft.UNDETERMINED)) { + int previousMatchup = getPreviousMatchup(i); + addMatchup(previousMatchup, previousMatchup + 1, draft); + if (i >= 8) { + previousMatchup = getPreviousMatchup(i + 1); + addMatchup(previousMatchup, previousMatchup + 1, draft); + } + foundMatchups = true; + } + } + + //If no previous matches need doing, start the next round as normal + if (!foundMatchups) { + switch (currentSet) { + case 7: + addMatchup(0, 1, draft); + addMatchup(2, 3, draft); + addMatchup(4, 5, draft); + addMatchup(6, 7, draft); + break; + case 8: + addMatchup(2, 3, draft); + addMatchup(4, 5, draft); + addMatchup(6, 7, draft); + break; + case 9: + addMatchup(4, 5, draft); + addMatchup(6, 7, draft); + break; + case 10: + addMatchup(6, 7, draft); + break; + case 11: + addMatchup(8, 9, draft); + addMatchup(10, 11, draft); + break; + case 12: + addMatchup(10, 11, draft); + break; + case 13: + addMatchup(12, 13, draft); + break; + case 14: + default: + return; + } } update(gui); @@ -128,8 +191,7 @@ public class QuestDraftUtils { final int aiDeckIndex = Integer.parseInt(draft.getStandings()[aiIndex]) - 1; matchup.matchStarter.add(new RegisteredPlayer(decks.getAiDecks().get(aiDeckIndex)).setPlayer(GamePlayerUtil.createAiPlayer(draft.getAINames()[aiName], draft.getAIIcons()[aiName]))); - } - else { + } else { final int aiName1 = Integer.parseInt(draft.getStandings()[player1]) - 1; final int aiName2 = Integer.parseInt(draft.getStandings()[player2]) - 1; @@ -180,8 +242,14 @@ public class QuestDraftUtils { update(gui); } + public static void cancelFurtherMatches() { + matchInProgress = false; + waitForUserInput = false; + matchups.clear(); + } + private static final class DraftMatchup { - private final List matchStarter = new ArrayList(); + private final List matchStarter = new ArrayList<>(); private RegisteredPlayer humanPlayer = null; private void setHumanPlayer(final RegisteredPlayer humanPlayer) { this.matchStarter.add(humanPlayer); diff --git a/forge-gui/src/main/java/forge/quest/QuestEventDraft.java b/forge-gui/src/main/java/forge/quest/QuestEventDraft.java index 641f7b56410..1729a55db41 100644 --- a/forge-gui/src/main/java/forge/quest/QuestEventDraft.java +++ b/forge-gui/src/main/java/forge/quest/QuestEventDraft.java @@ -17,16 +17,6 @@ */ package forge.quest; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - import forge.GuiBase; import forge.card.CardEdition; import forge.card.CardEdition.CardInSet; @@ -44,9 +34,11 @@ import forge.player.GamePlayerUtil; import forge.quest.data.QuestPreferences.QPref; import forge.quest.io.ReadPriceList; import forge.util.NameGenerator; -import forge.util.TextUtil; import forge.util.storage.IStorage; +import java.text.SimpleDateFormat; +import java.util.*; + /** *

* QuestEvent. @@ -69,14 +61,14 @@ public class QuestEventDraft { } public boolean hasBoosterPacks() { - return boosterPacks != null && boosterPacks.size() > 0; + return boosterPacks != null && !boosterPacks.isEmpty(); } public boolean hasIndividualCards() { - return individualCards != null && individualCards.size() > 0; + return individualCards != null && !individualCards.isEmpty(); } - public boolean selectRareFromSets() { return selectRareCards != null && selectRareCards.size() > 0; } + public boolean selectRareFromSets() { return selectRareCards != null && !selectRareCards.isEmpty(); } public void addSelectedCard(final PaperCard card) { FModel.getQuest().getCards().addSingleCard(card, 1); @@ -362,19 +354,8 @@ public class QuestEventDraft { cards.add(getPromoCard()); - int creditsForPacks = (credits / 2); //Spend 50% of the credits on packs - - while (true) { - final BoosterPack pack = getBoosterPack(); - final int price = getBoosterPrice(pack); - if (price > creditsForPacks + creditsForPacks * 0.1f) { //Add a little room for near-same price packs. - break; - } - creditsForPacks -= price; - boosters.add(pack); - } - - credits = (credits / 2) + creditsForPacks; //Add the leftover credits + 50% + int creditsLeftAfterPacks = generateBoosters((credits / 2), boosters); //Spend 75% of the credits on packs + credits = (credits / 2) + creditsLeftAfterPacks; //Add the leftover credits + 50% final QuestDraftPrizes prizes = new QuestDraftPrizes(); prizes.credits = credits; @@ -394,19 +375,9 @@ public class QuestEventDraft { cards.add(getPromoCard()); - int creditsForPacks = (credits / 4) * 3; //Spend 75% of the credits on packs + int creditsLeftAfterPacks = generateBoosters((credits / 4) * 3, boosters); //Spend 75% of the credits on packs - while (true) { - final BoosterPack pack = getBoosterPack(); - final int price = getBoosterPrice(pack); - if (price > creditsForPacks + creditsForPacks * 0.1f) { //Add a little room for near-same price packs. - break; - } - creditsForPacks -= price; - boosters.add(pack); - } - - credits = (credits / 4) + creditsForPacks; //Add the leftover credits + 25% + credits = (credits / 4) + creditsLeftAfterPacks; //Add the leftover credits + 25% final QuestDraftPrizes prizes = new QuestDraftPrizes(); prizes.credits = credits; @@ -452,6 +423,20 @@ public class QuestEventDraft { } + private int generateBoosters(final int creditsForPacks, final List boosters) { + int creditsAfterPacks = creditsForPacks; + while (true) { + final BoosterPack pack = getBoosterPack(); + final int price = getBoosterPrice(pack); + if (price > creditsAfterPacks * 1.1f) { //Add a little room for near-same price packs. + break; + } + creditsAfterPacks -= price; + boosters.add(pack); + } + return creditsAfterPacks; + } + private void awardSelectedRare(final QuestDraftPrizes prizes) { final List possibleCards = new ArrayList<>(); @@ -682,14 +667,60 @@ public class QuestEventDraft { return title; } - public static List getAvailableBlocks(final QuestController quest) { + public static class QuestDraftFormat implements Comparable { + + private CardEdition edition; + private CardBlock block; + + public QuestDraftFormat(final CardEdition edition) { + this.edition = edition; + } + + public QuestDraftFormat(final CardBlock block) { + this.block = block; + } + + private boolean isSet() { + return edition != null; + } + + @Override + public String toString() { + if (edition != null) { + return edition.getName() + " (" + edition.getCode() + ")"; + } + String blockString = block.getName() + " ("; + List sets = block.getSets(); + for (int i = 0; i < sets.size(); i++) { + CardEdition cardEdition = sets.get(i); + blockString += cardEdition.getCode(); + if (i < sets.size() - 1) { + blockString += ", "; + } + } + blockString += ")"; + return blockString; + } + + public String getName() { + if (edition != null) { + return edition.getName(); + } + return block.getName(); + } + + @Override + public int compareTo(final QuestDraftFormat other) { + return toString().compareToIgnoreCase(other.toString()); + } + + } + + private static List getAllowedSets(final QuestController quest) { - final List possibleBlocks = new ArrayList<>(); final List allowedQuestSets = new ArrayList<>(); - final boolean questUsesLimitedCardPool = quest.getFormat() != null; - - if (questUsesLimitedCardPool) { + if (quest.getFormat() != null) { final List allowedSetCodes = quest.getFormat().getAllowedSetCodes(); @@ -699,6 +730,12 @@ public class QuestEventDraft { } + return allowedQuestSets; + + } + + private static List getBlocks() { + final List blocks = new ArrayList<>(); final IStorage storage = FModel.getBlocks(); @@ -708,29 +745,72 @@ public class QuestEventDraft { } } - if (questUsesLimitedCardPool) { + return blocks; + + } + + public static List getAvailableFormats(final QuestController quest) { + + final List allowedQuestSets = getAllowedSets(quest); + final List possibleFormats = new ArrayList<>(); + final List blocks = getBlocks(); + + List singleSets = new ArrayList<>(); + if (!allowedQuestSets.isEmpty()) { for (final CardBlock block : blocks) { - boolean blockAllowed = true; + boolean blockAllowed = false; + boolean largeSetUnlocked = false; + int unlockedSets = 0; final boolean allBlocksSanctioned = quest.getFormat().getAllowedSetCodes().isEmpty(); for (final CardEdition set : block.getSets()) { if (!allowedQuestSets.contains(set) && !allBlocksSanctioned) { - blockAllowed = false; - break; + continue; + } + unlockedSets++; + if (set.isLargeSet()) { + largeSetUnlocked = true; } } + //Allow partially unlocked blocks if they contain at least one large and one small unlocked set. + if (largeSetUnlocked && unlockedSets > 1) { + blockAllowed = true; + } + + if (largeSetUnlocked && block.getSets().size() == 1) { + blockAllowed = true; + singleSets.add(block.getSets().get(0).getCode()); + } + if (blockAllowed) { - possibleBlocks.add(block); + possibleFormats.add(new QuestDraftFormat(block)); } } + + for (CardEdition allowedQuestSet : allowedQuestSets) { + if (allowedQuestSet.isLargeSet() && !singleSets.contains(allowedQuestSet.getCode())) { + possibleFormats.add(new QuestDraftFormat(allowedQuestSet)); + } + } + } else { - possibleBlocks.addAll(blocks); + for (CardBlock block : blocks) { + possibleFormats.add(new QuestDraftFormat(block)); + if (block.getSets().size() > 1) { + for (CardEdition edition : block.getSets()) { + if (edition.isLargeSet()) { + possibleFormats.add(new QuestDraftFormat(edition)); + } + } + } + } } - return possibleBlocks.isEmpty() ? null : possibleBlocks; + Collections.sort(possibleFormats); + return possibleFormats; } @@ -741,41 +821,42 @@ public class QuestEventDraft { */ public static QuestEventDraft getRandomDraftOrNull(final QuestController quest) { - final List possibleBlocks = getAvailableBlocks(quest); + final List possibleFormats = getAvailableFormats(quest); - if (possibleBlocks == null) { + if (possibleFormats.isEmpty()) { return null; } - Collections.shuffle(possibleBlocks); - return getDraftOrNull(quest, possibleBlocks.get(0)); + Collections.shuffle(possibleFormats); + return getDraftOrNull(quest, possibleFormats.get(0)); } /** - * Generates a draft event based on the provided block. + * Generates a draft event based on the provided format. * @return The created draft or null in the event no draft could be created. */ - public static QuestEventDraft getDraftOrNull(final QuestController quest, final CardBlock block) { + public static QuestEventDraft getDraftOrNull(final QuestController quest, final QuestDraftFormat format) { - final QuestEventDraft event = new QuestEventDraft(block.getName()); + final QuestEventDraft event = new QuestEventDraft(format.getName()); - if (block.getNumberSets() == 1) { + if (format.isSet()) { + CardEdition edition = format.edition; String boosterConfiguration = ""; - for (int i = 0; i < block.getCntBoostersDraft(); i++) { - boosterConfiguration += block.getSets().get(0).getCode(); - if (i != block.getCntBoostersDraft() - 1) { + for (int i = 0; i < 3; i++) { + boosterConfiguration += edition.getCode(); + if (i != 2) { boosterConfiguration += "/"; } event.boosterConfiguration = boosterConfiguration; } } else { - final List possibleSetCombinations = getSetCombos(block); + final List possibleSetCombinations = new ArrayList<>(getSetCombos(quest, format.block)); Collections.shuffle(possibleSetCombinations); event.boosterConfiguration = possibleSetCombinations.get(0); } - event.block = block.getName(); + event.block = format.getName(); event.entryFee = calculateEntryFee(event.boosterConfiguration.split("/")); final List players = new ArrayList<>(); @@ -850,57 +931,76 @@ public class QuestEventDraft { } - private static List getSetCombos(final CardBlock block) { - final List result = new ArrayList<>(); + private static Set getSetCombos(final QuestController quest, final CardBlock block) { + final Set possibleCombinations = new LinkedHashSet<>(); final List sets = block.getSets(); + final String s0c = sets.get(0).getCode(); if (sets.size() == 1) { - result.add(String.format("%s/%s/%s", s0c, s0c, s0c)); - return result; + int numBoosters = block.getCntBoostersDraft(); + String combination = ""; + for (int i = 0; i < numBoosters; i++) { + combination += s0c; + if (i < numBoosters - 1) { + combination += "/"; + } + } + possibleCombinations.add(combination); + return possibleCombinations; } - final String s1c = sets.get(1).getCode(); - final String s2c = sets.size() > 2 ? sets.get(2).getCode() : null; - - final boolean s0isLarge = sets.get(0).getCards().length > 200; - final boolean s1isLarge = sets.get(1).getCards().length > 200; - - final String largerSet = s0isLarge == s1isLarge ? null : s0isLarge ? s0c : s1c; - - if (s2c == null) { - if (largerSet != null ) { - result.add(String.format("%s/%s/%s", s0c, largerSet, s1c)); - } else { - result.add(String.format("%s/%s/%s", s1c, s1c, s1c)); - result.add(String.format("%s/%s/%s", s0c, s1c, s1c)); - result.add(String.format("%s/%s/%s", s0c, s0c, s1c)); - result.add(String.format("%s/%s/%s", s0c, s0c, s0c)); - } + List allowedSets; + if (quest.getFormat() == null) { + allowedSets = new ArrayList<>(sets); } else { - result.add(String.format("%s/%s/%s", s0c, s0c, s0c)); - result.add(String.format("%s/%s/%s", s0c, s1c, s2c)); + allowedSets = getAllowedSets(quest); + allowedSets.retainAll(sets); + } - // allow separate drafts with 3rd large set (ex: ROE, AVR) - if( sets.get(2).getCards().length > 200) { - result.add(String.format("%s/%s/%s", s2c, s2c, s2c)); + final boolean oldSetsFirst = sets.get(0).getDate().before(FModel.getMagicDb().getEditions().get("SOM").getDate()); + Collections.sort(allowedSets, new Comparator() { + @Override + public int compare(final CardEdition edition1, final CardEdition edition2) { + if (edition1.getDate().before(edition2.getDate())) { + return oldSetsFirst ? -1 : 1; + } else if (edition1.getDate().after(edition2.getDate())) { + return oldSetsFirst ? 1 : -1; + } + return 0; + } + }); + + boolean largeSetFound = false; + for (CardEdition allowedSet : allowedSets) { + if (allowedSet.isLargeSet()) { + largeSetFound = true; + break; } } - // This is set to Scars of Mirrodin date to account for the fact that MBS is drafted as a part of the Scars of Mirrodin block. - // Setting it to the date of Mirrodin Besieged makes it treat all drafts that feature Scars of Mirrodin incorrectly. - final Date SOMDate = FModel.getMagicDb().getEditions().get("SOM").getDate(); - final boolean openOlderPacksFirst = sets.get(0).getDate().before(SOMDate); // before Mirrodin Besieged, sets were drafted in the opposite order (old->new instead of new->old) + if (!largeSetFound) { + throw new IllegalStateException(allowedSets + " does not contain a large set for quest draft generation."); + } - if( !openOlderPacksFirst ){ - for(int i = result.size() - 1; i >= 0; i--) { - final List parts = Arrays.asList(TextUtil.split(result.get(i), '/')); - Collections.reverse(parts); - result.set(i, TextUtil.join(parts, "/")); + if (allowedSets.containsAll(sets)) { + CardEdition set0 = allowedSets.get(0); + CardEdition set1 = allowedSets.get(1); + if (allowedSets.size() == 2) { + if (set0.isLargeSet()) { + possibleCombinations.add(String.format("%s/%s/%s", set0.getCode(), set0.getCode(), set1.getCode())); + } else { + possibleCombinations.add(String.format("%s/%s/%s", set0.getCode(), set1.getCode(), set1.getCode())); + } + } + if (allowedSets.size() == 3) { + CardEdition set2 = allowedSets.get(2); + possibleCombinations.add(String.format("%s/%s/%s", set0.getCode(), set1.getCode(), set2.getCode())); } } - return result; + return possibleCombinations; + } } diff --git a/forge-gui/src/main/java/forge/quest/data/QuestAchievements.java b/forge-gui/src/main/java/forge/quest/data/QuestAchievements.java index d6e741492eb..572a3c49880 100644 --- a/forge-gui/src/main/java/forge/quest/data/QuestAchievements.java +++ b/forge-gui/src/main/java/forge/quest/data/QuestAchievements.java @@ -1,8 +1,8 @@ package forge.quest.data; -import forge.model.CardBlock; import forge.model.FModel; import forge.quest.QuestEventDraft; +import forge.quest.QuestEventDraft.QuestDraftFormat; import forge.quest.data.QuestPreferences.DifficultyPrefs; import forge.quest.data.QuestPreferences.QPref; @@ -11,7 +11,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -/** +/** * TODO: Write javadoc for this type. * */ @@ -23,7 +23,7 @@ public class QuestAchievements { private List completedChallenges = new ArrayList<>(); private List currentChallenges = new ArrayList<>(); - + private QuestEventDraftContainer drafts = new QuestEventDraftContainer(); private int currentDraft = -1; private int draftsToGenerate = 1; @@ -33,17 +33,17 @@ public class QuestAchievements { private int winstreakBest = 0; private int winstreakCurrent = 0; private int lost; - + private int firstPlaceDraftFinishes = 0; private int secondPlaceDraftFinishes = 0; private int thirdPlaceDraftFinishes = 0; private int fourthPlaceDraftFinishes = 0; - + // Difficulty - will store only index from now. private int difficulty; - - private transient CardBlock nextDraftBlock; - + + private transient QuestDraftFormat nextDraftFormat; + public QuestAchievements() { //needed for XML serialization } @@ -54,14 +54,14 @@ public class QuestAchievements { public QuestAchievements(int diff) { difficulty = diff; } - + public void deleteDraft(QuestEventDraft draft) { if (currentDraft == drafts.indexOf(draft)) { currentDraft = -1; } drafts.remove(draft); } - + public void endCurrentTournament(final int place) { drafts.remove(drafts.get(currentDraft)); currentDraft = -1; @@ -77,7 +77,7 @@ public class QuestAchievements { * Adds the win. */ public void addWin() { // changes getRank() - + win++; winstreakCurrent++; @@ -92,17 +92,17 @@ public class QuestAchievements { if (win % FModel.getQuestPreferences().getPrefInt(QPref.WINS_NEW_DRAFT) == 0) { draftsToGenerate++; } - + if (winstreakCurrent > winstreakBest) { winstreakBest = winstreakCurrent; } - + } // Challenge performance /** * Gets the challenges played. - * + * * @return the challenges played */ public int getChallengesPlayed() { @@ -118,7 +118,7 @@ public class QuestAchievements { /** * Returns stored list of non-repeatable challenge IDs. - * + * * @return List */ public List getLockedChallenges() { @@ -130,7 +130,7 @@ public class QuestAchievements { * addCompletedChallenge. *

* Add non-repeatable challenge ID to list. - * + * * @param i * the i */ @@ -140,7 +140,7 @@ public class QuestAchievements { /** * Stores a list of current challenges. - * + * * @return List */ public List getCurrentChallenges() { @@ -153,7 +153,7 @@ public class QuestAchievements { /** * Returns the stored list of current challenges. - * + * * @param lst0 List */ public void setCurrentChallenges(final List lst0) { @@ -171,7 +171,7 @@ public class QuestAchievements { // Level, read-only ( note: it increments in addWin() ) /** * Gets the level. - * + * * @return the level */ public int getLevel() { @@ -182,7 +182,7 @@ public class QuestAchievements { // Wins & Losses /** * Gets the lost. - * + * * @return the lost */ public int getLost() { @@ -191,7 +191,7 @@ public class QuestAchievements { /** * Gets the win. - * + * * @return the win */ public int getWin() { @@ -218,7 +218,7 @@ public class QuestAchievements { /** * Gets the difficulty index. - * + * * @return the difficulty index */ public int getDifficulty() { @@ -230,7 +230,7 @@ public class QuestAchievements { } public void generateDrafts() { - + if (drafts == null) { drafts = new QuestEventDraftContainer(); draftsToGenerate = 1; @@ -251,9 +251,9 @@ public class QuestAchievements { for (int i = 0; i < draftsToGenerate; i++) { QuestEventDraft draft; - if (nextDraftBlock != null) { - draft = QuestEventDraft.getDraftOrNull(FModel.getQuest(), nextDraftBlock); - nextDraftBlock = null; + if (nextDraftFormat != null) { + draft = QuestEventDraft.getDraftOrNull(FModel.getQuest(), nextDraftFormat); + nextDraftFormat = null; } else { draft = QuestEventDraft.getRandomDraftOrNull(FModel.getQuest()); } @@ -264,7 +264,7 @@ public class QuestAchievements { } FModel.getQuest().save(); - + } public void addDraftToken() { @@ -276,7 +276,7 @@ public class QuestAchievements { } public QuestEventDraft getCurrentDraft() { - if (drafts == null || drafts.size() == 0) { + if (drafts == null || drafts.isEmpty()) { return null; } if (currentDraft > drafts.size() - 1) { @@ -286,11 +286,11 @@ public class QuestAchievements { } return drafts.get(currentDraft); } - + public int getCurrentDraftIndex() { return currentDraft; } - + public int getWinsForPlace(final int place) { switch (place) { case 1: @@ -302,7 +302,7 @@ public class QuestAchievements { case 4: return fourthPlaceDraftFinishes; } - + return 0; } @@ -327,13 +327,13 @@ public class QuestAchievements { return draftTokens; } - public void spendDraftToken(final CardBlock block) { + public void spendDraftToken(final QuestDraftFormat format) { if (draftTokens > 0) { draftTokens--; draftsToGenerate++; - nextDraftBlock = block; + nextDraftFormat = format; generateDrafts(); } } - + } diff --git a/forge-gui/src/main/java/forge/quest/data/QuestPreferences.java b/forge-gui/src/main/java/forge/quest/data/QuestPreferences.java index 5d798eec49e..4cb53d44120 100644 --- a/forge-gui/src/main/java/forge/quest/data/QuestPreferences.java +++ b/forge-gui/src/main/java/forge/quest/data/QuestPreferences.java @@ -275,12 +275,6 @@ public class QuestPreferences extends PreferencesStore i } break; - case PLAYSET_BASIC_LAND_SIZE: - if (val < 10) { - return "Value too small (minimum 10)."; - } - break; - case SHOP_MAX_PACKS: case SHOP_MAX_SELLING_PRICE: case SHOP_WINS_FOR_ADDITIONAL_PACK: @@ -298,6 +292,7 @@ public class QuestPreferences extends PreferencesStore i case BOOSTER_COMMONS: case BOOSTER_UNCOMMONS: case BOOSTER_RARES: + case PLAYSET_BASIC_LAND_SIZE: case STARTING_CREDITS_EASY: case STARTING_CREDITS_MEDIUM: case STARTING_CREDITS_HARD: