diff --git a/.gitattributes b/.gitattributes index 9027e829cb0..9c156ae3e94 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1279,6 +1279,11 @@ forge-gui-mobile/src/forge/screens/match/winlose/GauntletWinLose.java -text forge-gui-mobile/src/forge/screens/match/winlose/LimitedWinLose.java -text forge-gui-mobile/src/forge/screens/match/winlose/QuestWinLose.java -text forge-gui-mobile/src/forge/screens/match/winlose/ViewWinLose.java -text +forge-gui-mobile/src/forge/screens/planarconquest/ConquestMapScreen.java -text +forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java -text +forge-gui-mobile/src/forge/screens/planarconquest/ConquestPrefsScreen.java -text +forge-gui-mobile/src/forge/screens/planarconquest/LoadConquestScreen.java -text +forge-gui-mobile/src/forge/screens/planarconquest/NewConquestScreen.java -text forge-gui-mobile/src/forge/screens/quest/LoadQuestScreen.java -text forge-gui-mobile/src/forge/screens/quest/NewQuestScreen.java -text forge-gui-mobile/src/forge/screens/quest/QuestBazaarScreen.java -text @@ -17134,6 +17139,12 @@ forge-gui/src/main/java/forge/model/MetaSet.java -text forge-gui/src/main/java/forge/model/MultipleForgeJarsFoundError.java -text forge-gui/src/main/java/forge/model/UnOpenedMeta.java -text forge-gui/src/main/java/forge/model/package-info.java svneol=native#text/plain +forge-gui/src/main/java/forge/planarconquest/ConquestController.java -text +forge-gui/src/main/java/forge/planarconquest/ConquestData.java -text +forge-gui/src/main/java/forge/planarconquest/ConquestDataIO.java -text +forge-gui/src/main/java/forge/planarconquest/ConquestDeckMap.java -text +forge-gui/src/main/java/forge/planarconquest/ConquestPlane.java -text +forge-gui/src/main/java/forge/planarconquest/ConquestPreferences.java -text forge-gui/src/main/java/forge/player/GamePlayerUtil.java -text forge-gui/src/main/java/forge/player/HumanCostDecision.java -text forge-gui/src/main/java/forge/player/HumanPlay.java -text diff --git a/forge-core/src/main/java/forge/card/CardRulesPredicates.java b/forge-core/src/main/java/forge/card/CardRulesPredicates.java index b96c6bdcd0b..b5bf4ff9880 100644 --- a/forge-core/src/main/java/forge/card/CardRulesPredicates.java +++ b/forge-core/src/main/java/forge/card/CardRulesPredicates.java @@ -10,6 +10,7 @@ import forge.util.PredicateString.StringOp; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * Filtering conditions specific for CardRules class, defined here along with @@ -149,6 +150,23 @@ public final class CardRulesPredicates { return new LeafString(LeafString.CardField.JOINED_TYPE, op, what); } + public static Predicate hasCreatureType(final String... creatureTypes) { + return new Predicate() { + @Override + public boolean apply(final CardRules card) { + if (!card.getType().isCreature()) { return false; } + + Set set = card.getType().getCreatureTypes(); + for (String creatureType : creatureTypes) { + if (set.contains(creatureType)) { + return true; + } + } + return false; + } + }; + } + /** * Has Keyword. * @@ -292,6 +310,15 @@ public final class CardRulesPredicates { return new LeafColor(LeafColor.ColorOperator.CountColorsGreaterOrEqual, cntColors); } + public static Predicate hasColorIdentity(final byte colors) { + return new Predicate() { + @Override + public boolean apply(CardRules rules) { + return rules.getColorIdentity().hasAllColors(colors); + } + }; + } + private static class LeafString extends PredicateString { public enum CardField { ORACLE_TEXT, NAME, SUBTYPE, JOINED_TYPE, COST diff --git a/forge-core/src/main/java/forge/util/FCollection.java b/forge-core/src/main/java/forge/util/FCollection.java index 6be8830b6be..5a3fc6a0d08 100644 --- a/forge-core/src/main/java/forge/util/FCollection.java +++ b/forge-core/src/main/java/forge/util/FCollection.java @@ -19,6 +19,11 @@ public class FCollection implements List, Set, FCollectionView, Clon public FCollection(T e) { add(e); } + public FCollection(T[] c) { + for (T e : c) { + add(e); + } + } public FCollection(Collection c) { for (T e : c) { add(e); diff --git a/forge-gui-mobile/src/forge/deck/FDeckEditor.java b/forge-gui-mobile/src/forge/deck/FDeckEditor.java index f05f776a11b..9a95e2042a2 100644 --- a/forge-gui-mobile/src/forge/deck/FDeckEditor.java +++ b/forge-gui-mobile/src/forge/deck/FDeckEditor.java @@ -106,6 +106,12 @@ public class FDeckEditor extends TabPageScreen { public Deck get() { return new Deck(); } + })), + PlanarConquest(new DeckController(null, new Supplier() { //delay setting root folder until conquest loaded + @Override + public Deck get() { + return new Deck(); + } })); private final DeckController controller; diff --git a/forge-gui-mobile/src/forge/screens/home/HomeScreen.java b/forge-gui-mobile/src/forge/screens/home/HomeScreen.java index c9c5260d429..cfd5d0d3384 100644 --- a/forge-gui-mobile/src/forge/screens/home/HomeScreen.java +++ b/forge-gui-mobile/src/forge/screens/home/HomeScreen.java @@ -9,8 +9,8 @@ import forge.assets.FSkinImage; import forge.screens.constructed.ConstructedScreen; import forge.screens.gauntlet.GauntletScreen; import forge.screens.limited.LimitedScreen; +import forge.screens.planarconquest.ConquestMenu; import forge.screens.quest.QuestMenu; -import forge.screens.quest.QuestMenu.LaunchReason; import forge.screens.settings.SettingsScreen; import forge.toolbox.FButton; import forge.toolbox.FEvent; @@ -39,15 +39,16 @@ public class HomeScreen extends FScreen { Forge.openScreen(new LimitedScreen()); } }); - addButton("???", new FEventHandler() { + addButton("Planar Conquest", 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(LaunchReason.StartQuestMode); + QuestMenu.launchQuestMode(QuestMenu.LaunchReason.StartQuestMode); } }); addButton("Gauntlets", new FEventHandler() { diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMapScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMapScreen.java new file mode 100644 index 00000000000..d2532bc81e5 --- /dev/null +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMapScreen.java @@ -0,0 +1,63 @@ +package forge.screens.planarconquest; + +import forge.FThreads; +import forge.quest.QuestUtil; +import forge.screens.LaunchScreen; +import forge.screens.LoadingOverlay; +import forge.toolbox.FOptionPane; + +public class ConquestMapScreen extends LaunchScreen { + protected static final float PADDING = FOptionPane.PADDING; + + public ConquestMapScreen() { + super("", ConquestMenu.getMenu()); + } + + @Override + public final void onActivate() { + update(); + } + + @Override + protected void startMatch() { + if (creatingMatch) { return; } + creatingMatch = true; //ensure user doesn't create multiple matches by tapping multiple times + + FThreads.invokeInBackgroundThread(new Runnable() { + @Override + public void run() { + if (QuestUtil.canStartGame()) { + FThreads.invokeInEdtLater(new Runnable() { + @Override + public void run() { + LoadingOverlay.show("Loading new game...", new Runnable() { + @Override + public void run() { + QuestUtil.finishStartingGame(); + creatingMatch = false; + } + }); + } + }); + return; + } + creatingMatch = false; + } + }); + } + + public void update() { + + } + + @Override + protected final boolean buildLaunchParams(LaunchParams launchParams) { + return false; //this override isn't needed + } + + @Override + protected void doLayoutAboveBtnStart(float startY, float width, float height) { + // TODO Auto-generated method stub + + } +} diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java new file mode 100644 index 00000000000..ec1844de55c --- /dev/null +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestMenu.java @@ -0,0 +1,116 @@ +package forge.screens.planarconquest; + +import java.io.File; + +import forge.Forge; +import forge.assets.FSkinImage; +import forge.deck.Deck; +import forge.deck.FDeckEditor.DeckController; +import forge.deck.FDeckEditor.EditorType; +import forge.menu.FMenuItem; +import forge.menu.FPopupMenu; +import forge.model.FModel; +import forge.planarconquest.ConquestDataIO; +import forge.planarconquest.ConquestPreferences.CQPref; +import forge.properties.ForgeConstants; +import forge.screens.FScreen; +import forge.screens.LoadingOverlay; +import forge.toolbox.FEvent; +import forge.toolbox.FEvent.FEventHandler; + +public class ConquestMenu extends FPopupMenu { + private static final ConquestMenu conquestMenu = new ConquestMenu(); + private static final ConquestMapScreen mapScreen = new ConquestMapScreen(); + private static final ConquestPrefsScreen prefsScreen = new ConquestPrefsScreen(); + + private static final FMenuItem mapItem = new FMenuItem("Planar Map", FSkinImage.QUEST_MAP, new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + Forge.openScreen(mapScreen); + } + }); + + public static ConquestMenu getMenu() { + return conquestMenu; + } + + private ConquestMenu() { + } + + public enum LaunchReason { + StartPlanarConquest, + LoadConquest, + NewConquest + } + + public static void launchPlanarConquest(final LaunchReason reason) { + //attempt to load current quest + final File dirConquests = new File(ForgeConstants.CONQUEST_SAVE_DIR); + final String questname = FModel.getConquestPreferences().getPref(CQPref.CURRENT_CONQUEST); + final File data = new File(dirConquests.getPath(), questname); + if (data.exists()) { + LoadingOverlay.show("Loading current conquest...", new Runnable() { + @Override + @SuppressWarnings("unchecked") + public void run() { + FModel.getConquest().load(ConquestDataIO.loadData(data)); + ((DeckController)EditorType.PlanarConquest.getController()).setRootFolder(FModel.getConquest().getDecks()); + if (reason == LaunchReason.StartPlanarConquest) { + Forge.openScreen(mapScreen); + } + else { + mapScreen.update(); + if (reason == LaunchReason.LoadConquest) { + Forge.back(); + if (Forge.onHomeScreen()) { //open map screen if Load Conquest screen was opening direct from home screen + Forge.openScreen(mapScreen); + } + } + else { + Forge.back(); + if (Forge.getCurrentScreen() instanceof LoadConquestScreen) { + Forge.back(); //remove LoadConquestScreen from screen stack + } + if (Forge.onHomeScreen()) { //open map screen if New Conquest screen was opening direct from home screen + Forge.openScreen(mapScreen); + } + } + } + } + }); + return; + } + + //if current quest can't be loaded, open New Conquest or Load Conquest screen based on whether a quest exists + if (dirConquests.exists() && dirConquests.isDirectory() && dirConquests.list().length > 0) { + Forge.openScreen(new LoadConquestScreen()); + } + else { + Forge.openScreen(new NewConquestScreen()); + } + } + + @Override + protected void buildMenu() { + FScreen currentScreen = Forge.getCurrentScreen(); + addItem(mapItem); mapItem.setSelected(currentScreen == mapScreen); + addItem(new FMenuItem("New Conquest", FSkinImage.NEW, new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + Forge.openScreen(new NewConquestScreen()); + } + })); + addItem(new FMenuItem("Load Conquest", FSkinImage.OPEN, new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + Forge.openScreen(new LoadConquestScreen()); + } + })); + addItem(new FMenuItem("Preferences", FSkinImage.SETTINGS, new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + Forge.openScreen(prefsScreen); + } + })); + } +} diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPrefsScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPrefsScreen.java new file mode 100644 index 00000000000..c8b385dd96a --- /dev/null +++ b/forge-gui-mobile/src/forge/screens/planarconquest/ConquestPrefsScreen.java @@ -0,0 +1,131 @@ +package forge.screens.planarconquest; + +import forge.assets.FImage; +import forge.assets.FSkinFont; +import forge.assets.FSkinImage; +import forge.model.FModel; +import forge.planarconquest.ConquestPreferences; +import forge.planarconquest.ConquestPreferences.CQPref; +import forge.screens.FScreen; +import forge.toolbox.FContainer; +import forge.toolbox.FDisplayObject; +import forge.toolbox.FEvent; +import forge.toolbox.FEvent.FEventHandler; +import forge.toolbox.FLabel; +import forge.toolbox.FNumericTextField; +import forge.toolbox.FOptionPane; +import forge.toolbox.FScrollPane; +import forge.toolbox.FTextField; +import forge.util.Utils; + +public class ConquestPrefsScreen extends FScreen { + private static final float PADDING = Utils.scale(5); + + private enum PrefsGroup { + TODO + } + + private FScrollPane scroller = add(new FScrollPane() { + @Override + protected ScrollBounds layoutAndGetScrollBounds(float visibleWidth, float visibleHeight) { + float x = PADDING; + float y = PADDING; + float w = visibleWidth - 2 * PADDING; + float fieldHeight = FTextField.getDefaultHeight(); + float dy = fieldHeight + PADDING; + + for (FDisplayObject child : getChildren()) { + if (child.isVisible()) { + child.setBounds(x, y, w, fieldHeight); + y += dy; + } + } + + return new ScrollBounds(visibleWidth, y); + } + }); + + public ConquestPrefsScreen() { + super("Conquest Preferences", ConquestMenu.getMenu()); + + scroller.add(new PrefsHeader("TODO", FSkinImage.QUEST_COIN, PrefsGroup.TODO)); + } + + @Override + protected void doLayout(float startY, float width, float height) { + scroller.setBounds(0, startY, width, height - startY); + } + + private class PrefsHeader extends FLabel { + private PrefsHeader(String title, FImage icon, final PrefsGroup group) { + super(new ButtonBuilder().text(title).font(FSkinFont.get(16)).icon(icon).iconScaleFactor(1f) + .command(new FEventHandler() { + private boolean showOptions = true; + + @Override + public void handleEvent(FEvent e) { + showOptions = !showOptions; + for (FDisplayObject child : scroller.getChildren()) { + if (child instanceof PrefsOption && ((PrefsOption)child).group == group) { + child.setVisible(showOptions); + } + } + scroller.revalidate(); + } + })); + } + } + + private static class PrefsOption extends FContainer { + private static final float FIELD_WIDTH = new FTextField("99999").getAutoSizeWidth(); //base width on 5 digit number + + private final FLabel label = add(new FLabel.Builder().build()); + private final OptionField field = add(new OptionField()); + private final CQPref pref; + private final PrefsGroup group; + + private PrefsOption(String label0, CQPref pref0, PrefsGroup group0) { + label.setText(label0); + pref = pref0; + group = group0; + field.setText(FModel.getConquestPreferences().getPref(pref0)); + } + + @Override + protected void doLayout(float width, float height) { + label.setBounds(0, 0, width - FIELD_WIDTH - PADDING, height); + field.setBounds(width - FIELD_WIDTH, 0, FIELD_WIDTH, height); + } + + private class OptionField extends FNumericTextField { + private OptionField() { + } + + @Override + protected boolean validate() { + if (super.validate()) { + final ConquestPreferences prefs = FModel.getConquestPreferences(); + + int val = Integer.parseInt(getText()); + + String validationError = prefs.validatePreference(pref, val); + if (validationError != null) { + String prefType; + switch (group) { + default: + prefType = "TODO"; + break; + } + FOptionPane.showErrorDialog(validationError, "Save Failed - " + prefType); + return false; + } + + prefs.setPref(pref, getText()); + prefs.save(); + return true; + } + return false; + } + } + } +} diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/LoadConquestScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/LoadConquestScreen.java new file mode 100644 index 00000000000..9f4211120d7 --- /dev/null +++ b/forge-gui-mobile/src/forge/screens/planarconquest/LoadConquestScreen.java @@ -0,0 +1,310 @@ +package forge.screens.planarconquest; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; + +import forge.FThreads; +import forge.Forge; +import forge.Graphics; +import forge.assets.FSkinColor; +import forge.assets.FSkinColor.Colors; +import forge.assets.FSkinFont; +import forge.assets.FSkinImage; +import forge.card.CardRenderer; +import forge.model.FModel; +import forge.planarconquest.ConquestController; +import forge.planarconquest.ConquestData; +import forge.planarconquest.ConquestDataIO; +import forge.planarconquest.ConquestPreferences.CQPref; +import forge.properties.ForgeConstants; +import forge.quest.QuestUtil; +import forge.screens.FScreen; +import forge.screens.settings.SettingsScreen; +import forge.toolbox.FButton; +import forge.toolbox.FEvent; +import forge.toolbox.FList; +import forge.toolbox.FEvent.FEventHandler; +import forge.util.ThreadUtil; +import forge.util.Utils; +import forge.util.gui.SOptionPane; + +public class LoadConquestScreen extends FScreen { + private static final float PADDING = Utils.AVG_FINGER_HEIGHT * 0.1f; + private static final FSkinColor SEL_COLOR = FSkinColor.get(Colors.CLR_ACTIVE); + + private final ConquestFileLister lstConquests = add(new ConquestFileLister()); + private final FButton btnNewConquest = add(new FButton("New")); + private final FButton btnRenameConquest = add(new FButton("Rename")); + private final FButton btnDeleteConquest = add(new FButton("Delete")); + + public LoadConquestScreen() { + super("Load Planar Conquest"); + + btnNewConquest.setFont(FSkinFont.get(16)); + btnNewConquest.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + Forge.openScreen(new NewConquestScreen()); + } + }); + btnRenameConquest.setFont(btnNewConquest.getFont()); + btnRenameConquest.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + renameConquest(lstConquests.getSelectedConquest()); + } + }); + btnDeleteConquest.setFont(btnNewConquest.getFont()); + btnDeleteConquest.setCommand(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + deleteConquest(lstConquests.getSelectedConquest()); + } + }); + + FThreads.invokeInBackgroundThread(new Runnable() { + @Override + public void run() { + final File dirConquests = new File(ForgeConstants.CONQUEST_SAVE_DIR); + final ConquestController qc = FModel.getConquest(); + + // Iterate over files and load quest data for each. + FilenameFilter takeDatFiles = new FilenameFilter() { + @Override + public boolean accept(final File dir, final String name) { + return name.endsWith(".dat"); + } + }; + File[] arrFiles = dirConquests.listFiles(takeDatFiles); + Map arrConquests = new HashMap(); + for (File f : arrFiles) { + arrConquests.put(f.getName(), ConquestDataIO.loadData(f)); + } + + // Populate list with available quest data. + lstConquests.setConquests(new ArrayList(arrConquests.values())); + + // If there are quests available, force select. + if (arrConquests.size() > 0) { + final String questname = FModel.getConquestPreferences().getPref(CQPref.CURRENT_CONQUEST); + + // Attempt to select previous quest. + if (arrConquests.get(questname) != null) { + lstConquests.setSelectedConquest(arrConquests.get(questname)); + } + else { + lstConquests.setSelectedIndex(0); + } + + // Drop into AllZone. + qc.load(lstConquests.getSelectedConquest()); + } + else { + qc.load(null); + } + } + }); + } + + @Override + protected void drawOverlay(Graphics g) { + float y = lstConquests.getTop(); + g.drawLine(1, FList.LINE_COLOR, 0, y, getWidth(), y); //draw top border for list + } + + @Override + protected void doLayout(float startY, float width, float height) { + float buttonWidth = (width - 2 * PADDING) / 3; + float buttonHeight = btnNewConquest.getAutoSizeBounds().height * 1.2f; + + float y = startY + 2 * PADDING; + lstConquests.setBounds(0, y, width, height - y - buttonHeight - 2 * PADDING); + y += lstConquests.getHeight() + PADDING; + + float x = 0; + btnNewConquest.setBounds(x, y, buttonWidth, buttonHeight); + x += buttonWidth + PADDING; + btnRenameConquest.setBounds(x, y, buttonWidth, buttonHeight); + x += buttonWidth + PADDING; + btnDeleteConquest.setBounds(x, y, buttonWidth, buttonHeight); + } + + private void changeConquest() { + FModel.getConquestPreferences().setPref(CQPref.CURRENT_CONQUEST, + lstConquests.getSelectedConquest().getName() + ".dat"); + FModel.getConquestPreferences().save(); + } + + private void renameConquest(final ConquestData quest) { + if (quest == null) { return; } + + ThreadUtil.invokeInGameThread(new Runnable() { + @Override + public void run() { + String questName; + String oldConquestName = quest.getName(); + while (true) { + questName = SOptionPane.showInputDialog("Enter new name for quest:", "Rename Conquest", null, oldConquestName); + if (questName == null) { return; } + + questName = QuestUtil.cleanString(questName); + if (questName.equals(oldConquestName)) { return; } //quit if chose same name + + if (questName.isEmpty()) { + SOptionPane.showMessageDialog("Please specify a quest name."); + continue; + } + + boolean exists = false; + for (ConquestData questData : lstConquests) { + if (questData.getName().equalsIgnoreCase(questName)) { + exists = true; + break; + } + } + if (exists) { + SOptionPane.showMessageDialog("A quest already exists with that name. Please pick another quest name."); + continue; + } + break; + } + + quest.rename(questName); + } + }); + } + + private void deleteConquest(final ConquestData quest) { + if (quest == null) { return; } + + ThreadUtil.invokeInGameThread(new Runnable() { + @Override + public void run() { + if (!SOptionPane.showConfirmDialog( + "Are you sure you want to delete '" + quest.getName() + "'?", + "Delete Conquest", "Delete", "Cancel")) { + return; + } + + new File(ForgeConstants.CONQUEST_SAVE_DIR, quest.getName() + ".dat").delete(); + + lstConquests.removeConquest(quest); + } + }); + } + + private class ConquestFileLister extends FList { + private int selectedIndex = 0; + + private ConquestFileLister() { + setListItemRenderer(new ListItemRenderer() { + @Override + public boolean tap(Integer index, ConquestData value, float x, float y, int count) { + if (count == 2) { + changeConquest(); + } + else { + selectedIndex = index; + } + return true; + } + + @Override + public float getItemHeight() { + return CardRenderer.getCardListItemHeight(false); + } + + @Override + public void drawValue(Graphics g, Integer index, ConquestData 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; + + String winRatio = value.getWins() + "W / " + value.getLosses() + "L"; + float winRatioWidth = font.getBounds(winRatio).width + SettingsScreen.SETTING_PADDING; + + g.drawText(name, font, foreColor, x, y, w - winRatioWidth, h, false, HAlignment.LEFT, false); + g.drawText(winRatio, font, foreColor, x, y, w, h, false, HAlignment.RIGHT, false); + + h += SettingsScreen.SETTING_PADDING; + y += h; + h = totalHeight - h + w * SettingsScreen.INSETS_FACTOR; + float iconSize = h + Utils.scale(1); + float iconOffset = SettingsScreen.SETTING_PADDING - Utils.scale(2); + + String cards = String.valueOf(value.getCardPool().countAll()); + font = FSkinFont.get(12); + float cardsWidth = font.getBounds(cards).width + iconSize + SettingsScreen.SETTING_PADDING; + g.drawImage(FSkinImage.HAND, x + w - cardsWidth + iconOffset, y - SettingsScreen.SETTING_PADDING, iconSize, iconSize); + g.drawText(cards, font, SettingsScreen.DESC_COLOR, x + w - cardsWidth + iconSize + SettingsScreen.SETTING_PADDING, y, w, h, false, HAlignment.LEFT, false); + g.drawImage(FSkinImage.QUEST_COINSTACK, x + w + iconOffset, y - SettingsScreen.SETTING_PADDING, iconSize, iconSize); + } + }); + } + + @Override + protected FSkinColor getItemFillColor(int index) { + if (index == selectedIndex) { + return SEL_COLOR; + } + return null; + } + + public void setConquests(List qd0) { + List sorted = new ArrayList(); + for (ConquestData qd : qd0) { + sorted.add(qd); + } + Collections.sort(sorted, new Comparator() { + @Override + public int compare(final ConquestData x, final ConquestData y) { + return x.getName().toLowerCase().compareTo(y.getName().toLowerCase()); + } + }); + setListData(sorted); + } + + public void removeConquest(ConquestData qd) { + removeItem(qd); + if (selectedIndex == getCount()) { + selectedIndex--; + } + revalidate(); + } + + public boolean setSelectedIndex(int i0) { + if (i0 >= getCount()) { return false; } + selectedIndex = i0; + return true; + } + + public ConquestData getSelectedConquest() { + if (selectedIndex == -1) { return null; } + return getItemAt(selectedIndex); + } + + public boolean setSelectedConquest(ConquestData qd0) { + for (int i = 0; i < getCount(); i++) { + if (getItemAt(i) == qd0) { + selectedIndex = i; + return true; + } + } + return false; + } + } +} diff --git a/forge-gui-mobile/src/forge/screens/planarconquest/NewConquestScreen.java b/forge-gui-mobile/src/forge/screens/planarconquest/NewConquestScreen.java new file mode 100644 index 00000000000..4fc2bc480a6 --- /dev/null +++ b/forge-gui-mobile/src/forge/screens/planarconquest/NewConquestScreen.java @@ -0,0 +1,142 @@ +package forge.screens.planarconquest; + +import forge.FThreads; +import forge.assets.FSkinFont; +import forge.assets.FSkinImage; +import forge.item.PaperCard; +import forge.model.FModel; +import forge.planarconquest.ConquestController; +import forge.planarconquest.ConquestData; +import forge.planarconquest.ConquestPlane; +import forge.planarconquest.ConquestPreferences.CQPref; +import forge.properties.ForgeConstants; +import forge.quest.QuestUtil; +import forge.screens.FScreen; +import forge.screens.LoadingOverlay; +import forge.toolbox.FChoiceList; +import forge.toolbox.FComboBox; +import forge.toolbox.FEvent; +import forge.toolbox.FEvent.FEventHandler; +import forge.toolbox.FLabel; +import forge.toolbox.FOptionPane; +import forge.util.FileUtil; +import forge.util.ThreadUtil; +import forge.util.Utils; +import forge.util.gui.SOptionPane; + +public class NewConquestScreen extends FScreen { + private static final float EMBARK_BTN_HEIGHT = 2 * Utils.AVG_FINGER_HEIGHT; + private static final float PADDING = FOptionPane.PADDING; + + private final FLabel lblDifficulty = add(new FLabel.Builder().text("Difficulty:").build()); + private final FComboBox cbxDifficulty = add(new FComboBox(new String[]{ "Easy", "Medium", "Hard", "Expert" })); + + private final FLabel lblStartingPlane = add(new FLabel.Builder().text("Starting world:").build()); + private final FComboBox cbxStartingPlane = add(new FComboBox(ConquestPlane.values())); + + private final FLabel lblStartingCommander = add(new FLabel.Builder().text("Starting commander:").build()); + private final FChoiceList lstCommanders = add(new FChoiceList(cbxStartingPlane.getSelectedItem().getCommanders())); + + private final FLabel btnEmbark = add(new FLabel.ButtonBuilder() + .font(FSkinFont.get(22)).text("Embark!").icon(FSkinImage.QUEST_ZEP).command(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + //create new quest in game thread so option panes can wait for input + ThreadUtil.invokeInGameThread(new Runnable() { + @Override + public void run() { + newConquest(); + } + }); + } + }).build()); + + public NewConquestScreen() { + super("New Planar Conquest"); + + cbxStartingPlane.setChangedHandler(new FEventHandler() { + @Override + public void handleEvent(FEvent e) { + lstCommanders.setListData(cbxStartingPlane.getSelectedItem().getCommanders()); + } + }); + } + + public int getSelectedDifficulty() { + int difficulty = cbxDifficulty.getSelectedIndex(); + if (difficulty < 0) { + difficulty = 0; + } + return difficulty; + } + + @Override + protected void doLayout(float startY, float width, float height) { + float x = PADDING; + float y = startY + PADDING; + float right = width - PADDING; + float w = width - 2 * PADDING; + float h = cbxStartingPlane.getHeight(); + float gapY = PADDING / 2; + + lblDifficulty.setBounds(x, y, width / 2 - x, h); + x += lblDifficulty.getWidth(); + cbxDifficulty.setBounds(x, y, right - x, h); + x = PADDING; + y += h + gapY; + + lblStartingPlane.setBounds(x, y, width / 2 - x, h); + x += lblStartingPlane.getWidth(); + cbxStartingPlane.setBounds(x, y, right - x, h); + x = PADDING; + y += h + gapY; + + lblStartingCommander.setBounds(x, y, w, h); + y += h; + lstCommanders.setBounds(x, y, w, height - EMBARK_BTN_HEIGHT - gapY - PADDING - y); + y += lstCommanders.getHeight() + gapY; + + btnEmbark.setBounds(x, y, w, EMBARK_BTN_HEIGHT); + } + + private void newConquest() { + String conquestName; + while (true) { + conquestName = SOptionPane.showInputDialog("Historians will recall your conquest as:", "Conquest Name"); + if (conquestName == null) { return; } + + conquestName = QuestUtil.cleanString(conquestName); + + if (conquestName.isEmpty()) { + SOptionPane.showMessageDialog("Please specify a conquest name."); + continue; + } + if (FileUtil.doesFileExist(ForgeConstants.CONQUEST_SAVE_DIR + conquestName + ".dat")) { + SOptionPane.showMessageDialog("A quest already exists with that name. Please pick another quest name."); + continue; + } + break; + } + startNewConquest(conquestName); + } + + private void startNewConquest(final String conquestName) { + FThreads.invokeInEdtLater(new Runnable() { + @Override + public void run() { + LoadingOverlay.show("Creating new quest...", new Runnable() { + @Override + public void run() { + ConquestController qc = FModel.getConquest(); + qc.load(new ConquestData(conquestName, getSelectedDifficulty(), cbxStartingPlane.getSelectedItem(), lstCommanders.getSelectedItem())); + qc.save(); + + // Save in preferences. + FModel.getConquestPreferences().setPref(CQPref.CURRENT_CONQUEST, conquestName + ".dat"); + FModel.getConquestPreferences().save(); + } + }); + } + }); + } +} diff --git a/forge-gui-mobile/src/forge/toolbox/FChoiceList.java b/forge-gui-mobile/src/forge/toolbox/FChoiceList.java index 1fb41fbd31d..e3fbfdbb6dd 100644 --- a/forge-gui-mobile/src/forge/toolbox/FChoiceList.java +++ b/forge-gui-mobile/src/forge/toolbox/FChoiceList.java @@ -1,7 +1,6 @@ package forge.toolbox; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; @@ -35,19 +34,19 @@ public class FChoiceList extends FList { private final CompactModeHandler compactModeHandler = new CompactModeHandler(); private final List selectedIndices = new ArrayList(); - public FChoiceList(Collection items) { + public FChoiceList(Iterable items) { this(items, null); } - protected FChoiceList(Collection items, T typeItem) { + protected FChoiceList(Iterable items, T typeItem) { this(items, 0, 1, typeItem); - if (items.size() > 0) { + if (getCount() > 0) { addSelectedIndex(0); //select first item by default } } - public FChoiceList(Collection items, int minChoices0, int maxChoices0) { + public FChoiceList(Iterable items, int minChoices0, int maxChoices0) { this(items, minChoices0, maxChoices0, null); } - protected FChoiceList(Collection items, int minChoices0, int maxChoices0, T typeItem) { + protected FChoiceList(Iterable items, int minChoices0, int maxChoices0, T typeItem) { super(items); minChoices = minChoices0; maxChoices = maxChoices0; diff --git a/forge-gui/src/main/java/forge/model/FModel.java b/forge-gui/src/main/java/forge/model/FModel.java index 13dae55eb71..260b8306ab6 100644 --- a/forge-gui/src/main/java/forge/model/FModel.java +++ b/forge-gui/src/main/java/forge/model/FModel.java @@ -38,6 +38,8 @@ import forge.gauntlet.GauntletData; import forge.interfaces.IProgressBar; import forge.itemmanager.ItemManagerConfig; import forge.limited.GauntletMini; +import forge.planarconquest.ConquestController; +import forge.planarconquest.ConquestPreferences; import forge.player.GamePlayerUtil; import forge.properties.ForgeConstants; import forge.properties.ForgePreferences; @@ -70,6 +72,7 @@ public class FModel { private static StaticData magicDb; private static QuestPreferences questPreferences; + private static ConquestPreferences conquestPreferences; private static ForgePreferences preferences; private static Map achievements; @@ -79,6 +82,7 @@ public class FModel { private static GauntletMini gauntlet; private static QuestController quest; + private static ConquestController conquest; private static CardCollections decks; private static IStorage blocks; @@ -153,6 +157,7 @@ public class FModel { formats = new GameFormat.Collection(new GameFormat.Reader(new File(ForgeConstants.BLOCK_DATA_DIR + "formats.txt"))); blocks = new StorageBase("Block definitions", new CardBlock.Reader(ForgeConstants.BLOCK_DATA_DIR + "blocks.txt", magicDb.getEditions())); questPreferences = new QuestPreferences(); + conquestPreferences = new ConquestPreferences(); fantasyBlocks = new StorageBase("Custom blocks", new CardBlock.Reader(ForgeConstants.BLOCK_DATA_DIR + "fantasyblocks.txt", magicDb.getEditions())); worlds = new StorageBase("Quest worlds", new QuestWorld.Reader(ForgeConstants.QUEST_WORLD_DIR + "worlds.txt")); @@ -169,6 +174,7 @@ public class FModel { decks = new CardCollections(); quest = new QuestController(); + conquest = new ConquestController(); CardPreferences.load(); DeckPreferences.load(); @@ -187,7 +193,11 @@ public class FModel { public static QuestController getQuest() { return quest; } - + + public static ConquestController getConquest() { + return conquest; + } + private static boolean keywordsLoaded = false; /** @@ -292,12 +302,16 @@ public class FModel { public static IStorage getBlocks() { return blocks; - } + } public static QuestPreferences getQuestPreferences() { return questPreferences; } + public static ConquestPreferences getConquestPreferences() { + return conquestPreferences; + } + public static GauntletData getGauntletData() { return gauntletData; } diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestController.java b/forge-gui/src/main/java/forge/planarconquest/ConquestController.java new file mode 100644 index 00000000000..39069c206dd --- /dev/null +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestController.java @@ -0,0 +1,63 @@ +/* + * Forge: Play Magic: the Gathering. + * Copyright (C) 2011 Nate + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package forge.planarconquest; + +import com.google.common.eventbus.Subscribe; + +import forge.deck.CardPool; +import forge.deck.Deck; +import forge.game.event.GameEvent; +import forge.util.storage.IStorage; + +public class ConquestController { + private ConquestData model; + private CardPool cardPool; + private transient IStorage decks; + + public ConquestController() { + } + + public String getName() { + return model == null ? null : model.getName(); + } + + public CardPool getCardPool() { + return cardPool; + } + + public IStorage getDecks() { + return decks; + } + + public void load(final ConquestData model0) { + model = model0; + cardPool = model == null ? null : model.getCardPool(); + decks = model == null ? null : model.getDeckStorage(); + } + + public void save() { + if (model != null) { + model.saveData(); + } + } + + @Subscribe + public void receiveGameEvent(GameEvent ev) { // Receives events only during planar conquest games + + } +} diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestData.java b/forge-gui/src/main/java/forge/planarconquest/ConquestData.java new file mode 100644 index 00000000000..ad8410b6a4d --- /dev/null +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestData.java @@ -0,0 +1,140 @@ +/* + * 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.planarconquest; + +import forge.deck.CardPool; +import forge.deck.Deck; +import forge.item.PaperCard; +import forge.properties.ForgeConstants; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public final class ConquestData { + /** Holds the latest version of the Conquest Data. */ + public static final int CURRENT_VERSION_NUMBER = 0; + + // This field places the version number into QD instance, + // but only when the object is created through the constructor + // DO NOT RENAME THIS FIELD + private int versionNumber = ConquestData.CURRENT_VERSION_NUMBER; + + private String name; + private int wins, losses; + private int winStreakBest = 0; + private int winStreakCurrent = 0; + private int difficulty; + private ConquestPlane startingPlane, currentPlane; + private List commanders = new ArrayList(); + + private final CardPool cardPool = new CardPool(); + private final HashMap decks = new HashMap(); + + public ConquestData() { //needed for XML serialization + } + + public ConquestData(String name0, int difficulty0, ConquestPlane startingPlane0, PaperCard startingCommander0) { + name = name0; + difficulty = difficulty0; + startingPlane = startingPlane0; + currentPlane = startingPlane0; + commanders.add(startingCommander0); + } + + public String getName() { + return name; + } + + public int getDifficulty() { + return difficulty; + } + + public ConquestPlane getStartingPlane() { + return startingPlane; + } + + public ConquestPlane getCurrentPlane() { + return currentPlane; + } + + public CardPool getCardPool() { + return cardPool; + } + + public ConquestDeckMap getDeckStorage() { + return new ConquestDeckMap(decks); + } + + public void addWin() { + wins++; + winStreakCurrent++; + + if (winStreakCurrent > winStreakBest) { + winStreakBest = winStreakCurrent; + } + } + + public void addLoss() { + losses++; + winStreakCurrent = 0; + } + + public int getWins() { + return wins; + } + + public int getLosses() { + return losses; + } + + public int getWinStreakBest() { + return winStreakBest; + } + + public int getWinStreakCurrent() { + return winStreakCurrent; + } + + // SERIALIZATION - related things + // This must be called by XML-serializer via reflection + public Object readResolve() { + return this; + } + + public void saveData() { + ConquestDataIO.saveData(this); + } + + public int getVersionNumber() { + return versionNumber; + } + public void setVersionNumber(final int versionNumber0) { + versionNumber = versionNumber0; + } + + public void rename(final String newName) { + File newpath = new File(ForgeConstants.CONQUEST_SAVE_DIR, newName + ".dat"); + File oldpath = new File(ForgeConstants.CONQUEST_SAVE_DIR, name + ".dat"); + oldpath.renameTo(newpath); + + name = newName; + saveData(); + } +} diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestDataIO.java b/forge-gui/src/main/java/forge/planarconquest/ConquestDataIO.java new file mode 100644 index 00000000000..9a07229c974 --- /dev/null +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestDataIO.java @@ -0,0 +1,144 @@ +/* + * 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.planarconquest; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StringReader; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +import javax.xml.parsers.ParserConfigurationException; + +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import com.thoughtworks.xstream.XStream; +import forge.deck.CardPool; +import forge.properties.ForgeConstants; +import forge.util.FileUtil; +import forge.util.IgnoringXStream; +import forge.util.ItemPool; + +public class ConquestDataIO { + static { + //ensure save directory exists if this class is used + FileUtil.ensureDirectoryExists(ForgeConstants.CONQUEST_SAVE_DIR); + } + + protected static XStream getSerializer(final boolean isIgnoring) { + final XStream xStream = isIgnoring ? new IgnoringXStream() : new XStream(); + xStream.autodetectAnnotations(true); + xStream.alias("CardPool", ItemPool.class); + xStream.alias("DeckSection", CardPool.class); + return xStream; + } + + public static ConquestData loadData(final File xmlSaveFile) { + try { + ConquestData data = null; + + final GZIPInputStream zin = new GZIPInputStream(new FileInputStream(xmlSaveFile)); + final StringBuilder xml = new StringBuilder(); + final char[] buf = new char[1024]; + final InputStreamReader reader = new InputStreamReader(zin); + while (reader.ready()) { + final int len = reader.read(buf); + if (len == -1) { + break; + } // when end of stream was reached + xml.append(buf, 0, len); + } + + zin.close(); + + String bigXML = xml.toString(); + data = (ConquestData) ConquestDataIO.getSerializer(true).fromXML(bigXML); + + if (data.getVersionNumber() != ConquestData.CURRENT_VERSION_NUMBER) { + try { + ConquestDataIO.updateSaveFile(data, bigXML, xmlSaveFile.getName().replace(".dat", "")); + } + catch (final Exception e) { + //BugReporter.reportException(e); + throw new RuntimeException(e); + } + } + + return data; + } + catch (final Exception ex) { + //BugReporter.reportException(ex, "Error loading Conquest Data"); + throw new RuntimeException(ex); + } + } + + private static void updateSaveFile(final ConquestData newData, final String input, String filename) throws ParserConfigurationException, SAXException, IOException, IllegalAccessException, NoSuchFieldException { + //final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + final InputSource is = new InputSource(); + is.setCharacterStream(new StringReader(input)); + //final Document document = builder.parse(is); + + final int saveVersion = newData.getVersionNumber(); + switch (saveVersion) { + // There should be a fall-through between the cases so that each + // version's changes get applied progressively + case 0: + + default: + break; + } + + // mark the QD as the latest version + newData.setVersionNumber(ConquestData.CURRENT_VERSION_NUMBER); + } + + public static synchronized void saveData(final ConquestData qd) { + try { + final XStream xStream = ConquestDataIO.getSerializer(false); + + final File f = new File(ForgeConstants.CONQUEST_SAVE_DIR, qd.getName()); + ConquestDataIO.savePacked(f + ".dat", xStream, qd); + // ConquestDataIO.saveUnpacked(f + ".xml", xStream, qd); + } + catch (final Exception ex) { + //BugReporter.reportException(ex, "Error saving Conquest Data."); + throw new RuntimeException(ex); + } + } + + private static void savePacked(final String f, final XStream xStream, final ConquestData qd) throws IOException { + final BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(f)); + final GZIPOutputStream zout = new GZIPOutputStream(bout); + xStream.toXML(qd, zout); + zout.flush(); + zout.close(); + } + + @SuppressWarnings("unused") // used only for debug purposes + private static void saveUnpacked(final String f, final XStream xStream, final ConquestData qd) throws IOException { + final BufferedOutputStream boutUnp = new BufferedOutputStream(new FileOutputStream(f)); + xStream.toXML(qd, boutUnp); + boutUnp.flush(); + boutUnp.close(); + } +} diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestDeckMap.java b/forge-gui/src/main/java/forge/planarconquest/ConquestDeckMap.java new file mode 100644 index 00000000000..741f3666ef8 --- /dev/null +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestDeckMap.java @@ -0,0 +1,39 @@ +/* + * 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.planarconquest; + +import forge.deck.Deck; +import forge.util.storage.StorageBase; + +import java.util.Map; + +public class ConquestDeckMap extends StorageBase { + public ConquestDeckMap(Map in) { + super("Conquest decks", in); + } + + @Override + public void add(final Deck deck) { + map.put(deck.getName(), deck); + } + + @Override + public void delete(final String deckName) { + map.remove(deckName); + } +} diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestPlane.java b/forge-gui/src/main/java/forge/planarconquest/ConquestPlane.java new file mode 100644 index 00000000000..acc9b56990e --- /dev/null +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestPlane.java @@ -0,0 +1,329 @@ +/* + * Forge: Play Magic: the Gathering. + * Copyright (C) 2011 Nate + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package forge.planarconquest; + +import com.google.common.base.Predicate; + +import forge.card.CardEdition; +import forge.card.CardRules; +import forge.card.CardRulesPredicates; +import forge.card.CardEdition.CardInSet; +import forge.card.CardType; +import forge.card.MagicColor; +import forge.deck.CardPool; +import forge.item.PaperCard; +import forge.model.FModel; +import forge.util.FCollection; +import forge.util.FCollectionView; + + +public enum ConquestPlane { + Alara("Alara", new String[] { + "ALA", "CON", "ARB" + }, new Region[] { + + }, new String[] { + + }), + Azoria("Azoria", new String[] { + + }, new Region[] { + + }, new String[] { + + }), + BolasMeditationRealm("Bolas's Meditation Realm", new String[] { + + }, new Region[] { + + }, new String[] { + + }), + Dominaria("Dominaria", new String[] { + + }, new Region[] { + + }, new String[] { + + }), + Equilor("Equilor", new String[] { + + }, new Region[] { + + }, new String[] { + + }), + Gastal("Gastal", new String[] { + + }, new Region[] { + + }, new String[] { + + }), + Innistrad("Innistrad", new String[] { + "ISD", "DKA", "AVR" + }, new Region[] { + + }, new String[] { + + }), + Kamigawa("Kamigawa", new String[] { + "CHK", "BOK", "SOK" + }, new Region[] { + new Region("Towabara", "", CardRulesPredicates.hasColorIdentity(MagicColor.WHITE), + new String[] { "Towabara", "Plains" }), + new Region("Minamo Academy", "", CardRulesPredicates.hasColorIdentity(MagicColor.BLUE), + new String[] { "Minamo", "Academy", "Island" }), + new Region("Takenuma", "", CardRulesPredicates.hasColorIdentity(MagicColor.BLACK), + new String[] { "Takenuma", "Swamp" }), + new Region("Sokenzan Mountains", "", CardRulesPredicates.hasColorIdentity(MagicColor.RED), + new String[] { "Sokenzan", "Mountain" }), + new Region("Jukai Forest", "", CardRulesPredicates.hasColorIdentity(MagicColor.GREEN), + new String[] { "Jukai", "Forest" }) + }, new String[] { + + }), + Lorwyn("Lorwyn", new String[] { + + }, new Region[] { + + }, new String[] { + + }), + Mercadia("Mercadia", new String[] { + "MMQ", "NEM", "PCY" + }, new Region[] { + new Region("Deepwood", "", CardRulesPredicates.hasCreatureType("Zombie", "Ghoul", "Dryad"), + new String[] { }), + new Region("Mercadia City", "", CardRulesPredicates.hasCreatureType("Goblin"), + new String[] { }), + new Region("Rishada", "", CardRulesPredicates.hasCreatureType("Pirate", "Rebel", "Mercenary"), + new String[] { }), + new Region("Rushwood", "", CardRulesPredicates.hasCreatureType("Beast", "Troll"), + new String[] { }), + new Region("Saprazzo", "", CardRulesPredicates.hasCreatureType("Merfolk", "Human"), + new String[] { }) + }, new String[] { + + }), + Mirrodin("Mirrodin", new String[] { + "MRD", "DST", "5DN", "SOM", "MBS", "NPH" + }, new Region[] { + new Region("Mirrodin's Core", "Mirrodin's Core", null, + new String[] { "Core", "Mycosynth", "Memnarch" }), + new Region("The Glimmervoid", "Glimmervoid", CardRulesPredicates.hasKeyword("Sunburst"), + new String[] { "Glimmervoid" }), + new Region("Mephidross", "", CardRulesPredicates.hasColorIdentity(MagicColor.BLACK), + new String[] { "Dross", "Mephidross" }), + new Region("The Oxidda Chain", "", CardRulesPredicates.hasColorIdentity(MagicColor.RED), + new String[] { "Oxidda", "Chain", "Mountain" }), + new Region("The Quicksilver Sea", "", CardRulesPredicates.hasColorIdentity(MagicColor.BLUE), + new String[] { "Quicksilver", "Sea", "Island" }), + new Region("The Razor Fields", "", CardRulesPredicates.hasColorIdentity(MagicColor.WHITE), + new String[] { "Razor", "Fields", "Plains" }), + new Region("The Tangle", "", CardRulesPredicates.hasColorIdentity(MagicColor.GREEN), + new String[] { "Tangle", "Forest" }) + }, new String[] { + + }), + Rabiah("Rabiah", new String[] { + "ARN" + }, new Region[] { + + }, new String[] { + + }), + Rath("Rath", new String[] { + "TMP", "STH", "EXO" + }, new Region[] { + + }, new String[] { + + }), + Ravnica("Ravnica", new String[] { + "RAV", "GPT", "DIS", "RTR", "GTC", "DGM" + }, new Region[] { + + }, new String[] { + + }), + Segovia("Segovia", new String[] { + + }, new Region[] { + + }, new String[] { + + }), + SerraRealm("Serra's Realm", new String[] { + + }, new Region[] { + + }, new String[] { + + }), + Shandalar("Shandalar", new String[] { + "2ED", "ARN", "ATQ", "3ED", "LEG", "DRK", "4ED" + }, new Region[] { + + }, new String[] { + + }), + Ulgrotha("Ulgrotha", new String[] { + + }, new Region[] { + + }, new String[] { + + }), + Theros("Theros", new String[] { + + }, new Region[] { + + }, new String[] { + + }), + Zendikar("Zendikar", new String[] { + "ZEN", "WWK", "ROE" + }, new Region[] { + + }, new String[] { + + }); + + private final String name; + private final FCollection editions = new FCollection(); + private final FCollection regions; + private final FCollection bannedCards; + private final CardPool cardPool = new CardPool(); + private final FCollection commanders = new FCollection(); + + private ConquestPlane(String name0, String[] setCodes0, Region[] regions0, String[] bannedCards0) { + name = name0; + regions = new FCollection(regions0); + bannedCards = new FCollection(bannedCards0); + for (String setCode : setCodes0) { + CardEdition edition = FModel.getMagicDb().getEditions().get(setCode); + if (edition != null) { + editions.add(edition); + for (CardInSet card : edition.getCards()) { + if (!bannedCards.contains(card.name)) { + PaperCard pc = FModel.getMagicDb().getCommonCards().getCard(card.name, setCode); + if (pc != null) { + CardType type = pc.getRules().getType(); + if (!type.isBasicLand()) { //don't include basic lands + boolean isCommander = type.isLegendary() && type.isCreature(); + cardPool.add(pc); + if (isCommander) { + commanders.add(pc); + } + int count = 0; + for (Region region : regions) { + if (region.pred.apply(pc)) { + region.cardPool.add(pc); + if (isCommander) { + region.commanders.add(pc); + } + count++; + } + } + //if card doesn't match any region's predicate, + //make card available to all regions + if (count == 0) { + for (Region region : regions) { + region.cardPool.add(pc); + if (isCommander) { + region.commanders.add(pc); + } + } + } + } + } + } + } + } + } + } + + public String getName() { + return name; + } + + public FCollectionView getEditions() { + return editions; + } + + public FCollectionView getBannedCards() { + return bannedCards; + } + + public FCollectionView getRegions() { + return regions; + } + + public CardPool getCardPool() { + return cardPool; + } + + public FCollectionView getCommanders() { + return commanders; + } + + public String toString() { + return name; + } + + public static class Region { + private final String name; + private final String artCardName; + private final Predicate pred; + private final CardPool cardPool = new CardPool(); + private final FCollection commanders = new FCollection(); + + private Region(String name0, String artCardName0, final Predicate rulesPred, final String[] keywords) { + name = name0; + artCardName = artCardName0; + + pred = new Predicate() { + @Override + public boolean apply(PaperCard pc) { + if (rulesPred != null && rulesPred.apply(pc.getRules())) { + return true; + } + for (String s : keywords) { + if (pc.getName().contains(s)) { + return true; + } + } + return false; + } + }; + } + + public String getName() { + return name; + } + + public CardPool getCardPool() { + return cardPool; + } + + public FCollectionView getCommanders() { + return commanders; + } + } +} diff --git a/forge-gui/src/main/java/forge/planarconquest/ConquestPreferences.java b/forge-gui/src/main/java/forge/planarconquest/ConquestPreferences.java new file mode 100644 index 00000000000..fbe369ae8af --- /dev/null +++ b/forge-gui/src/main/java/forge/planarconquest/ConquestPreferences.java @@ -0,0 +1,124 @@ +/* + * 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.planarconquest; + +import forge.properties.ForgeConstants; +import forge.properties.PreferencesStore; + +import java.io.Serializable; + +@SuppressWarnings("serial") +public class ConquestPreferences extends PreferencesStore implements Serializable { + /** + * Preference identifiers, and their default values. + */ + public static enum CQPref { + CURRENT_CONQUEST("DEFAULT"); + + private final String strDefaultVal; + + CQPref(final String s0) { + this.strDefaultVal = s0; + } + + public String getDefault() { + return this.strDefaultVal; + } + } + + public static enum DifficultyPrefs { + } + + public ConquestPreferences() { + super(ForgeConstants.CONQUEST_PREFS_FILE, CQPref.class); + } + + protected CQPref[] getEnumValues() { + return CQPref.values(); + } + + protected CQPref valueOf(String name) { + try { + return CQPref.valueOf(name); + } + catch (Exception e) { + return null; + } + } + + protected String getPrefDefault(CQPref key) { + return key.getDefault(); + } + + public String getPref(DifficultyPrefs pref, int difficultyIndex) { + String newCQPref = pref.toString(); + + switch (difficultyIndex) { + case 0: + newCQPref += "_EASY"; + break; + case 1: + newCQPref += "_MEDIUM"; + break; + case 2: + newCQPref += "_HARD"; + break; + case 3: + newCQPref += "_EXPERT"; + break; + default: + try { + throw new Exception(); + } catch (final Exception e1) { + System.err.println("Difficulty index out of bounds: " + difficultyIndex); + e1.printStackTrace(); + } + } + + return getPref(CQPref.valueOf(newCQPref)); + } + + public int getPrefInt(DifficultyPrefs pref, int difficultyIndex) { + return Integer.parseInt(this.getPref(pref, difficultyIndex)); + } + + public static String getDifficulty(int difficultyIndex) { + String s; + switch (difficultyIndex) { + case 1: + s = "EASY"; + break; + case 2: + s = "MEDIUM"; + break; + case 3: + s = "HARD"; + break; + case 4: + s = "EXPERT"; + break; + default: + s = "UNKNOWN"; + } + return s; + } + + public String validatePreference(CQPref qpref, int val) { + return null; + } +} diff --git a/forge-gui/src/main/java/forge/properties/ForgeConstants.java b/forge-gui/src/main/java/forge/properties/ForgeConstants.java index 4172dce3b7d..70b35f4c0cb 100644 --- a/forge-gui/src/main/java/forge/properties/ForgeConstants.java +++ b/forge-gui/src/main/java/forge/properties/ForgeConstants.java @@ -100,6 +100,7 @@ public final class ForgeConstants { // data that is only in the profile dirs public static final String USER_QUEST_DIR = USER_DIR + "quest/"; + public static final String USER_CONQUEST_DIR = USER_DIR + "conquest/"; public static final String USER_PREFS_DIR = USER_DIR + "preferences/"; public static final String USER_GAMES_DIR = USER_DIR + "games/"; public static final String LOG_FILE = USER_DIR + "forge.log"; @@ -113,10 +114,12 @@ public final class ForgeConstants { public static final String DECK_PLANE_DIR = DECK_BASE_DIR + "planar/"; public static final String DECK_COMMANDER_DIR = DECK_BASE_DIR + "commander/"; public static final String QUEST_SAVE_DIR = USER_QUEST_DIR + "saves/"; + public static final String CONQUEST_SAVE_DIR = USER_CONQUEST_DIR + "saves/"; public static final String MAIN_PREFS_FILE = USER_PREFS_DIR + "forge.preferences"; public static final String CARD_PREFS_FILE = USER_PREFS_DIR + "card.preferences"; public static final String DECK_PREFS_FILE = USER_PREFS_DIR + "deck.preferences"; public static final String QUEST_PREFS_FILE = USER_PREFS_DIR + "quest.preferences"; + public static final String CONQUEST_PREFS_FILE = USER_PREFS_DIR + "conquest.preferences"; public static final String ITEM_VIEW_PREFS_FILE = USER_PREFS_DIR + "item_view.preferences"; // data that has defaults in the program dir but overrides/additions in the user dir