From 172c172fa53df2b27f3b539d16e660f34e209713 Mon Sep 17 00:00:00 2001 From: drdev Date: Wed, 22 Apr 2015 22:42:51 +0000 Subject: [PATCH] Start working on new menu screens --- .gitattributes | 7 +- .../src/forge/menu/FMenuItem.java | 4 + .../constructed/ConstructedScreen.java | 3 +- ...letScreen.java => LoadGauntletScreen.java} | 4 +- .../screens/gauntlet/NewGauntletScreen.java | 480 ++++++++++++++++++ .../src/forge/screens/home/HomeScreen.java | 40 +- .../src/forge/screens/home/NewGameMenu.java | 100 ++++ ...LimitedScreen.java => NewDraftScreen.java} | 7 +- .../screens/limited/NewSealedScreen.java | 150 ++++++ .../planarconquest/NewConquestScreen.java | 3 +- .../forge/screens/quest/NewQuestScreen.java | 3 +- .../forge/properties/ForgePreferences.java | 3 + 12 files changed, 766 insertions(+), 38 deletions(-) rename forge-gui-mobile/src/forge/screens/gauntlet/{GauntletScreen.java => LoadGauntletScreen.java} (97%) create mode 100644 forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java create mode 100644 forge-gui-mobile/src/forge/screens/home/NewGameMenu.java rename forge-gui-mobile/src/forge/screens/limited/{LimitedScreen.java => NewDraftScreen.java} (95%) create mode 100644 forge-gui-mobile/src/forge/screens/limited/NewSealedScreen.java diff --git a/.gitattributes b/.gitattributes index 592b66a2af2..256e6d995dd 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1301,12 +1301,15 @@ forge-gui-mobile/src/forge/screens/SplashScreen.java -text forge-gui-mobile/src/forge/screens/TabPageScreen.java -text forge-gui-mobile/src/forge/screens/constructed/AvatarSelector.java -text forge-gui-mobile/src/forge/screens/constructed/ConstructedScreen.java -text -forge-gui-mobile/src/forge/screens/gauntlet/GauntletScreen.java -text +forge-gui-mobile/src/forge/screens/gauntlet/LoadGauntletScreen.java -text +forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java -text forge-gui-mobile/src/forge/screens/home/HomeScreen.java -text +forge-gui-mobile/src/forge/screens/home/NewGameMenu.java -text forge-gui-mobile/src/forge/screens/limited/DraftingProcessScreen.java -text -forge-gui-mobile/src/forge/screens/limited/LimitedScreen.java -text forge-gui-mobile/src/forge/screens/limited/LoadDraftScreen.java -text forge-gui-mobile/src/forge/screens/limited/LoadSealedScreen.java -text +forge-gui-mobile/src/forge/screens/limited/NewDraftScreen.java -text +forge-gui-mobile/src/forge/screens/limited/NewSealedScreen.java -text forge-gui-mobile/src/forge/screens/match/MatchController.java -text forge-gui-mobile/src/forge/screens/match/MatchScreen.java -text forge-gui-mobile/src/forge/screens/match/TargetingOverlay.java -text diff --git a/forge-gui-mobile/src/forge/menu/FMenuItem.java b/forge-gui-mobile/src/forge/menu/FMenuItem.java index d994eb633e8..6aa9e29c944 100644 --- a/forge-gui-mobile/src/forge/menu/FMenuItem.java +++ b/forge-gui-mobile/src/forge/menu/FMenuItem.java @@ -53,6 +53,10 @@ public class FMenuItem extends FDisplayObject implements IButton { textWidth = FONT.getBounds(text).width; } + public String getText() { + return text; + } + public boolean hasIcon() { return icon != null; } diff --git a/forge-gui-mobile/src/forge/screens/constructed/ConstructedScreen.java b/forge-gui-mobile/src/forge/screens/constructed/ConstructedScreen.java index 29f38ab25da..40602a89935 100644 --- a/forge-gui-mobile/src/forge/screens/constructed/ConstructedScreen.java +++ b/forge-gui-mobile/src/forge/screens/constructed/ConstructedScreen.java @@ -34,6 +34,7 @@ import forge.properties.ForgePreferences; import forge.properties.ForgePreferences.FPref; import forge.screens.FScreen; import forge.screens.LaunchScreen; +import forge.screens.home.NewGameMenu; import forge.screens.settings.SettingsScreen; import forge.toolbox.FCheckBox; import forge.toolbox.FComboBox; @@ -95,7 +96,7 @@ public class ConstructedScreen extends LaunchScreen { private int lastArchenemy = 0; public ConstructedScreen() { - super("Constructed"); + super(null, NewGameMenu.getMenu()); btnStart.setEnabled(false); //disable start button until decks loaded diff --git a/forge-gui-mobile/src/forge/screens/gauntlet/GauntletScreen.java b/forge-gui-mobile/src/forge/screens/gauntlet/LoadGauntletScreen.java similarity index 97% rename from forge-gui-mobile/src/forge/screens/gauntlet/GauntletScreen.java rename to forge-gui-mobile/src/forge/screens/gauntlet/LoadGauntletScreen.java index eb199295b7e..e07818a51c6 100644 --- a/forge-gui-mobile/src/forge/screens/gauntlet/GauntletScreen.java +++ b/forge-gui-mobile/src/forge/screens/gauntlet/LoadGauntletScreen.java @@ -41,7 +41,7 @@ import forge.util.ThreadUtil; import forge.util.Utils; import forge.util.gui.SOptionPane; -public class GauntletScreen extends LaunchScreen { +public class LoadGauntletScreen extends LaunchScreen { private static final float PADDING = Utils.AVG_FINGER_HEIGHT * 0.1f; private static final FSkinColor SEL_COLOR = FSkinColor.get(Colors.CLR_ACTIVE); @@ -50,7 +50,7 @@ public class GauntletScreen extends LaunchScreen { private final FButton btnRenameGauntlet = add(new FButton("Rename")); private final FButton btnDeleteGauntlet = add(new FButton("Delete")); - public GauntletScreen() { + public LoadGauntletScreen() { super("Gauntlets"); btnNewGauntlet.setFont(FSkinFont.get(16)); diff --git a/forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java b/forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java new file mode 100644 index 00000000000..b97de2365e7 --- /dev/null +++ b/forge-gui-mobile/src/forge/screens/gauntlet/NewGauntletScreen.java @@ -0,0 +1,480 @@ +package forge.screens.gauntlet; + +import java.io.File; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; + +import forge.FThreads; +import forge.Graphics; +import forge.assets.FSkinColor; +import forge.assets.FSkinColor.Colors; +import forge.assets.FSkinFont; +import forge.card.CardRenderer; +import forge.deck.Deck; +import forge.deck.DeckType; +import forge.deck.FDeckChooser; +import forge.game.GameType; +import forge.game.player.RegisteredPlayer; +import forge.gauntlet.GauntletData; +import forge.gauntlet.GauntletIO; +import forge.gauntlet.GauntletUtil; +import forge.model.FModel; +import forge.player.GamePlayerUtil; +import forge.quest.QuestUtil; +import forge.screens.LaunchScreen; +import forge.screens.home.NewGameMenu; +import forge.screens.settings.SettingsScreen; +import forge.toolbox.FButton; +import forge.toolbox.FEvent; +import forge.toolbox.FList; +import forge.toolbox.FOptionPane; +import forge.toolbox.GuiChoose; +import forge.toolbox.ListChooser; +import forge.toolbox.FEvent.FEventHandler; +import forge.util.Callback; +import forge.util.ThreadUtil; +import forge.util.Utils; +import forge.util.gui.SOptionPane; + +public class NewGauntletScreen extends LaunchScreen { + private static final float PADDING = Utils.AVG_FINGER_HEIGHT * 0.1f; + private static final FSkinColor SEL_COLOR = FSkinColor.get(Colors.CLR_ACTIVE); + + private final GauntletFileLister lstGauntlets = add(new GauntletFileLister()); + private final FButton btnNewGauntlet = add(new FButton("New")); + private final FButton btnRenameGauntlet = add(new FButton("Rename")); + private final FButton btnDeleteGauntlet = add(new FButton("Delete")); + + public NewGauntletScreen() { + super(null, NewGameMenu.getMenu()); + + btnNewGauntlet.setFont(FSkinFont.get(16)); + btnNewGauntlet.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + GuiChoose.oneOrNone("Select a Gauntlet Type", new String[] { + "Quick Gauntlet", + "Custom Gauntlet", + "Gauntlet Contest", + }, new Callback() { + @Override + public void run(String result) { + if (result == null) { return; } + + switch (result) { + case "Quick Gauntlet": + createQuickGauntlet(); + break; + case "Custom Gauntlet": + createCustomGauntlet(); + break; + default: + createGauntletContest(); + break; + } + } + }); + } + }); + btnRenameGauntlet.setFont(btnNewGauntlet.getFont()); + btnRenameGauntlet.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + renameGauntlet(lstGauntlets.getSelectedGauntlet()); + } + }); + btnDeleteGauntlet.setFont(btnNewGauntlet.getFont()); + btnDeleteGauntlet.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + deleteGauntlet(lstGauntlets.getSelectedGauntlet()); + } + }); + + final File[] files = GauntletIO.getGauntletFilesUnlocked(null); + final List data = new ArrayList(); + + for (final File f : files) { + GauntletData gd = GauntletIO.loadGauntlet(f); + if (gd != null) { + data.add(gd); + } + } + + lstGauntlets.setGauntlets(data); + } + + private void updateButtons() { + boolean enabled = !lstGauntlets.isEmpty(); + btnRenameGauntlet.setEnabled(enabled); + btnDeleteGauntlet.setEnabled(enabled); + btnStart.setEnabled(enabled); + } + + @Override + protected void doLayoutAboveBtnStart(float startY, float width, float height) { + float buttonWidth = (width - 2 * PADDING) / 3; + float buttonHeight = btnNewGauntlet.getAutoSizeBounds().height * 1.2f; + + float y = startY; + lstGauntlets.setBounds(0, y, width, height - y - buttonHeight - PADDING); + y += lstGauntlets.getHeight() + PADDING; + + float x = 0; + btnNewGauntlet.setBounds(x, y, buttonWidth, buttonHeight); + x += buttonWidth + PADDING; + btnRenameGauntlet.setBounds(x, y, buttonWidth, buttonHeight); + x += buttonWidth + PADDING; + btnDeleteGauntlet.setBounds(x, y, buttonWidth, buttonHeight); + } + + private void createQuickGauntlet() { + GuiChoose.getInteger("How many opponents are you willing to face?", 3, 50, new Callback() { + @Override + public void run(final Integer numOpponents) { + if (numOpponents == null) { return; } + + ListChooser chooser = new ListChooser( + "Choose allowed deck types for opponents", 0, 5, Arrays.asList(new DeckType[] { + DeckType.CUSTOM_DECK, + DeckType.PRECONSTRUCTED_DECK, + DeckType.QUEST_OPPONENT_DECK, + DeckType.COLOR_DECK, + DeckType.THEME_DECK + }), null, new Callback>() { + @Override + public void run(final List allowedDeckTypes) { + if (allowedDeckTypes == null || allowedDeckTypes.isEmpty()) { return; } + + FDeckChooser.promptForDeck("Select Your Deck", GameType.Gauntlet, false, new Callback() { + @Override + public void run(Deck userDeck) { + if (userDeck == null) { return; } + + lstGauntlets.addGauntlet(GauntletUtil.createQuickGauntlet( + userDeck, numOpponents, allowedDeckTypes)); + } + }); + } + }); + chooser.show(null, true); + } + }); + } + + private void createCustomGauntlet() { + GuiChoose.getInteger("How many opponents are you willing to face?", 3, 50, new Callback() { + @Override + public void run(final Integer numOpponents) { + if (numOpponents == null) { return; } + + GauntletData gauntlet = new GauntletData(); + gauntlet.setDecks(new ArrayList()); + promptForAiDeck(gauntlet, numOpponents); + } + }); + } + + private void promptForAiDeck(final GauntletData gauntlet, final int numOpponents) { + final int opponentNum = gauntlet.getDecks().size() + 1; + FDeckChooser.promptForDeck("Select Deck for Opponent " + opponentNum + " / " + numOpponents, GameType.Gauntlet, true, new Callback() { + @Override + public void run(Deck aiDeck) { + if (aiDeck == null) { return; } + + gauntlet.getDecks().add(aiDeck); + gauntlet.getEventNames().add(aiDeck.getName()); + + if (opponentNum < numOpponents) { + promptForAiDeck(gauntlet, numOpponents); + } + else { + //once all ai decks have been selected, prompt for user deck + FDeckChooser.promptForDeck("Select Your Deck", GameType.Gauntlet, false, new Callback() { + @Override + public void run(Deck userDeck) { + if (userDeck == null) { return; } + + gauntlet.setUserDeck(userDeck); + GauntletUtil.setDefaultGauntletName(gauntlet, GauntletIO.PREFIX_CUSTOM); + FModel.setGauntletData(gauntlet); + gauntlet.reset(); + lstGauntlets.addGauntlet(gauntlet); + } + }); + } + } + }); + } + + private void createGauntletContest() { + final File[] files = GauntletIO.getGauntletFilesLocked(); + final List contests = new ArrayList(); + for (final File f : files) { + GauntletData gd = GauntletIO.loadGauntlet(f); + if (gd != null) { + contests.add(gd); + } + } + + GuiChoose.oneOrNone("Select Gauntlet Contest", contests, new Callback() { + @Override + public void run(final GauntletData contest) { + if (contest == null) { return; } + + FDeckChooser.promptForDeck("Select Your Deck", GameType.Gauntlet, false, new Callback() { + @Override + public void run(final Deck userDeck) { + if (userDeck == null) { return; } + + //create copy of contest to use as gauntlet + GauntletData gauntlet = new GauntletData(); + gauntlet.setDecks(new ArrayList(contest.getDecks())); + gauntlet.setEventNames(new ArrayList(contest.getEventNames())); + gauntlet.setUserDeck(userDeck); + GauntletUtil.setDefaultGauntletName(gauntlet, contest.getDisplayName() + "_"); + FModel.setGauntletData(gauntlet); + gauntlet.reset(); + lstGauntlets.addGauntlet(gauntlet); + } + }); + } + }); + } + + @Override + protected void startMatch() { + final GauntletData gauntlet = lstGauntlets.getSelectedGauntlet(); + if (gauntlet == null) { + FOptionPane.showMessageDialog("You must create and select a gauntlet."); + return; + } + FModel.setGauntletData(gauntlet); + Deck userDeck = gauntlet.getUserDeck(); + if (userDeck == null) { + //give user a chance to select a deck if none saved with gauntlet + FDeckChooser.promptForDeck("Select Deck for Gauntlet", GameType.Gauntlet, false, new Callback() { + @Override + public void run(Deck result) { + if (result != null) { + gauntlet.setUserDeck(result); + GauntletIO.saveGauntlet(gauntlet); + } + } + }); + return; + } + super.startMatch(); + } + + @Override + protected boolean buildLaunchParams(LaunchParams launchParams) { + final GauntletData gauntlet = FModel.getGauntletData(); + launchParams.gameType = GameType.Gauntlet; + RegisteredPlayer humanPlayer = new RegisteredPlayer(gauntlet.getUserDeck()).setPlayer(GamePlayerUtil.getGuiPlayer()); + launchParams.humanPlayers.add(humanPlayer); + launchParams.players.add(humanPlayer); + launchParams.players.add(new RegisteredPlayer(gauntlet.getDecks().get(gauntlet.getCompleted())).setPlayer(GamePlayerUtil.createAiPlayer())); + gauntlet.startRound(launchParams.players, humanPlayer); + return false; //return false since we're creating the match here + } + + private void renameGauntlet(final GauntletData gauntlet) { + if (gauntlet == null) { return; } + + ThreadUtil.invokeInGameThread(new Runnable() { + @Override + public void run() { + String gauntletName; + String oldGauntletName = gauntlet.getName(); + while (true) { + gauntletName = SOptionPane.showInputDialog("Enter new name for gauntlet:", "Rename Gauntlet", null, oldGauntletName); + if (gauntletName == null) { return; } + + gauntletName = QuestUtil.cleanString(gauntletName); + if (gauntletName.equals(oldGauntletName)) { return; } //quit if chose same name + + if (gauntletName.isEmpty()) { + SOptionPane.showMessageDialog("Please specify a gauntlet name."); + continue; + } + + boolean exists = false; + for (GauntletData gauntletData : lstGauntlets) { + if (gauntletData.getName().equalsIgnoreCase(gauntletName)) { + exists = true; + break; + } + } + if (exists) { + SOptionPane.showMessageDialog("A gauntlet already exists with that name. Please pick another gauntlet name."); + continue; + } + break; + } + final String newGauntletName = gauntletName; + FThreads.invokeInEdtLater(new Runnable() { + @Override + public void run() { + gauntlet.rename(newGauntletName); + lstGauntlets.refresh(); + lstGauntlets.setSelectedGauntlet(gauntlet); + } + }); + } + }); + } + + private void deleteGauntlet(final GauntletData gauntlet) { + if (gauntlet == null) { return; } + + ThreadUtil.invokeInGameThread(new Runnable() { + @Override + public void run() { + if (!SOptionPane.showConfirmDialog( + "Are you sure you want to delete '" + gauntlet.getName() + "'?", + "Delete Gauntlet", "Delete", "Cancel")) { + return; + } + + GauntletIO.getGauntletFile(gauntlet).delete(); + + lstGauntlets.removeGauntlet(gauntlet); + } + }); + } + + private class GauntletFileLister extends FList { + private int selectedIndex = 0; + private List gauntlets; + + private GauntletFileLister() { + setListItemRenderer(new ListItemRenderer() { + @Override + public boolean tap(Integer index, GauntletData value, float x, float y, int count) { + if (count == 2) { + startMatch(); + } + else { + selectedIndex = index; + } + return true; + } + + @Override + public float getItemHeight() { + return CardRenderer.getCardListItemHeight(false); + } + + @Override + public void drawValue(Graphics g, Integer index, GauntletData value, FSkinFont font, FSkinColor foreColor, FSkinColor backColor, boolean pressed, float x, float y, float w, float h) { + float offset = w * SettingsScreen.INSETS_FACTOR - FList.PADDING; //increase padding for settings items + x += offset; + y += offset; + w -= 2 * offset; + h -= 2 * offset; + + float totalHeight = h; + String name = value.getName(); + h = font.getMultiLineBounds(name).height + SettingsScreen.SETTING_PADDING; + + int completed = value.getCompleted(); + int opponents = value.getDecks().size(); + NumberFormat percent = NumberFormat.getPercentInstance(); + String progress = completed + " / " + opponents + " (" + percent.format((double)completed / (double)opponents) + ")"; + float progressWidth = font.getBounds(progress).width + SettingsScreen.SETTING_PADDING; + + g.drawText(name, font, foreColor, x, y, w - progressWidth, h, false, HAlignment.LEFT, false); + g.drawText(progress, font, foreColor, x, y, w, h, false, HAlignment.RIGHT, false); + + h += SettingsScreen.SETTING_PADDING; + y += h; + h = totalHeight - h + w * SettingsScreen.INSETS_FACTOR; + + String timestamp = value.getTimestamp(); + font = FSkinFont.get(12); + float timestampWidth = font.getBounds(timestamp).width + SettingsScreen.SETTING_PADDING; + g.drawText(value.getUserDeck() == null ? "(none)" : value.getUserDeck().getName(), font, SettingsScreen.DESC_COLOR, x, y, w - timestampWidth, h, false, HAlignment.LEFT, false); + g.drawText(timestamp, font, SettingsScreen.DESC_COLOR, x + w - timestampWidth + SettingsScreen.SETTING_PADDING, y, w, h, false, HAlignment.LEFT, false); + } + }); + } + + @Override + protected FSkinColor getItemFillColor(int index) { + if (index == selectedIndex) { + return SEL_COLOR; + } + return null; + } + + public void setGauntlets(List gauntlets0) { + gauntlets = gauntlets0; + refresh(); + setSelectedIndex(0); + updateButtons(); + } + + public void addGauntlet(GauntletData gauntlet) { + if (gauntlets == null) { return; } + gauntlets.add(gauntlet); + refresh(); + setSelectedGauntlet(gauntlet); + updateButtons(); + } + + public void removeGauntlet(GauntletData gauntlet) { + if (gauntlets == null) { return; } + removeItem(gauntlet); + gauntlets.remove(gauntlet); + if (selectedIndex == gauntlets.size()) { + selectedIndex--; + } + revalidate(); + updateButtons(); + } + + public void refresh() { + List sorted = new ArrayList(); + for (GauntletData gauntlet : gauntlets) { + sorted.add(gauntlet); + } + Collections.sort(sorted, new Comparator() { + @Override + public int compare(final GauntletData x, final GauntletData y) { + return x.getName().toLowerCase().compareTo(y.getName().toLowerCase()); + } + }); + setListData(sorted); + } + + public boolean setSelectedIndex(int i0) { + if (i0 >= getCount()) { return false; } + selectedIndex = i0; + scrollIntoView(i0); + return true; + } + + public GauntletData getSelectedGauntlet() { + if (selectedIndex == -1) { return null; } + return getItemAt(selectedIndex); + } + + public boolean setSelectedGauntlet(GauntletData gauntlet) { + for (int i = 0; i < getCount(); i++) { + if (getItemAt(i) == gauntlet) { + selectedIndex = i; + scrollIntoView(i); + return true; + } + } + return false; + } + } +} diff --git a/forge-gui-mobile/src/forge/screens/home/HomeScreen.java b/forge-gui-mobile/src/forge/screens/home/HomeScreen.java index 28392892f3c..780d774b2c1 100644 --- a/forge-gui-mobile/src/forge/screens/home/HomeScreen.java +++ b/forge-gui-mobile/src/forge/screens/home/HomeScreen.java @@ -3,15 +3,11 @@ package forge.screens.home; import java.util.ArrayList; import forge.screens.FScreen; -import forge.screens.LoadingOverlay; import forge.Forge; import forge.assets.FSkinImage; import forge.deck.FDeckChooser; import forge.game.GameType; -import forge.screens.constructed.ConstructedScreen; -import forge.screens.gauntlet.GauntletScreen; -import forge.screens.limited.LimitedScreen; -import forge.screens.quest.QuestMenu; +import forge.screens.limited.LoadDraftScreen; import forge.screens.settings.SettingsScreen; import forge.toolbox.FButton; import forge.toolbox.FEvent; @@ -28,45 +24,33 @@ public class HomeScreen extends FScreen { public HomeScreen() { super((Header)null); - addButton("Constructed", new FEventHandler() { + addButton("New Game", new FEventHandler() { @Override public void handleEvent(FEvent e) { - Forge.openScreen(new ConstructedScreen()); + NewGameMenu.openPreferredScreen(); } }); - addButton("Draft / Sealed", new FEventHandler() { + addButton("Load Game", new FEventHandler() { @Override public void handleEvent(FEvent e) { - Forge.openScreen(new LimitedScreen()); + Forge.openScreen(new LoadDraftScreen()); } }); + addButton("Play Online", new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + } + }); + buttons.get(buttons.size() - 1).setEnabled(false); addButton("Deck Editor", new FEventHandler() { @Override public void handleEvent(FEvent e) { FDeckChooser.promptForDeck("Deck Editor", GameType.DeckEditorTest, false, null); } }); - /*addButton("Planar Conquest", new FEventHandler() { + addButton("Achievements", new FEventHandler() { @Override public void handleEvent(FEvent e) { - ConquestMenu.launchPlanarConquest(ConquestMenu.LaunchReason.StartPlanarConquest); - } - });*/ - addButton("Quest Mode", new FEventHandler() { - @Override - public void handleEvent(FEvent e) { - QuestMenu.launchQuestMode(QuestMenu.LaunchReason.StartQuestMode); - } - }); - addButton("Gauntlets", new FEventHandler() { - @Override - public void handleEvent(FEvent e) { - LoadingOverlay.show("Loading gauntlets...", new Runnable() { - @Override - public void run() { - Forge.openScreen(new GauntletScreen()); - } - }); } }); addButton("Settings", new FEventHandler() { diff --git a/forge-gui-mobile/src/forge/screens/home/NewGameMenu.java b/forge-gui-mobile/src/forge/screens/home/NewGameMenu.java new file mode 100644 index 00000000000..efdd4af7909 --- /dev/null +++ b/forge-gui-mobile/src/forge/screens/home/NewGameMenu.java @@ -0,0 +1,100 @@ +package forge.screens.home; + +import forge.Forge; +import forge.menu.FMenuItem; +import forge.menu.FPopupMenu; +import forge.model.FModel; +import forge.properties.ForgePreferences; +import forge.properties.ForgePreferences.FPref; +import forge.screens.FScreen; +import forge.screens.constructed.ConstructedScreen; +import forge.screens.gauntlet.NewGauntletScreen; +import forge.screens.limited.NewDraftScreen; +import forge.screens.limited.NewSealedScreen; +import forge.screens.planarconquest.NewConquestScreen; +import forge.screens.quest.NewQuestScreen; +import forge.toolbox.FEvent; +import forge.toolbox.FEvent.FEventHandler; + +public class NewGameMenu extends FPopupMenu { + private enum NewGameScreen { + Constructed("Constructed", ConstructedScreen.class), + BoosterDraft("Booster Draft", NewDraftScreen.class), + SealedDeck("Sealed Deck", NewSealedScreen.class), + QuestMode("Quest Mode", NewQuestScreen.class), + PlanarConquest("Planar Conquest", NewConquestScreen.class), + Gauntlet("Gauntlet", NewGauntletScreen.class); + + private final FMenuItem item; + private final Class screenClass; + private FScreen screen; + + private NewGameScreen(final String caption0, final Class screenClass0) { + screenClass = screenClass0; + item = new FMenuItem(caption0, new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + open(); + } + }); + } + + private void open() { + if (screen == null) { //don't initialize screen until it's opened the first time + try { + screen = screenClass.newInstance(); + screen.setHeaderCaption("New Game - " + item.getText()); + } + catch (Exception e) { + e.printStackTrace(); + return; + } + } + Forge.openScreen(screen); + } + } + + private static final ForgePreferences prefs = FModel.getPreferences(); + private static final NewGameMenu menu = new NewGameMenu(); + private static NewGameScreen preferredScreen; + + static { + try { + preferredScreen = NewGameScreen.valueOf(prefs.getPref(FPref.NEW_GAME_SCREEN)); + } + catch (Exception ex) { + ex.printStackTrace(); + preferredScreen = NewGameScreen.Constructed; + } + } + + public static void openPreferredScreen() { + preferredScreen.open(); + } + public static void setPreferredScreen(FScreen screen) { + for (NewGameScreen ngs : NewGameScreen.values()) { + if (ngs.screen == screen) { + preferredScreen = ngs; + prefs.setPref(FPref.NEW_GAME_SCREEN, ngs.name()); + prefs.save(); + return; + } + } + } + + public static NewGameMenu getMenu() { + return menu; + } + + private NewGameMenu() { + } + + @Override + protected void buildMenu() { + FScreen currentScreen = Forge.getCurrentScreen(); + for (NewGameScreen ngs : NewGameScreen.values()) { + addItem(ngs.item); + ngs.item.setSelected(currentScreen == ngs.screen); + } + } +} diff --git a/forge-gui-mobile/src/forge/screens/limited/LimitedScreen.java b/forge-gui-mobile/src/forge/screens/limited/NewDraftScreen.java similarity index 95% rename from forge-gui-mobile/src/forge/screens/limited/LimitedScreen.java rename to forge-gui-mobile/src/forge/screens/limited/NewDraftScreen.java index 8653386cb05..72d2e5c2c44 100644 --- a/forge-gui-mobile/src/forge/screens/limited/LimitedScreen.java +++ b/forge-gui-mobile/src/forge/screens/limited/NewDraftScreen.java @@ -12,6 +12,7 @@ import forge.limited.LimitedPoolType; import forge.limited.SealedCardPoolGenerator; import forge.screens.FScreen; import forge.screens.LoadingOverlay; +import forge.screens.home.NewGameMenu; import forge.toolbox.FButton; import forge.toolbox.FEvent; import forge.toolbox.FGroupBox; @@ -22,7 +23,7 @@ import forge.util.ThreadUtil; import forge.util.Utils; import forge.util.gui.SGuiChoose; -public class LimitedScreen extends FScreen { +public class NewDraftScreen extends FScreen { private static final float PADDING = Utils.scale(10); private final FGroupBox grpDraft = add(new FGroupBox("Booster Draft") { @@ -66,8 +67,8 @@ public class LimitedScreen extends FScreen { private final FButton btnNewSealed = grpSealed.add(new FButton("New Deck")); private final FButton btnLoadSealed = grpSealed.add(new FButton("Load Deck")); - public LimitedScreen() { - super("Draft / Sealed"); + public NewDraftScreen() { + super(null, NewGameMenu.getMenu()); lblDraftDesc.setFont(FSkinFont.get(12)); lblDraftDesc.setTextColor(FLabel.INLINE_LABEL_COLOR); diff --git a/forge-gui-mobile/src/forge/screens/limited/NewSealedScreen.java b/forge-gui-mobile/src/forge/screens/limited/NewSealedScreen.java new file mode 100644 index 00000000000..e167c9569db --- /dev/null +++ b/forge-gui-mobile/src/forge/screens/limited/NewSealedScreen.java @@ -0,0 +1,150 @@ +package forge.screens.limited; + +import forge.FThreads; +import forge.Forge; +import forge.assets.FSkinFont; +import forge.deck.DeckGroup; +import forge.deck.FDeckEditor; +import forge.deck.FDeckEditor.EditorType; +import forge.deck.io.DeckPreferences; +import forge.limited.BoosterDraft; +import forge.limited.LimitedPoolType; +import forge.limited.SealedCardPoolGenerator; +import forge.screens.FScreen; +import forge.screens.LoadingOverlay; +import forge.screens.home.NewGameMenu; +import forge.toolbox.FButton; +import forge.toolbox.FEvent; +import forge.toolbox.FGroupBox; +import forge.toolbox.FLabel; +import forge.toolbox.FEvent.FEventHandler; +import forge.toolbox.FTextArea; +import forge.util.ThreadUtil; +import forge.util.Utils; +import forge.util.gui.SGuiChoose; + +public class NewSealedScreen extends FScreen { + private static final float PADDING = Utils.scale(10); + + private final FGroupBox grpDraft = add(new FGroupBox("Booster Draft") { + @Override + protected void layoutBox(float x, float y, float w, float h) { + float buttonWidth = (w - PADDING) / 2; + float buttonHeight = btnNewDraft.getAutoSizeBounds().height * 1.2f; + float labelHeight = h - buttonHeight - PADDING; + + lblDraftDesc.setBounds(x, y, w, labelHeight); + y += labelHeight + PADDING; + btnNewDraft.setBounds(x, y, buttonWidth, buttonHeight); + btnLoadDraft.setBounds(x + buttonWidth + PADDING, y, buttonWidth, buttonHeight); + } + }); + private final FTextArea lblDraftDesc = grpDraft.add(new FTextArea(false, + "In Draft mode, three booster packs are rotated around eight players.\n\n" + + "Build a deck from the cards you choose. The AI will do the same.\n\n" + + "Then, play against any number of the AI opponents.")); + + private final FButton btnNewDraft = grpDraft.add(new FButton("New Draft")); + private final FButton btnLoadDraft = grpDraft.add(new FButton("Load Draft")); + + private final FGroupBox grpSealed = add(new FGroupBox("Sealed Deck") { + @Override + protected void layoutBox(float x, float y, float w, float h) { + float buttonWidth = (w - PADDING) / 2; + float buttonHeight = btnNewSealed.getAutoSizeBounds().height * 1.2f; + float labelHeight = h - buttonHeight - PADDING; + + lblSealedDesc.setBounds(x, y, w, labelHeight); + y += labelHeight + PADDING; + btnNewSealed.setBounds(x, y, buttonWidth, buttonHeight); + btnLoadSealed.setBounds(x + buttonWidth + PADDING, y, buttonWidth, buttonHeight); + } + }); + private final FTextArea lblSealedDesc = grpSealed.add(new FTextArea(false, + "In Sealed mode, you build a deck from booster packs (maximum 10).\n\n" + + "Build a deck from the cards you receive. A number of AI opponents will do the same.\n\n" + + "Then, play against each of the AI opponents.")); + private final FButton btnNewSealed = grpSealed.add(new FButton("New Deck")); + private final FButton btnLoadSealed = grpSealed.add(new FButton("Load Deck")); + + public NewSealedScreen() { + super(null, NewGameMenu.getMenu()); + + lblDraftDesc.setFont(FSkinFont.get(12)); + lblDraftDesc.setTextColor(FLabel.INLINE_LABEL_COLOR); + btnNewDraft.setFont(FSkinFont.get(16)); + btnNewDraft.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + ThreadUtil.invokeInGameThread(new Runnable() { //must run in game thread to prevent blocking UI thread + @Override + public void run() { + final LimitedPoolType poolType = SGuiChoose.oneOrNone("Choose Draft Format", LimitedPoolType.values()); + if (poolType == null) { return; } + + final BoosterDraft draft = BoosterDraft.createDraft(poolType); + if (draft == null) { return; } + + FThreads.invokeInEdtLater(new Runnable() { + @Override + public void run() { + LoadingOverlay.show("Loading new draft...", new Runnable() { + @Override + public void run() { + Forge.openScreen(new DraftingProcessScreen(draft)); + } + }); + } + }); + } + }); + } + }); + btnLoadDraft.setFont(btnNewDraft.getFont()); + btnLoadDraft.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + Forge.openScreen(new LoadDraftScreen()); + } + }); + lblSealedDesc.setFont(lblDraftDesc.getFont()); + lblSealedDesc.setTextColor(lblDraftDesc.getTextColor()); + btnNewSealed.setFont(btnNewDraft.getFont()); + btnNewSealed.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + ThreadUtil.invokeInGameThread(new Runnable() { //must run in game thread to prevent blocking UI thread + @Override + public void run() { + final DeckGroup sealed = SealedCardPoolGenerator.generateSealedDeck(false); + if (sealed == null) { return; } + + FThreads.invokeInEdtLater(new Runnable() { + @Override + public void run() { + DeckPreferences.setSealedDeck(sealed.getName()); + Forge.openScreen(new FDeckEditor(EditorType.Sealed, sealed.getName(), false)); + Forge.setBackScreen(new LoadSealedScreen()); //ensure pressing back goes to load sealed screen + } + }); + } + }); + } + }); + btnLoadSealed.setFont(btnNewDraft.getFont()); + btnLoadSealed.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + Forge.openScreen(new LoadSealedScreen()); + } + }); + } + + @Override + protected void doLayout(float startY, float width, float height) { + float groupWidth = width - 2 * PADDING; + float groupHeight = (height - startY - 3 * PADDING) / 2; + grpDraft.setBounds(PADDING, startY + PADDING, groupWidth, groupHeight); + grpSealed.setBounds(PADDING, startY + groupHeight + 2 * PADDING, groupWidth, groupHeight); + } +} diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/NewConquestScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/NewConquestScreen.java index 1b0ddb1f9ad..e1cb170c4f5 100644 --- a/forge-gui-mobile/src/forge/screens/planarconquest/NewConquestScreen.java +++ b/forge-gui-mobile/src/forge/screens/planarconquest/NewConquestScreen.java @@ -12,6 +12,7 @@ import forge.planarconquest.ConquestPreferences.CQPref; import forge.planarconquest.ConquestUtil; import forge.screens.FScreen; import forge.screens.LoadingOverlay; +import forge.screens.home.NewGameMenu; import forge.screens.planarconquest.ConquestMenu.LaunchReason; import forge.toolbox.FChoiceList; import forge.toolbox.FComboBox; @@ -50,7 +51,7 @@ public class NewConquestScreen extends FScreen { }).build()); public NewConquestScreen() { - super("New Planar Conquest"); + super(null, NewGameMenu.getMenu()); cbxStartingPlane.setChangedHandler(new FEventHandler() { @Override diff --git a/forge-gui-mobile/src/forge/screens/quest/NewQuestScreen.java b/forge-gui-mobile/src/forge/screens/quest/NewQuestScreen.java index 5980ba635c4..565f7902bd6 100644 --- a/forge-gui-mobile/src/forge/screens/quest/NewQuestScreen.java +++ b/forge-gui-mobile/src/forge/screens/quest/NewQuestScreen.java @@ -35,6 +35,7 @@ import forge.quest.data.GameFormatQuest; import forge.quest.data.QuestPreferences.QPref; import forge.screens.FScreen; import forge.screens.LoadingOverlay; +import forge.screens.home.NewGameMenu; import forge.screens.quest.QuestMenu.LaunchReason; import forge.toolbox.FCheckBox; import forge.toolbox.FComboBox; @@ -154,7 +155,7 @@ public class NewQuestScreen extends FScreen { }).build()); public NewQuestScreen() { - super("Start a New Quest"); + super(null, NewGameMenu.getMenu()); cbxStartingPool.addItem(StartingPoolType.Complete); cbxStartingPool.addItem(StartingPoolType.Rotating); diff --git a/forge-gui/src/main/java/forge/properties/ForgePreferences.java b/forge-gui/src/main/java/forge/properties/ForgePreferences.java index ba5157978ca..e6295dab844 100644 --- a/forge-gui/src/main/java/forge/properties/ForgePreferences.java +++ b/forge-gui/src/main/java/forge/properties/ForgePreferences.java @@ -88,6 +88,9 @@ public class ForgePreferences extends PreferencesStore { MATCH_HOT_SEAT_MODE("false"), //this only applies to mobile game MATCHPREF_PROMPT_FREE_BLOCKS("false"), + NEW_GAME_SCREEN("Constructed"), + LOAD_GAME_SCREEN("BoosterDraft"), + SUBMENU_CURRENTMENU ("CONSTRUCTED"), SUBMENU_SANCTIONED ("true"), SUBMENU_ONLINE ("false"),