Start fleshing out network support. Preliminary support for:

- Network communication (both chat and game data);
- Lobby including remote players.
Long way to go before actually starting a network game, but we're getting there!
This commit is contained in:
elcnesh
2015-02-26 09:13:40 +00:00
parent 805bed02c7
commit 7ff89bd6b2
41 changed files with 3402 additions and 1778 deletions

View File

@@ -29,6 +29,7 @@ import forge.download.GuiDownloader;
import forge.error.BugReportDialog;
import forge.gui.BoxedProductCardListViewer;
import forge.gui.CardListViewer;
import forge.gui.FNetOverlay;
import forge.gui.GuiChoose;
import forge.gui.framework.FScreen;
import forge.interfaces.IGuiBase;
@@ -278,4 +279,10 @@ public class GuiDesktop implements IGuiBase {
Singletons.getControl().addMatch(match);
return match;
}
@Override
public void netMessage(final String origin, final String message) {
FNetOverlay.SINGLETON_INSTANCE.showUp("");
FNetOverlay.SINGLETON_INSTANCE.addMessage(origin, message);
}
}

View File

@@ -1,5 +1,9 @@
package forge.gui;
import forge.model.FModel;
import forge.net.FGameClient;
import forge.net.game.MessageEvent;
import forge.properties.ForgePreferences.FPref;
import forge.toolbox.*;
import forge.toolbox.FSkin.SkinnedPanel;
import net.miginfocom.swing.MigLayout;
@@ -31,20 +35,26 @@ public enum FNetOverlay {
private final FTextField txtInput = new FTextField.Builder().maxLength(60).build();
private final FLabel cmdSend = new FLabel.ButtonBuilder().text("Send").build();
//private boolean minimized = false;
private int height = 120;
private int width = 400;
private final ActionListener onSend = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String message = txtInput.getText();
txtInput.setText("");
if ( StringUtils.isBlank(message) )
return;
private FGameClient client = null;
public void setGameClient(final FGameClient client) {
this.client = client;
}
private final ActionListener onSend = new ActionListener() {
@Override public final void actionPerformed(final ActionEvent e) {
final String message = txtInput.getText();
txtInput.setText("");
if (StringUtils.isBlank(message)) {
return;
}
if (client != null) {
client.send(new MessageEvent(FModel.getPreferences().getPref(FPref.PLAYER_NAME), message));
}
// lobby.speak(ChatArea.Room, lobby.getGuiPlayer(), message);
}
};

View File

@@ -13,6 +13,7 @@ import forge.screens.home.gauntlet.VSubmenuGauntletBuild;
import forge.screens.home.gauntlet.VSubmenuGauntletContests;
import forge.screens.home.gauntlet.VSubmenuGauntletLoad;
import forge.screens.home.gauntlet.VSubmenuGauntletQuick;
import forge.screens.home.online.VOnlineLobby;
import forge.screens.home.online.VSubmenuOnlineLobby;
import forge.screens.home.quest.VSubmenuChallenges;
import forge.screens.home.quest.VSubmenuDuels;
@@ -73,9 +74,11 @@ public enum EDocID {
HOME_DRAFT (VSubmenuDraft.SINGLETON_INSTANCE),
HOME_SEALED (VSubmenuSealed.SINGLETON_INSTANCE),
HOME_WINSTON (VSubmenuWinston.SINGLETON_INSTANCE),
HOME_LOBBY (VSubmenuOnlineLobby.SINGLETON_INSTANCE),
HOME_NETWORK (VSubmenuOnlineLobby.SINGLETON_INSTANCE),
HOME_RELEASE_NOTES (VSubmenuReleaseNotes.SINGLETON_INSTANCE),
ONLINE_LOBBY (VOnlineLobby.SINGLETON_INSTANCE),
REPORT_MESSAGE (),
REPORT_STACK (),
REPORT_COMBAT (),

View File

@@ -12,6 +12,8 @@ import forge.screens.deckeditor.CDeckEditorUI;
import forge.screens.deckeditor.VDeckEditorUI;
import forge.screens.home.CHomeUI;
import forge.screens.home.VHomeUI;
import forge.screens.home.online.COnlineLobby;
import forge.screens.home.online.VOnlineLobby;
import forge.screens.match.CMatchUI;
import forge.screens.match.VMatchUI;
import forge.screens.workshop.CWorkshopUI;
@@ -151,6 +153,15 @@ public class FScreen {
"Leave Bazaar",
null,
false);
public static final FScreen ONLINE_LOBBY = new FScreen(
VOnlineLobby.SINGLETON_INSTANCE,
COnlineLobby.SINGLETON_INSTANCE,
"Online Lobby",
FSkin.getImage(FSkinProp.IMG_CHAOS),
true,
"Leave Lobby",
null,
false);
private final IVTopLevelUI view;
private final ICDoc controller;

View File

@@ -1,7 +1,11 @@
package forge.screens.home;
import forge.UiCommand;
import java.util.List;
import javax.swing.JMenu;
import forge.Singletons;
import forge.UiCommand;
import forge.gui.FNetOverlay;
import forge.gui.framework.EDocID;
import forge.gui.framework.ICDoc;
@@ -9,17 +13,12 @@ import forge.menus.IMenuProvider;
import forge.menus.MenuUtil;
import forge.model.FModel;
import forge.net.FServer;
import forge.net.NetServer;
import forge.net.FServerManager;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
import forge.properties.ForgeConstants;
import forge.screens.home.sanctioned.VSubmenuConstructed;
import forge.toolbox.FAbsolutePositioner;
import javax.swing.*;
import java.util.List;
/**
* Assembles Swing components of exit submenu option singleton.
*
@@ -88,13 +87,13 @@ public enum CHomeUI implements ICDoc, IMenuProvider {
VHomeUI.SINGLETON_INSTANCE.getLblStartServer().setCommand(new Runnable() {
@Override
public void run() {
NetServer srv = FServer.getServer();
srv.listen(ForgeConstants.SERVER_PORT_NUMBER);
//final NetServer srv = FServer.getServer();
//srv.listen(ForgeConstants.SERVER_PORT_NUMBER);
VHomeUI.SINGLETON_INSTANCE.getLblStopServer().setEnabled(true);
VHomeUI.SINGLETON_INSTANCE.getLblStartServer().setEnabled(false);
FNetOverlay.SINGLETON_INSTANCE.showUp("Server listening on port " + srv.getPortNumber());
FNetOverlay.SINGLETON_INSTANCE.showUp("");//"Server listening on port " + srv.getPortNumber());
}
});
@@ -102,6 +101,7 @@ public enum CHomeUI implements ICDoc, IMenuProvider {
@Override
public void run() {
FServer.getServer().stop();
FServerManager.getInstance().stopServer();
VHomeUI.SINGLETON_INSTANCE.getLblStopServer().setEnabled(false);
VHomeUI.SINGLETON_INSTANCE.getLblStartServer().setEnabled(true);

View File

@@ -0,0 +1,372 @@
package forge.screens.home;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import javax.swing.SwingUtilities;
import com.beust.jcommander.internal.Maps;
import forge.GuiBase;
import forge.LobbyPlayer;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckFormat;
import forge.deck.DeckSection;
import forge.deck.DeckType;
import forge.deck.DeckgenUtil;
import forge.game.GameType;
import forge.game.player.RegisteredPlayer;
import forge.gui.GuiDialog;
import forge.interfaces.IGuiGame;
import forge.item.PaperCard;
import forge.match.HostedMatch;
import forge.model.CardCollections;
import forge.model.FModel;
import forge.player.GamePlayerUtil;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
import forge.toolbox.FList;
import forge.toolbox.FOptionPane;
import forge.util.Aggregates;
import forge.util.storage.IStorage;
public class CLobby {
private final VLobby view;
public CLobby(final VLobby view) {
this.view = view;
}
public void update() {
SwingUtilities.invokeLater(new Runnable() {
@Override public final void run() {
final CardCollections cColl = FModel.getDecks();
FList<Object> deckList;
Vector<Object> listData;
Object val;
for (int i = 0; i < 8; i++) {
// Commander: reinit deck list and restore last selections (if any)
deckList = view.getCommanderDeckLists().get(i);
listData = new Vector<Object>();
listData.add("Generate");
if (cColl.getCommander().size() > 0) {
listData.add("Random");
for (Deck comDeck : cColl.getCommander()) {
listData.add(comDeck);
}
}
val = deckList.getSelectedValue();
deckList.setListData(listData);
if (null != val) {
deckList.setSelectedValue(val, true);
}
if (-1 == deckList.getSelectedIndex()) {
deckList.setSelectedIndex(0);
} // End Commander
// Archenemy: reinit deck list and restore last selections (if any)
deckList = view.getSchemeDeckLists().get(i);
listData = new Vector<Object>();
listData.add("Use deck's scheme section (random if unavailable)");
listData.add("Generate");
if (cColl.getScheme().size() > 0) {
listData.add("Random");
for (Deck schemeDeck : cColl.getScheme()) {
listData.add(schemeDeck);
}
}
val = deckList.getSelectedValue();
deckList.setListData(listData);
if (null != val) {
deckList.setSelectedValue(val, true);
}
if (-1 == deckList.getSelectedIndex()) {
deckList.setSelectedIndex(0);
} // End Archenemy
// Planechase: reinit deck lists and restore last selections (if any)
deckList = view.getPlanarDeckLists().get(i);
listData = new Vector<Object>();
listData.add("Use deck's planes section (random if unavailable)");
listData.add("Generate");
if (cColl.getPlane().size() > 0) {
listData.add("Random");
for (Deck planarDeck : cColl.getPlane()) {
listData.add(planarDeck);
}
}
val = deckList.getSelectedValue();
deckList.setListData(listData);
if (null != val) {
deckList.setSelectedValue(val, true);
}
if (-1 == deckList.getSelectedIndex()) {
deckList.setSelectedIndex(0);
} // End Planechase
view.updateVanguardList(i);
}
// General updates when switching back to this view
view.updatePlayersFromPrefs();
view.getBtnStart().requestFocusInWindow();
}
});
}
public void initialize() {
view.getDeckChooser(0).initialize(FPref.CONSTRUCTED_P1_DECK_STATE, DeckType.PRECONSTRUCTED_DECK);
view.getDeckChooser(1).initialize(FPref.CONSTRUCTED_P2_DECK_STATE, DeckType.COLOR_DECK);
view.getDeckChooser(2).initialize(FPref.CONSTRUCTED_P3_DECK_STATE, DeckType.COLOR_DECK);
view.getDeckChooser(3).initialize(FPref.CONSTRUCTED_P4_DECK_STATE, DeckType.COLOR_DECK);
view.getDeckChooser(4).initialize(FPref.CONSTRUCTED_P5_DECK_STATE, DeckType.COLOR_DECK);
view.getDeckChooser(5).initialize(FPref.CONSTRUCTED_P6_DECK_STATE, DeckType.COLOR_DECK);
view.getDeckChooser(6).initialize(FPref.CONSTRUCTED_P7_DECK_STATE, DeckType.COLOR_DECK);
view.getDeckChooser(7).initialize(FPref.CONSTRUCTED_P8_DECK_STATE, DeckType.COLOR_DECK);
// Start button event handling
view.getBtnStart().addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent arg0) {
startGame(view.getAppliedVariants());
}
});
final ForgePreferences prefs = FModel.getPreferences();
// Checkbox event handling
view.getCbSingletons().addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent arg0) {
prefs.setPref(FPref.DECKGEN_SINGLETONS, String.valueOf(view.getCbSingletons().isSelected()));
prefs.save();
}
});
view.getCbArtifacts().addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent arg0) {
prefs.setPref(FPref.DECKGEN_ARTIFACTS, String.valueOf(view.getCbArtifacts().isSelected()));
prefs.save();
}
});
// Pre-select checkboxes
view.getCbSingletons().setSelected(prefs.getPrefBoolean(FPref.DECKGEN_SINGLETONS));
view.getCbArtifacts().setSelected(prefs.getPrefBoolean(FPref.DECKGEN_ARTIFACTS));
}
/** Starts a match with the applied variants. */
private void startGame(final Set<GameType> variantTypes) {
if (!view.isEnoughTeams()) {
FOptionPane.showMessageDialog("There are not enough teams! Please adjust team allocations.");
return;
}
for (final int i : view.getParticipants()) {
if (view.getDeckChooser(i).getPlayer() == null) {
FOptionPane.showMessageDialog("Please specify a deck for " + view.getPlayerName(i));
return;
}
} // Is it even possible anymore? I think current implementation assigns decks automatically.
GameType autoGenerateVariant = null;
boolean isCommanderMatch = false;
boolean isTinyLeadersMatch = false;
if (!variantTypes.isEmpty()) {
isTinyLeadersMatch = variantTypes.contains(GameType.TinyLeaders);
isCommanderMatch = isTinyLeadersMatch || variantTypes.contains(GameType.Commander);
if (!isCommanderMatch) {
for (GameType variant : variantTypes) {
if (variant.isAutoGenerated()) {
autoGenerateVariant = variant;
break;
}
}
}
}
boolean checkLegality = FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY);
//Auto-generated decks don't need to be checked here
//Commander deck replaces regular deck and is checked later
if (checkLegality && autoGenerateVariant == null && !isCommanderMatch) {
for (final int i : view.getParticipants()) {
String name = view.getPlayerName(i);
String errMsg = GameType.Constructed.getDeckFormat().getDeckConformanceProblem(view.getDeckChooser(i).getPlayer().getDeck());
if (null != errMsg) {
FOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Deck");
return;
}
}
}
final List<RegisteredPlayer> players = new ArrayList<RegisteredPlayer>();
final Map<RegisteredPlayer, IGuiGame> guis = Maps.newHashMap();
final IGuiGame gui = GuiBase.getInterface().getNewGuiGame();
for (final int i : view.getParticipants()) {
final String name = view.getPlayerName(i);
final boolean isAI = view.isPlayerAI(i);
final LobbyPlayer lobbyPlayer = isAI
? GamePlayerUtil.createAiPlayer(name, view.getPlayerAvatar(i), view.getAiOptions(i))
: GamePlayerUtil.getGuiPlayer(name, i);
RegisteredPlayer rp = view.getDeckChooser(i).getPlayer();
if (variantTypes.isEmpty()) {
rp.setTeamNumber(view.getTeam(i));
players.add(rp.setPlayer(lobbyPlayer));
} else {
Deck deck = null;
PaperCard vanguardAvatar = null;
if (isCommanderMatch) {
final Object selected = view.getCommanderDeckLists().get(i).getSelectedValue();
if (selected instanceof String) {
final String sel = (String) selected;
final IStorage<Deck> comDecks = FModel.getDecks().getCommander();
if (sel.equals("Random") && comDecks.size() > 0) {
deck = Aggregates.random(comDecks);
}
} else {
deck = (Deck) selected;
}
GameType commanderGameType = isTinyLeadersMatch ? GameType.TinyLeaders : GameType.Commander;
if (deck == null) { //Can be null if player deselects the list selection or chose Generate
deck = DeckgenUtil.generateCommanderDeck(isAI, commanderGameType);
}
if (checkLegality) {
String errMsg = commanderGameType.getDeckFormat().getDeckConformanceProblem(deck);
if (null != errMsg) {
FOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid " + commanderGameType + " Deck");
return;
}
}
} else if (autoGenerateVariant != null) {
deck = autoGenerateVariant.autoGenerateDeck(rp);
CardPool avatarPool = deck.get(DeckSection.Avatar);
if (avatarPool != null) {
vanguardAvatar = avatarPool.get(0);
}
}
// Initialise variables for other variants
deck = deck == null ? rp.getDeck() : deck;
Iterable<PaperCard> schemes = null;
final boolean playerIsArchenemy = view.isPlayerArchenemy(i);
Iterable<PaperCard> planes = null;
//Archenemy
if (variantTypes.contains(GameType.ArchenemyRumble)
|| (variantTypes.contains(GameType.Archenemy) && playerIsArchenemy)) {
Object selected = view.getSchemeDeckLists().get(i).getSelectedValue();
CardPool schemePool = null;
if (selected instanceof String) {
String sel = (String) selected;
if (sel.contains("Use deck's scheme section")) {
if (deck.has(DeckSection.Schemes)) {
schemePool = deck.get(DeckSection.Schemes);
} else {
sel = "Random";
}
}
IStorage<Deck> sDecks = FModel.getDecks().getScheme();
if (sel.equals("Random") && sDecks.size() != 0) {
schemePool = Aggregates.random(sDecks).get(DeckSection.Schemes);
}
} else {
schemePool = ((Deck) selected).get(DeckSection.Schemes);
}
if (schemePool == null) { //Can be null if player deselects the list selection or chose Generate
schemePool = DeckgenUtil.generateSchemePool();
}
if (checkLegality) {
String errMsg = DeckFormat.getSchemeSectionConformanceProblem(schemePool);
if (null != errMsg) {
FOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Scheme Deck");
return;
}
}
schemes = schemePool.toFlatList();
}
//Planechase
if (variantTypes.contains(GameType.Planechase)) {
Object selected = view.getPlanarDeckLists().get(i).getSelectedValue();
CardPool planePool = null;
if (selected instanceof String) {
String sel = (String) selected;
if (sel.contains("Use deck's planes section")) {
if (deck.has(DeckSection.Planes)) {
planePool = deck.get(DeckSection.Planes);
} else {
sel = "Random";
}
}
IStorage<Deck> pDecks = FModel.getDecks().getPlane();
if (sel.equals("Random") && pDecks.size() != 0) {
planePool = Aggregates.random(pDecks).get(DeckSection.Planes);
}
} else {
planePool = ((Deck) selected).get(DeckSection.Planes);
}
if (planePool == null) { //Can be null if player deselects the list selection or chose Generate
planePool = DeckgenUtil.generatePlanarPool();
}
if (checkLegality) {
String errMsg = DeckFormat.getPlaneSectionConformanceProblem(planePool);
if (null != errMsg) {
FOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Planar Deck");
return;
}
}
planes = planePool.toFlatList();
}
//Vanguard
if (variantTypes.contains(GameType.Vanguard)) {
Object selected = view.getVanguardLists().get(i).getSelectedValue();
if (selected instanceof String) {
String sel = (String) selected;
if (sel.contains("Use deck's default avatar") && deck.has(DeckSection.Avatar)) {
vanguardAvatar = deck.get(DeckSection.Avatar).get(0);
} else { //Only other string is "Random"
if (isAI) { //AI
vanguardAvatar = Aggregates.random(view.getNonRandomAiAvatars());
} else { //Human
vanguardAvatar = Aggregates.random(view.getNonRandomHumanAvatars());
}
}
} else {
vanguardAvatar = (PaperCard)selected;
}
if (vanguardAvatar == null) { //ERROR! null if avatar deselected on list
GuiDialog.message("No Vanguard avatar selected for " + name
+ ". Please choose one or disable the Vanguard variant");
return;
}
}
rp = RegisteredPlayer.forVariants(variantTypes, deck, schemes, playerIsArchenemy, planes, vanguardAvatar);
rp.setTeamNumber(view.getTeam(i));
players.add(rp.setPlayer(lobbyPlayer));
}
if (!isAI) {
guis.put(rp, gui);
}
view.getDeckChooser(i).saveState();
}
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
hostedMatch.startMatch(GameType.Constructed, variantTypes, players, guis);
}
}

View File

@@ -9,7 +9,7 @@ package forge.screens.home;
*/
public enum EMenuGroup {
SANCTIONED ("Sanctioned Formats"),
//ONLINE ("Online Multiplayer"),
ONLINE ("Online Multiplayer"),
QUEST ("Quest Mode"),
GAUNTLET ("Gauntlets"),
SETTINGS ("Game Settings");

View File

@@ -0,0 +1,670 @@
package forge.screens.home;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.MouseEvent;
import java.util.List;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JPopupMenu;
import net.miginfocom.swing.MigLayout;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Predicate;
import forge.Singletons;
import forge.UiCommand;
import forge.assets.FSkinProp;
import forge.deck.DeckSection;
import forge.game.GameType;
import forge.gui.framework.FScreen;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
import forge.screens.deckeditor.CDeckEditorUI;
import forge.screens.deckeditor.controllers.CEditorCommander;
import forge.screens.deckeditor.controllers.CEditorVariant;
import forge.screens.home.sanctioned.AvatarSelector;
import forge.toolbox.FComboBox;
import forge.toolbox.FComboBoxWrapper;
import forge.toolbox.FLabel;
import forge.toolbox.FMouseAdapter;
import forge.toolbox.FPanel;
import forge.toolbox.FRadioButton;
import forge.toolbox.FSkin;
import forge.toolbox.FSkin.SkinColor;
import forge.toolbox.FSkin.SkinImage;
import forge.toolbox.FTextField;
import forge.util.MyRandom;
import forge.util.NameGenerator;
import forge.util.gui.SOptionPane;
@SuppressWarnings("serial")
public class PlayerPanel extends FPanel {
private final static ForgePreferences prefs = FModel.getPreferences();
private static final SkinColor unfocusedPlayerOverlay = FSkin.getColor(FSkin.Colors.CLR_OVERLAY).alphaColor(120);
private final int index;
private final boolean allowRemote;
private final FLabel nameRandomiser;
private final FLabel avatarLabel = new FLabel.Builder().opaque(true).hoverable(true).iconScaleFactor(0.99f).iconInBackground(true).build();
private int avatarIndex;
private final FTextField txtPlayerName = new FTextField.Builder().text("Player name").build();
private FRadioButton radioHuman;
private FRadioButton radioAi;
private JCheckBoxMenuItem radioAiUseSimulation;
private FRadioButton radioOpen;
/** Whether this panel is occupied by a remote player. */
private boolean isRemote;
private FComboBoxWrapper<Object> teamComboBox = new FComboBoxWrapper<Object>();
private FComboBoxWrapper<Object> aeTeamComboBox = new FComboBoxWrapper<Object>();
private final FLabel deckBtn = new FLabel.ButtonBuilder().text("Select a deck").build();
private final FLabel deckLabel;
private final String variantBtnConstraints = "height 30px, hidemode 3";
private boolean playerIsArchenemy = false;
private final FLabel scmDeckSelectorBtn = new FLabel.ButtonBuilder().text("Select a scheme deck").build();
private final FLabel scmDeckEditor = new FLabel.ButtonBuilder().text("Scheme Deck Editor").build();
private final FLabel scmLabel;
private final FLabel cmdDeckSelectorBtn = new FLabel.ButtonBuilder().text("Select a Commander deck").build();
private final FLabel cmdDeckEditor = new FLabel.ButtonBuilder().text("Commander Deck Editor").build();
private final FLabel cmdLabel;
private final FLabel pchDeckSelectorBtn = new FLabel.ButtonBuilder().text("Select a planar deck").build();
private final FLabel pchDeckEditor = new FLabel.ButtonBuilder().text("Planar Deck Editor").build();
private final FLabel pchLabel;
private final FLabel vgdSelectorBtn = new FLabel.ButtonBuilder().text("Select a Vanguard avatar").build();
private final FLabel vgdLabel;
private final VLobby lobby;
public PlayerPanel(final VLobby lobby, final int index, final boolean allowRemote) {
super();
this.lobby = lobby;
this.deckLabel = lobby.newLabel("Deck:");
this.scmLabel = lobby.newLabel("Scheme deck:");
this.cmdLabel = lobby.newLabel("Commander deck:");
this.pchLabel = lobby.newLabel("Planar deck:");
this.vgdLabel = lobby.newLabel("Vanguard:");
this.index = index;
this.allowRemote = allowRemote;
this.playerIsArchenemy = index == 0;
setLayout(new MigLayout("insets 10px, gap 5px"));
// Add a button to players 3+ (or if server) to remove them from the setup
if (index >= 2 || allowRemote) {
FLabel closeBtn = createCloseButton();
this.add(closeBtn, "w 20, h 20, pos (container.w-20) 0");
}
createAvatar();
this.add(avatarLabel, "spany 2, width 80px, height 80px");
createNameEditor();
this.add(lobby.newLabel("Name:"), "w 40px, h 30px, gaptop 5px");
this.add(txtPlayerName, "h 30px, pushx, growx");
nameRandomiser = createNameRandomizer();
this.add(nameRandomiser, "h 30px, w 30px, gaptop 5px");
createPlayerTypeOptions();
this.add(radioHuman, "gapright 5px");
this.add(radioAi, "wrap");
this.add(lobby.newLabel("Team:"), "w 40px, h 30px");
populateTeamsComboBoxes();
teamComboBox.addActionListener(teamListener);
aeTeamComboBox.addActionListener(teamListener);
teamComboBox.addTo(this, variantBtnConstraints + ", pushx, growx, gaptop 5px");
aeTeamComboBox.addTo(this, variantBtnConstraints + ", pushx, growx, gaptop 5px");
if (allowRemote) {
this.add(radioOpen, "gapleft 1px");
}
this.add(deckLabel, variantBtnConstraints + ", cell 0 2, sx 2, ax right");
this.add(deckBtn, variantBtnConstraints + ", cell 2 2, pushx, growx, wmax 100%-153px, h 30px, spanx 4, wrap");
addHandlersDeckSelector();
this.add(cmdLabel, variantBtnConstraints + ", cell 0 3, sx 2, ax right");
this.add(cmdDeckSelectorBtn, variantBtnConstraints + ", cell 2 3, growx, pushx");
this.add(cmdDeckEditor, variantBtnConstraints + ", cell 3 3, sx 3, growx, wrap");
this.add(scmLabel, variantBtnConstraints + ", cell 0 4, sx 2, ax right");
this.add(scmDeckSelectorBtn, variantBtnConstraints + ", cell 2 4, growx, pushx");
this.add(scmDeckEditor, variantBtnConstraints + ", cell 3 4, sx 3, growx, wrap");
this.add(pchLabel, variantBtnConstraints + ", cell 0 5, sx 2, ax right");
this.add(pchDeckSelectorBtn, variantBtnConstraints + ", cell 2 5, growx, pushx");
this.add(pchDeckEditor, variantBtnConstraints + ", cell 3 5, sx 3, growx, wrap");
this.add(vgdLabel, variantBtnConstraints + ", cell 0 6, sx 2, ax right");
this.add(vgdSelectorBtn, variantBtnConstraints + ", cell 2 6, sx 4, growx, wrap");
addHandlersToVariantsControls();
updateVariantControlsVisibility();
this.addMouseListener(new FMouseAdapter() {
@Override public final void onLeftMouseDown(final MouseEvent e) {
avatarLabel.requestFocusInWindow();
}
});
update();
}
private void update() {
final boolean enableComponents = !(isOpen() || isRemote());
avatarLabel.setEnabled(enableComponents);
txtPlayerName.setEnabled(enableComponents);
nameRandomiser.setEnabled(enableComponents);
deckLabel.setVisible(enableComponents);
deckBtn.setVisible(enableComponents);
}
private final FMouseAdapter radioMouseAdapter = new FMouseAdapter() {
@Override public final void onLeftClick(final MouseEvent e) {
avatarLabel.requestFocusInWindow();
lobby.updateVanguardList(index);
update();
}
};
/** Listens to name text fields and gives the appropriate player focus.
* Also saves the name preference when leaving player one's text field. */
private FocusAdapter nameFocusListener = new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
lobby.changePlayerFocus(index);
}
@Override
public void focusLost(FocusEvent e) {
final Object source = e.getSource();
if (source instanceof FTextField) { // the text box
FTextField nField = (FTextField)source;
String newName = nField.getText().trim();
if (index == 0 && !StringUtils.isBlank(newName)
&& StringUtils.isAlphanumericSpace(newName) && prefs.getPref(FPref.PLAYER_NAME) != newName) {
prefs.setPref(FPref.PLAYER_NAME, newName);
prefs.save();
}
}
}
};
/** Listens to avatar buttons and gives the appropriate player focus. */
private FocusAdapter avatarFocusListener = new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
lobby.changePlayerFocus(index);
}
};
private FMouseAdapter avatarMouseListener = new FMouseAdapter() {
@Override public final void onLeftClick(final MouseEvent e) {
if (!avatarLabel.isEnabled()) {
return;
}
final FLabel avatar = (FLabel)e.getSource();
PlayerPanel.this.lobby.changePlayerFocus(index);
avatar.requestFocusInWindow();
final AvatarSelector aSel = new AvatarSelector(getPlayerName(), avatarIndex, PlayerPanel.this.lobby.getUsedAvatars());
for (final FLabel lbl : aSel.getSelectables()) {
lbl.setCommand(new UiCommand() {
@Override
public void run() {
setAvatar(Integer.valueOf(lbl.getName().substring(11)));
aSel.setVisible(false);
}
});
}
aSel.setVisible(true);
aSel.dispose();
if (index < 2) {
PlayerPanel.this.lobby.updateAvatarPrefs();
}
}
@Override public final void onRightClick(final MouseEvent e) {
if (!avatarLabel.isEnabled()) {
return;
}
PlayerPanel.this.lobby.changePlayerFocus(index);
avatarLabel.requestFocusInWindow();
setRandomAvatar();
if (index < 2) {
PlayerPanel.this.lobby.updateAvatarPrefs();
}
}
};
public void updateVariantControlsVisibility() {
boolean isCommanderApplied = false;
boolean isPlanechaseApplied = false;
boolean isVanguardApplied = false;
boolean isArchenemyApplied = false;
boolean archenemyVisiblity = false;
boolean isDeckBuildingAllowed = true;
for (final GameType variant : lobby.getAppliedVariants()) {
switch (variant) {
case Archenemy:
isArchenemyApplied = true;
if (playerIsArchenemy) {
archenemyVisiblity = true;
}
break;
case ArchenemyRumble:
archenemyVisiblity = true;
break;
case Commander:
case TinyLeaders:
isCommanderApplied = true;
isDeckBuildingAllowed = false; //Commander deck replaces basic deck, so hide that
break;
case Planechase:
isPlanechaseApplied = true;
break;
case Vanguard:
isVanguardApplied = true;
break;
default:
if (variant.isAutoGenerated()) {
isDeckBuildingAllowed = false;
}
break;
}
}
deckLabel.setVisible(isDeckBuildingAllowed);
deckBtn.setVisible(isDeckBuildingAllowed);
cmdDeckSelectorBtn.setVisible(isCommanderApplied);
cmdDeckEditor.setVisible(isCommanderApplied);
cmdLabel.setVisible(isCommanderApplied);
scmDeckSelectorBtn.setVisible(archenemyVisiblity);
scmDeckEditor.setVisible(archenemyVisiblity);
scmLabel.setVisible(archenemyVisiblity);
teamComboBox.setVisible(!isArchenemyApplied);
aeTeamComboBox.setVisible(isArchenemyApplied);
aeTeamComboBox.setEnabled(!(isArchenemyApplied && playerIsArchenemy));
pchDeckSelectorBtn.setVisible(isPlanechaseApplied);
pchDeckEditor.setVisible(isPlanechaseApplied);
pchLabel.setVisible(isPlanechaseApplied);
vgdSelectorBtn.setVisible(isVanguardApplied);
vgdLabel.setVisible(isVanguardApplied);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (lobby.getPlayerPanelWithFocus() != this) {
FSkin.setGraphicsColor(g, unfocusedPlayerOverlay);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
}
}
int getIndex() {
return index;
}
public boolean isAi() {
return radioAi.isSelected();
}
public boolean isSimulatedAi() {
return radioAi.isSelected() && radioAiUseSimulation.isSelected();
}
public boolean isOpen() {
return radioOpen.isSelected() && !isRemote;
}
public boolean isArchenemy() {
return playerIsArchenemy;
}
public boolean isRemote() {
return isRemote;
}
public void setRemote(final boolean remote) {
isRemote = remote;
update();
}
public void setVanguardButtonText(String text) {
vgdSelectorBtn.setText(text);
}
public void setDeckSelectorButtonText(String text) {
deckBtn.setText(text);
}
public void focusOnAvatar() {
avatarLabel.requestFocusInWindow();
}
private void populateTeamsComboBoxes() {
aeTeamComboBox.addItem("Archenemy");
aeTeamComboBox.addItem("Heroes");
aeTeamComboBox.setSelectedIndex(lobby.getArchenemyTeams().get(index) - 1);
aeTeamComboBox.setEnabled(playerIsArchenemy);
for (int i = 1; i <= VLobby.MAX_PLAYERS; i++) {
teamComboBox.addItem(i);
}
teamComboBox.setSelectedIndex(lobby.getTeams().get(index) - 1);
teamComboBox.setEnabled(true);
}
private ActionListener teamListener = new ActionListener() {
@SuppressWarnings("unchecked")
@Override
public void actionPerformed(ActionEvent e) {
FComboBox<Object> cb = (FComboBox<Object>)e.getSource();
cb.requestFocusInWindow();
Object selection = cb.getSelectedItem();
if (null == selection) {
return;
}
if (PlayerPanel.this.lobby.getAppliedVariants().contains(GameType.Archenemy)) {
String sel = (String) selection;
if (sel.contains("Archenemy")) {
PlayerPanel.this.lobby.setLastArchenemy(index);
for (PlayerPanel pp : PlayerPanel.this.lobby.getPlayerPanels()) {
int i = pp.index;
PlayerPanel.this.lobby.getArchenemyTeams().set(i, i == PlayerPanel.this.lobby.getLastArchenemy() ? 1 : 2);
pp.aeTeamComboBox.setSelectedIndex(i == PlayerPanel.this.lobby.getLastArchenemy() ? 0 : 1);
pp.toggleIsPlayerArchenemy();
}
}
} else {
Integer sel = (Integer) selection;
PlayerPanel.this.lobby.getTeams().set(index, sel);
}
PlayerPanel.this.lobby.changePlayerFocus(index);
}
};
public void toggleIsPlayerArchenemy() {
if (lobby.getAppliedVariants().contains(GameType.Archenemy)) {
playerIsArchenemy = lobby.getLastArchenemy() == index;
} else {
playerIsArchenemy = lobby.getAppliedVariants().contains(GameType.ArchenemyRumble);
}
updateVariantControlsVisibility();
}
/**
* @param index
*/
private void addHandlersToVariantsControls() {
// Archenemy buttons
scmDeckSelectorBtn.setCommand(new Runnable() {
@Override
public void run() {
PlayerPanel.this.lobby.setCurrentGameMode(PlayerPanel.this.lobby.getVntArchenemy().isSelected() ? GameType.Archenemy : GameType.ArchenemyRumble);
scmDeckSelectorBtn.requestFocusInWindow();
PlayerPanel.this.lobby.changePlayerFocus(index, PlayerPanel.this.lobby.getCurrentGameMode());
}
});
scmDeckEditor.setCommand(new UiCommand() {
@Override
public void run() {
PlayerPanel.this.lobby.setCurrentGameMode(PlayerPanel.this.lobby.getVntArchenemy().isSelected() ? GameType.Archenemy : GameType.ArchenemyRumble);
Predicate<PaperCard> predSchemes = new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard arg0) {
return arg0.getRules().getType().isScheme();
}
};
Singletons.getControl().setCurrentScreen(FScreen.DECK_EDITOR_ARCHENEMY);
CDeckEditorUI.SINGLETON_INSTANCE.setEditorController(
new CEditorVariant(FModel.getDecks().getScheme(), predSchemes, DeckSection.Schemes, FScreen.DECK_EDITOR_ARCHENEMY, CDeckEditorUI.SINGLETON_INSTANCE.getCDetailPicture()));
}
});
// Commander buttons
cmdDeckSelectorBtn.setCommand(new Runnable() {
@Override
public void run() {
PlayerPanel.this.lobby.setCurrentGameMode(PlayerPanel.this.lobby.getVntTinyLeaders().isSelected() ? GameType.TinyLeaders : GameType.Commander);
cmdDeckSelectorBtn.requestFocusInWindow();
PlayerPanel.this.lobby.changePlayerFocus(index, PlayerPanel.this.lobby.getCurrentGameMode());
}
});
cmdDeckEditor.setCommand(new UiCommand() {
@Override
public void run() {
PlayerPanel.this.lobby.setCurrentGameMode(PlayerPanel.this.lobby.getVntTinyLeaders().isSelected() ? GameType.TinyLeaders : GameType.Commander);
Singletons.getControl().setCurrentScreen(FScreen.DECK_EDITOR_COMMANDER);
CDeckEditorUI.SINGLETON_INSTANCE.setEditorController(new CEditorCommander(CDeckEditorUI.SINGLETON_INSTANCE.getCDetailPicture()));
}
});
// Planechase buttons
pchDeckSelectorBtn.setCommand(new Runnable() {
@Override
public void run() {
PlayerPanel.this.lobby.setCurrentGameMode(GameType.Planechase);
pchDeckSelectorBtn.requestFocusInWindow();
PlayerPanel.this.lobby.changePlayerFocus(index, GameType.Planechase);
}
});
pchDeckEditor.setCommand(new UiCommand() {
@Override
public void run() {
PlayerPanel.this.lobby.setCurrentGameMode(GameType.Planechase);
Predicate<PaperCard> predPlanes = new Predicate<PaperCard>() {
@Override
public boolean apply(PaperCard arg0) {
return arg0.getRules().getType().isPlane() || arg0.getRules().getType().isPhenomenon();
}
};
Singletons.getControl().setCurrentScreen(FScreen.DECK_EDITOR_PLANECHASE);
CDeckEditorUI.SINGLETON_INSTANCE.setEditorController(
new CEditorVariant(FModel.getDecks().getPlane(), predPlanes, DeckSection.Planes, FScreen.DECK_EDITOR_PLANECHASE, CDeckEditorUI.SINGLETON_INSTANCE.getCDetailPicture()));
}
});
// Vanguard buttons
vgdSelectorBtn.setCommand(new Runnable() {
@Override
public void run() {
PlayerPanel.this.lobby.setCurrentGameMode(GameType.Vanguard);
vgdSelectorBtn.requestFocusInWindow();
PlayerPanel.this.lobby.changePlayerFocus(index, GameType.Vanguard);
}
});
}
/**
* @param index
*/
private void createPlayerTypeOptions() {
radioHuman = new FRadioButton(allowRemote ? "Local" : "Human", index == 0);
radioAi = new FRadioButton("AI", !allowRemote && index != 0);
radioOpen = new FRadioButton("Open", allowRemote && index != 0);
final JPopupMenu menu = new JPopupMenu();
radioAiUseSimulation = new JCheckBoxMenuItem("Use Simulation");
menu.add(radioAiUseSimulation);
radioAi.setComponentPopupMenu(menu);
radioHuman.addMouseListener(radioMouseAdapter);
radioAi.addMouseListener(radioMouseAdapter);
radioOpen.addMouseListener(radioMouseAdapter);
final ButtonGroup tempBtnGroup = new ButtonGroup();
tempBtnGroup.add(radioHuman);
tempBtnGroup.add(radioAi);
tempBtnGroup.add(radioOpen);
}
/**
* @param index
*/
private void addHandlersDeckSelector() {
deckBtn.setCommand(new Runnable() {
@Override
public void run() {
PlayerPanel.this.lobby.setCurrentGameMode(GameType.Constructed);
deckBtn.requestFocusInWindow();
PlayerPanel.this.lobby.changePlayerFocus(index, GameType.Constructed);
}
});
}
/**
* @param index
* @return
*/
private FLabel createNameRandomizer() {
final FLabel newNameBtn = new FLabel.Builder().tooltip("Get a new random name").iconInBackground(false)
.icon(FSkin.getIcon(FSkinProp.ICO_EDIT)).hoverable(true).opaque(false)
.unhoveredAlpha(0.9f).build();
newNameBtn.setCommand(new UiCommand() {
@Override
public void run() {
String newName = PlayerPanel.this.lobby.getNewName();
if (null == newName) {
return;
}
txtPlayerName.setText(newName);
if (index == 0) {
prefs.setPref(FPref.PLAYER_NAME, newName);
prefs.save();
}
txtPlayerName.requestFocus();
PlayerPanel.this.lobby.changePlayerFocus(index);
}
});
newNameBtn.addFocusListener(nameFocusListener);
return newNameBtn;
}
/**
* @param index
* @return
*/
private void createNameEditor() {
String name;
if (index == 0) {
name = FModel.getPreferences().getPref(FPref.PLAYER_NAME);
if (name.isEmpty()) {
name = "Human";
}
}
else {
name = NameGenerator.getRandomName("Any", "Any", lobby.getPlayerNames());
}
txtPlayerName.setText(name);
txtPlayerName.setFocusable(true);
txtPlayerName.setFont(FSkin.getFont(14));
txtPlayerName.addActionListener(lobby.nameListener);
txtPlayerName.addFocusListener(nameFocusListener);
}
private FLabel createCloseButton() {
final FLabel closeBtn = new FLabel.Builder().tooltip("Remove").iconInBackground(false)
.icon(FSkin.getIcon(FSkinProp.ICO_CLOSE)).hoverable(true).build();
closeBtn.setCommand(new Runnable() {
@Override public final void run() {
if (isRemote() && !SOptionPane.showConfirmDialog("Really kick player?", "Kick", false)) {
return;
}
PlayerPanel.this.lobby.removePlayer(index);
}
});
return closeBtn;
}
private void createAvatar() {
String[] currentPrefs = FModel.getPreferences().getPref(FPref.UI_AVATARS).split(",");
if (index < currentPrefs.length) {
avatarIndex = Integer.parseInt(currentPrefs[index]);
avatarLabel.setIcon(FSkin.getAvatars().get(avatarIndex));
}
else {
setRandomAvatar();
}
avatarLabel.setToolTipText("L-click: Select avatar. R-click: Randomize avatar.");
avatarLabel.addFocusListener(avatarFocusListener);
avatarLabel.addMouseListener(avatarMouseListener);
}
/** Applies a random avatar, avoiding avatars already used.
* @param playerIndex */
public void setRandomAvatar() {
int random = 0;
List<Integer> usedAvatars = lobby.getUsedAvatars();
do {
random = MyRandom.getRandom().nextInt(FSkin.getAvatars().size());
} while (usedAvatars.contains(random));
setAvatar(random);
}
public void setAvatar(int newAvatarIndex) {
avatarIndex = newAvatarIndex;
SkinImage icon = FSkin.getAvatars().get(newAvatarIndex);
avatarLabel.setIcon(icon);
avatarLabel.repaintSelf();
}
private final FSkin.LineSkinBorder focusedBorder = new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_BORDERS).alphaColor(255), 3);
private final FSkin.LineSkinBorder defaultBorder = new FSkin.LineSkinBorder(FSkin.getColor(FSkin.Colors.CLR_THEME).alphaColor(200), 2);
public void setFocused(boolean focused) {
avatarLabel.setBorder(focused ? focusedBorder : defaultBorder);
avatarLabel.setHoverable(focused);
}
public int getAvatarIndex() {
return avatarIndex;
}
public void setPlayerName(String string) {
txtPlayerName.setText(string);
}
public String getPlayerName() {
return txtPlayerName.getText();
}
}

View File

@@ -17,17 +17,43 @@
*/
package forge.screens.home;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import net.miginfocom.swing.MigLayout;
import forge.Singletons;
import forge.assets.FSkinProp;
import forge.gui.framework.*;
import forge.gui.framework.EDocID;
import forge.gui.framework.FScreen;
import forge.gui.framework.ICDoc;
import forge.gui.framework.ILocalRepaint;
import forge.gui.framework.IVTopLevelUI;
import forge.model.FModel;
import forge.properties.ForgePreferences.FPref;
import forge.properties.ForgeConstants;
import forge.properties.ForgePreferences.FPref;
import forge.screens.home.gauntlet.VSubmenuGauntletBuild;
import forge.screens.home.gauntlet.VSubmenuGauntletContests;
import forge.screens.home.gauntlet.VSubmenuGauntletLoad;
import forge.screens.home.gauntlet.VSubmenuGauntletQuick;
import forge.screens.home.quest.*;
import forge.screens.home.online.VSubmenuOnlineLobby;
import forge.screens.home.quest.VSubmenuChallenges;
import forge.screens.home.quest.VSubmenuDuels;
import forge.screens.home.quest.VSubmenuQuestData;
import forge.screens.home.quest.VSubmenuQuestDecks;
import forge.screens.home.quest.VSubmenuQuestDraft;
import forge.screens.home.quest.VSubmenuQuestPrefs;
import forge.screens.home.sanctioned.VSubmenuConstructed;
import forge.screens.home.sanctioned.VSubmenuDraft;
import forge.screens.home.sanctioned.VSubmenuSealed;
@@ -42,13 +68,6 @@ import forge.toolbox.FSkin;
import forge.toolbox.FSkin.SkinColor;
import forge.toolbox.FSkin.SkinnedPanel;
import forge.view.FView;
import net.miginfocom.swing.MigLayout;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;
/**
* Top level view class for home UI drag layout.<br>

View File

@@ -0,0 +1,792 @@
package forge.screens.home;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import net.miginfocom.swing.MigLayout;
import org.apache.commons.lang3.StringUtils;
import forge.UiCommand;
import forge.deck.DeckProxy;
import forge.deck.DeckType;
import forge.deckchooser.DecksComboBoxEvent;
import forge.deckchooser.FDeckChooser;
import forge.deckchooser.IDecksComboBoxListener;
import forge.game.GameType;
import forge.game.card.CardView;
import forge.gui.CardDetailPanel;
import forge.item.PaperCard;
import forge.model.FModel;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
import forge.toolbox.FCheckBox;
import forge.toolbox.FLabel;
import forge.toolbox.FList;
import forge.toolbox.FOptionPane;
import forge.toolbox.FPanel;
import forge.toolbox.FScrollPane;
import forge.toolbox.FScrollPanel;
import forge.toolbox.FSkin;
import forge.toolbox.FSkin.SkinImage;
import forge.toolbox.FTextField;
import forge.util.Lang;
import forge.util.NameGenerator;
/**
* Lobby view. View of a number of players at the deck selection stage.
*
* <br><br><i>(V at beginning of class name denotes a view class.)</i>
*/
public class VLobby {
static final int MAX_PLAYERS = 8;
private static final ForgePreferences prefs = FModel.getPreferences();
// General variables
private final boolean allowRemote;
private final LblHeader lblTitle = new LblHeader("Sanctioned Format: Constructed");
private int activePlayersNum = 2;
private int playerWithFocus = 0; // index of the player that currently has focus
private PlayerPanel playerPanelWithFocus;
private GameType currentGameMode = GameType.Constructed;
private List<Integer> teams = new ArrayList<Integer>(MAX_PLAYERS);
private List<Integer> archenemyTeams = new ArrayList<Integer>(MAX_PLAYERS);
private final StartButton btnStart = new StartButton();
private final JPanel pnlStart = new JPanel(new MigLayout("insets 0, gap 0, wrap 2"));
private final JPanel constructedFrame = new JPanel(new MigLayout("insets 0, gap 0, wrap 2")); // Main content frame
// Variants frame and variables
private final Set<GameType> appliedVariants = new TreeSet<GameType>();
private final FPanel variantsPanel = new FPanel(new MigLayout("insets 10, gapx 10"));
private final VariantCheckBox vntVanguard = new VariantCheckBox(GameType.Vanguard);
private final VariantCheckBox vntMomirBasic = new VariantCheckBox(GameType.MomirBasic);
private final VariantCheckBox vntCommander = new VariantCheckBox(GameType.Commander);
private final VariantCheckBox vntTinyLeaders = new VariantCheckBox(GameType.TinyLeaders);
private final VariantCheckBox vntPlanechase = new VariantCheckBox(GameType.Planechase);
private final VariantCheckBox vntArchenemy = new VariantCheckBox(GameType.Archenemy);
private final VariantCheckBox vntArchenemyRumble = new VariantCheckBox(GameType.ArchenemyRumble);
// Player frame elements
private final JPanel playersFrame = new JPanel(new MigLayout("insets 0, gap 0 5, wrap, hidemode 3"));
private final FScrollPanel playersScroll = new FScrollPanel(new MigLayout("insets 0, gap 0, wrap, hidemode 3"), true);
private final List<PlayerPanel> playerPanels = new ArrayList<PlayerPanel>(MAX_PLAYERS);
private final FLabel addPlayerBtn = new FLabel.ButtonBuilder().fontSize(14).text("Add a Player").build();
// Deck frame elements
private final JPanel decksFrame = new JPanel(new MigLayout("insets 0, gap 0, wrap, hidemode 3"));
private final List<FDeckChooser> deckChoosers = new ArrayList<FDeckChooser>(8);
private final FCheckBox cbSingletons = new FCheckBox("Singleton Mode");
private final FCheckBox cbArtifacts = new FCheckBox("Remove Artifacts");
// Variants
private final List<FList<Object>> schemeDeckLists = new ArrayList<FList<Object>>();
private final List<FPanel> schemeDeckPanels = new ArrayList<FPanel>(MAX_PLAYERS);
private int lastArchenemy = 0;
private final List<FList<Object>> commanderDeckLists = new ArrayList<FList<Object>>();
private final List<FPanel> commanderDeckPanels = new ArrayList<FPanel>(MAX_PLAYERS);
private final List<FList<Object>> planarDeckLists = new ArrayList<FList<Object>>();
private final List<FPanel> planarDeckPanels = new ArrayList<FPanel>(MAX_PLAYERS);
private final List<FList<Object>> vgdAvatarLists = new ArrayList<FList<Object>>();
private final List<FPanel> vgdPanels = new ArrayList<FPanel>(MAX_PLAYERS);
private final List<CardDetailPanel> vgdAvatarDetails = new ArrayList<CardDetailPanel>();
private final List<PaperCard> vgdAllAvatars = new ArrayList<PaperCard>();
private final List<PaperCard> vgdAllAiAvatars = new ArrayList<PaperCard>();
private final List<PaperCard> nonRandomHumanAvatars = new ArrayList<PaperCard>();
private final List<PaperCard> nonRandomAiAvatars = new ArrayList<PaperCard>();
private final Vector<Object> humanListData = new Vector<Object>();
private final Vector<Object> aiListData = new Vector<Object>();
// CTR
public VLobby(final boolean allowRemote) {
this.allowRemote = allowRemote;
lblTitle.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));
////////////////////////////////////////////////////////
//////////////////// Variants Panel ////////////////////
variantsPanel.setOpaque(false);
variantsPanel.add(newLabel("Variants:"));
variantsPanel.add(vntVanguard);
variantsPanel.add(vntMomirBasic);
variantsPanel.add(vntCommander);
variantsPanel.add(vntTinyLeaders);
variantsPanel.add(vntPlanechase);
variantsPanel.add(vntArchenemy);
variantsPanel.add(vntArchenemyRumble);
constructedFrame.add(new FScrollPane(variantsPanel, false, true,
ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED),
"w 100%, h 45px!, gapbottom 10px, spanx 2, wrap");
////////////////////////////////////////////////////////
///////////////////// Player Panel /////////////////////
// Construct individual player panels
String constraints = "pushx, growx, wrap, hidemode 3";
for (int i = 0; i < MAX_PLAYERS; i++) {
teams.add(i + 1);
archenemyTeams.add(i == 0 ? 1 : 2);
final PlayerPanel player = new PlayerPanel(this, i, allowRemote);
playerPanels.add(player);
// Populate players panel
player.setVisible(i < activePlayersNum);
playersScroll.add(player, constraints);
if (i == 0) {
constraints += ", gaptop 5px";
}
}
playerPanelWithFocus = playerPanels.get(0);
playerPanelWithFocus.setFocused(true);
playersFrame.setOpaque(false);
playersFrame.add(playersScroll, "w 100%, h 100%-35px");
addPlayerBtn.setFocusable(true);
addPlayerBtn.setCommand(new Runnable() {
@Override
public void run() {
addPlayer();
}
});
playersFrame.add(addPlayerBtn, "height 30px!, growx, pushx");
constructedFrame.add(playersFrame, "gapright 10px, w 50%-5px, growy, pushy");
////////////////////////////////////////////////////////
////////////////////// Deck Panel //////////////////////
for (int i = 0; i < MAX_PLAYERS; i++) {
buildDeckPanel(i);
}
constructedFrame.add(decksFrame, "w 50%-5px, growy, pushy");
constructedFrame.setOpaque(false);
decksFrame.setOpaque(false);
// Start Button
pnlStart.setOpaque(false);
pnlStart.add(btnStart, "align center");
}
public void populate() {
for (final FDeckChooser fdc : deckChoosers) {
fdc.populate();
fdc.getDecksComboBox().addListener(new IDecksComboBoxListener() {
@Override
public void deckTypeSelected(DecksComboBoxEvent ev) {
playerPanelWithFocus.focusOnAvatar();
}
});
}
populateDeckPanel(GameType.Constructed);
populateVanguardLists();
}
public void addPlayerInFreeSlot(final String name) {
if (activePlayersNum >= MAX_PLAYERS) {
return;
}
for (final PlayerPanel pp : getPlayerPanels()) {
if (pp.isVisible() && pp.isOpen()) {
addPlayer(pp.getIndex());
pp.setPlayerName(name);
pp.setRemote(true);
return;
}
}
}
private void addPlayer() {
if (activePlayersNum >= MAX_PLAYERS) {
return;
}
int freeIndex = -1;
for (int i = 0; i < MAX_PLAYERS; i++) {
if (!playerPanels.get(i).isVisible()) {
freeIndex = i;
break;
}
}
addPlayer(freeIndex);
}
private void addPlayer(final int slot) {
playerPanels.get(slot).setVisible(true);
activePlayersNum++;
addPlayerBtn.setEnabled(activePlayersNum < MAX_PLAYERS);
playerPanels.get(slot).setVisible(true);
playerPanels.get(slot).focusOnAvatar();
}
void removePlayer(final int playerIndex) {
if (activePlayersNum < playerIndex) {
return;
}
activePlayersNum--;
final FPanel player = playerPanels.get(playerIndex);
player.setVisible(false);
addPlayerBtn.setEnabled(true);
//find closest player still in game and give focus
int min = MAX_PLAYERS;
final List<Integer> participants = getParticipants();
if (!participants.isEmpty()) {
int closest = 2;
for (final int participantIndex : getParticipants()) {
final int diff = Math.abs(playerIndex - participantIndex);
if (diff < min) {
min = diff;
closest = participantIndex;
}
}
changePlayerFocus(closest);
playerPanels.get(closest).focusOnAvatar();
}
}
/** Builds the actual deck panel layouts for each player.
* These are added to a list which can be referenced to populate the deck panel appropriately. */
@SuppressWarnings("serial")
private void buildDeckPanel(final int playerIndex) {
String sectionConstraints = "insets 0, gap 0, wrap";
String labelConstraints = "gaptop 10px, gapbottom 5px";
// Main deck
final FDeckChooser mainChooser = new FDeckChooser(null, isPlayerAI(playerIndex));
mainChooser.initialize();
mainChooser.getLstDecks().setSelectCommand(new UiCommand() {
@Override
public void run() {
VLobby.this.onDeckClicked(playerIndex, mainChooser.getSelectedDeckType(), mainChooser.getLstDecks().getSelectedItems());
}
});
deckChoosers.add(mainChooser);
// Scheme deck list
FPanel schemeDeckPanel = new FPanel();
schemeDeckPanel.setBorderToggle(false);
schemeDeckPanel.setLayout(new MigLayout(sectionConstraints));
schemeDeckPanel.add(new FLabel.Builder().text("Select Scheme deck:").build(), labelConstraints);
FList<Object> schemeDeckList = new FList<Object>();
schemeDeckList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
FScrollPane scrSchemes = new FScrollPane(schemeDeckList, true,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
schemeDeckPanel.add(scrSchemes, "grow, push");
schemeDeckLists.add(schemeDeckList);
schemeDeckPanels.add(schemeDeckPanel);
// Commander deck list
FPanel commanderDeckPanel = new FPanel();
commanderDeckPanel.setBorderToggle(false);
commanderDeckPanel.setLayout(new MigLayout(sectionConstraints));
commanderDeckPanel.add(new FLabel.Builder().text("Select Commander deck:").build(), labelConstraints);
FList<Object> commanderDeckList = new FList<Object>();
commanderDeckList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
FScrollPane scrCommander = new FScrollPane(commanderDeckList, true,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
commanderDeckPanel.add(scrCommander, "grow, push");
commanderDeckLists.add(commanderDeckList);
commanderDeckPanels.add(commanderDeckPanel);
// Planar deck list
FPanel planarDeckPanel = new FPanel();
planarDeckPanel.setBorderToggle(false);
planarDeckPanel.setLayout(new MigLayout(sectionConstraints));
planarDeckPanel.add(new FLabel.Builder().text("Select Planar deck:").build(), labelConstraints);
FList<Object> planarDeckList = new FList<Object>();
planarDeckList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
FScrollPane scrPlanes = new FScrollPane(planarDeckList, true,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
planarDeckPanel.add(scrPlanes, "grow, push");
planarDeckLists.add(planarDeckList);
planarDeckPanels.add(planarDeckPanel);
// Vanguard avatar list
FPanel vgdDeckPanel = new FPanel();
vgdDeckPanel.setBorderToggle(false);
FList<Object> vgdAvatarList = new FList<Object>();
vgdAvatarList.setListData(isPlayerAI(playerIndex) ? aiListData : humanListData);
vgdAvatarList.setSelectedIndex(0);
vgdAvatarList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
vgdAvatarList.addListSelectionListener(vgdLSListener);
FScrollPane scrAvatars = new FScrollPane(vgdAvatarList, true,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
CardDetailPanel vgdDetail = new CardDetailPanel();
vgdAvatarDetails.add(vgdDetail);
vgdDeckPanel.setLayout(new MigLayout(sectionConstraints));
vgdDeckPanel.add(new FLabel.Builder().text("Select a Vanguard avatar:").build(), labelConstraints);
vgdDeckPanel.add(scrAvatars, "grow, push");
vgdDeckPanel.add(vgdDetail, "h 200px, pushx, growx, hidemode 3");
vgdAvatarLists.add(vgdAvatarList);
vgdPanels.add(vgdDeckPanel);
}
protected void onDeckClicked(int iPlayer, DeckType type, Collection<DeckProxy> selectedDecks) {
String text = type.toString() + ": " + Lang.joinHomogenous(selectedDecks, DeckProxy.FN_GET_NAME);
playerPanels.get(iPlayer).setDeckSelectorButtonText(text);
}
/** Populates the deck panel with the focused player's deck choices. */
private void populateDeckPanel(final GameType forGameType) {
decksFrame.removeAll();
if (playerPanelWithFocus.isOpen() || playerPanelWithFocus.isRemote()) {
return;
}
if (GameType.Constructed == forGameType) {
decksFrame.add(deckChoosers.get(playerWithFocus), "grow, push");
if (deckChoosers.get(playerWithFocus).getSelectedDeckType().toString().contains("Random")) {
final String strCheckboxConstraints = "h 30px!, gap 0 20px 0 0";
decksFrame.add(cbSingletons, strCheckboxConstraints);
decksFrame.add(cbArtifacts, strCheckboxConstraints);
}
} else if (GameType.Archenemy == forGameType || GameType.ArchenemyRumble == forGameType) {
if (isPlayerArchenemy(playerWithFocus)) {
decksFrame.add(schemeDeckPanels.get(playerWithFocus), "grow, push");
} else {
populateDeckPanel(GameType.Constructed);
}
} else if (GameType.Commander == forGameType || GameType.TinyLeaders == forGameType) {
decksFrame.add(commanderDeckPanels.get(playerWithFocus), "grow, push");
} else if (GameType.Planechase == forGameType) {
decksFrame.add(planarDeckPanels.get(playerWithFocus), "grow, push");
} else if (GameType.Vanguard == forGameType) {
updateVanguardList(playerWithFocus);
decksFrame.add(vgdPanels.get(playerWithFocus), "grow, push");
}
refreshPanels(false, true);
}
/** @return {@link javax.swing.JButton} */
public JButton getBtnStart() {
return this.btnStart;
}
public LblHeader getLblTitle() { return lblTitle; }
public JPanel getConstructedFrame() { return constructedFrame; }
public JPanel getPanelStart() { return pnlStart; }
public List<FDeckChooser> getDeckChoosers() { return Collections.unmodifiableList(deckChoosers); }
/** Gets the random deck checkbox for Singletons. */
public FCheckBox getCbSingletons() { return cbSingletons; }
/** Gets the random deck checkbox for Artifacts. */
public FCheckBox getCbArtifacts() { return cbArtifacts; }
public FCheckBox getVntArchenemy() { return vntArchenemy; }
public FCheckBox getVntArchenemyRumble() { return vntArchenemyRumble; }
public FCheckBox getVntCommander() { return vntCommander; }
public FCheckBox getVntMomirBasic() { return vntMomirBasic; }
public FCheckBox getVntPlanechase() { return vntPlanechase; }
public FCheckBox getVntTinyLeaders() { return vntTinyLeaders; }
public FCheckBox getVntVanguard() { return vntVanguard; }
public int getLastArchenemy() { return lastArchenemy; }
public void setLastArchenemy(final int archenemy) { lastArchenemy = archenemy; }
public final List<PlayerPanel> getPlayerPanels() {
return playerPanels;
}
public final PlayerPanel getPlayerPanelWithFocus() {
return playerPanelWithFocus;
}
public final FDeckChooser getDeckChooser(int playernum) {
return deckChoosers.get(playernum);
}
public List<Integer> getTeams() { return Collections.unmodifiableList(teams); }
public List<Integer> getArchenemyTeams() { return Collections.unmodifiableList(archenemyTeams); }
public GameType getCurrentGameMode() { return currentGameMode; }
public void setCurrentGameMode(final GameType mode) { currentGameMode = mode; }
public boolean isPlayerAI(int playernum) {
return playerPanels.get(playernum).isAi();
}
public Map<String, String> getAiOptions(int playernum) {
if (playerPanels.get(playernum).isSimulatedAi()) {
Map<String, String> options = new HashMap<String, String>();
options.put("UseSimulation", "True");
return options;
}
return null;
}
public int getNumPlayers() {
return activePlayersNum;
}
public final List<Integer> getParticipants() {
final List<Integer> participants = new ArrayList<Integer>(activePlayersNum);
for (final PlayerPanel panel : playerPanels) {
if (panel.isVisible()) {
participants.add(playerPanels.indexOf(panel));
}
}
return participants;
}
/** Revalidates the player and deck sections. Necessary after adding or hiding any panels. */
private void refreshPanels(boolean refreshPlayerFrame, boolean refreshDeckFrame) {
if (refreshPlayerFrame) {
playersScroll.validate();
playersScroll.repaint();
}
if (refreshDeckFrame) {
decksFrame.validate();
decksFrame.repaint();
}
}
public void changePlayerFocus(int newFocusOwner) {
changePlayerFocus(newFocusOwner, appliedVariants.contains(currentGameMode) ? currentGameMode : GameType.Constructed);
}
void changePlayerFocus(int newFocusOwner, GameType gType) {
playerPanelWithFocus.setFocused(false);
playerWithFocus = newFocusOwner;
playerPanelWithFocus = playerPanels.get(playerWithFocus);
playerPanelWithFocus.setFocused(true);
playersScroll.getViewport().scrollRectToVisible(playerPanelWithFocus.getBounds());
populateDeckPanel(gType);
refreshPanels(true, true);
}
/** Saves avatar prefs for players one and two. */
void updateAvatarPrefs() {
int pOneIndex = playerPanels.get(0).getAvatarIndex();
int pTwoIndex = playerPanels.get(1).getAvatarIndex();
prefs.setPref(FPref.UI_AVATARS, pOneIndex + "," + pTwoIndex);
prefs.save();
}
/** Updates the avatars from preferences on update. */
public void updatePlayersFromPrefs() {
ForgePreferences prefs = FModel.getPreferences();
// Avatar
String[] avatarPrefs = prefs.getPref(FPref.UI_AVATARS).split(",");
for (int i = 0; i < avatarPrefs.length; i++) {
int avatarIndex = Integer.parseInt(avatarPrefs[i]);
playerPanels.get(i).setAvatar(avatarIndex);
}
// Name
String prefName = prefs.getPref(FPref.PLAYER_NAME);
playerPanels.get(0).setPlayerName(StringUtils.isBlank(prefName) ? "Human" : prefName);
}
/** Adds a pre-styled FLabel component with the specified title. */
FLabel newLabel(String title) {
return new FLabel.Builder().text(title).fontSize(14).fontStyle(Font.ITALIC).build();
}
List<Integer> getUsedAvatars() {
List<Integer> usedAvatars = Arrays.asList(-1,-1,-1,-1,-1,-1,-1,-1);
int i = 0;
for (PlayerPanel pp : playerPanels) {
usedAvatars.set(i++, pp.getAvatarIndex());
}
return usedAvatars;
}
final String getNewName() {
final String title = "Get new random name";
final String message = "What type of name do you want to generate?";
final SkinImage icon = FOptionPane.QUESTION_ICON;
final String[] genderOptions = new String[]{ "Male", "Female", "Any" };
final String[] typeOptions = new String[]{ "Fantasy", "Generic", "Any" };
final int genderIndex = FOptionPane.showOptionDialog(message, title, icon, genderOptions, 2);
if (genderIndex < 0) {
return null;
}
final int typeIndex = FOptionPane.showOptionDialog(message, title, icon, typeOptions, 2);
if (typeIndex < 0) {
return null;
}
final String gender = genderOptions[genderIndex];
final String type = typeOptions[typeIndex];
String confirmMsg, newName;
List<String> usedNames = getPlayerNames();
do {
newName = NameGenerator.getRandomName(gender, type, usedNames);
confirmMsg = "Would you like to use the name \"" + newName + "\", or try again?";
} while (!FOptionPane.showConfirmDialog(confirmMsg, title, "Use this name", "Try again", true));
return newName;
}
List<String> getPlayerNames() {
List<String> names = new ArrayList<String>();
for (PlayerPanel pp : playerPanels) {
names.add(pp.getPlayerName());
}
return names;
}
public String getPlayerName(int i) {
return playerPanels.get(i).getPlayerName();
}
public int getPlayerAvatar(int i) {
return playerPanels.get(i).getAvatarIndex();
}
public boolean isEnoughTeams() {
int lastTeam = -1;
final List<Integer> teamList = appliedVariants.contains(GameType.Archenemy) ? archenemyTeams : teams;
for (final int i : getParticipants()) {
if (lastTeam == -1) {
lastTeam = teamList.get(i);
} else if (lastTeam != teamList.get(i)) {
return true;
}
}
return false;
}
/////////////////////////////////////////////
//========== Various listeners in build order
@SuppressWarnings("serial") private class VariantCheckBox extends FCheckBox {
private final GameType variantType;
private VariantCheckBox(GameType variantType0) {
super(variantType0.toString());
variantType = variantType0;
setToolTipText(variantType.getDescription());
addItemListener(new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
appliedVariants.add(variantType);
currentGameMode = variantType;
//ensure other necessary variants are unchecked
switch (variantType) {
case Archenemy:
vntArchenemyRumble.setSelected(false);
break;
case ArchenemyRumble:
vntArchenemy.setSelected(false);
break;
case Commander:
vntTinyLeaders.setSelected(false);
vntMomirBasic.setSelected(false);
break;
case TinyLeaders:
vntCommander.setSelected(false);
vntMomirBasic.setSelected(false);
break;
case Vanguard:
vntMomirBasic.setSelected(false);
break;
case MomirBasic:
vntCommander.setSelected(false);
vntVanguard.setSelected(false);
break;
default:
break;
}
}
else {
appliedVariants.remove(variantType);
if (currentGameMode == variantType) {
currentGameMode = GameType.Constructed;
}
}
for (PlayerPanel pp : playerPanels) {
pp.toggleIsPlayerArchenemy();
}
changePlayerFocus(playerWithFocus, currentGameMode);
}
});
}
}
ActionListener nameListener = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
FTextField nField = (FTextField)e.getSource();
nField.transferFocus();
}
};
/** This listener will look for a vanguard avatar being selected in the lists
/ and update the corresponding detail panel. */
private ListSelectionListener vgdLSListener = new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
int index = vgdAvatarLists.indexOf(e.getSource());
Object obj = vgdAvatarLists.get(index).getSelectedValue();
PlayerPanel pp = playerPanels.get(index);
CardDetailPanel cdp = vgdAvatarDetails.get(index);
if (obj instanceof PaperCard) {
pp.setVanguardButtonText(((PaperCard) obj).getName());
cdp.setCard(CardView.getCardForUi((PaperCard) obj));
cdp.setVisible(true);
refreshPanels(false, true);
}
else {
pp.setVanguardButtonText((String) obj);
cdp.setVisible(false);
}
}
};
/////////////////////////////////////
//========== METHODS FOR VARIANTS
public Set<GameType> getAppliedVariants() {
return Collections.unmodifiableSet(appliedVariants);
}
public int getTeam(final int playerIndex) {
return appliedVariants.contains(GameType.Archenemy) ? archenemyTeams.get(playerIndex) : teams.get(playerIndex);
}
/** Gets the list of planar deck lists. */
public List<FList<Object>> getPlanarDeckLists() {
return planarDeckLists;
}
/** Gets the list of commander deck lists. */
public List<FList<Object>> getCommanderDeckLists() {
return commanderDeckLists;
}
/** Gets the list of scheme deck lists. */
public List<FList<Object>> getSchemeDeckLists() {
return schemeDeckLists;
}
public boolean isPlayerArchenemy(final int playernum) {
return playerPanels.get(playernum).isArchenemy();
}
/** Gets the list of Vanguard avatar lists. */
public List<FList<Object>> getVanguardLists() {
return vgdAvatarLists;
}
/** Return all the Vanguard avatars. */
public Iterable<PaperCard> getAllAvatars() {
if (vgdAllAvatars.isEmpty()) {
for (PaperCard c : FModel.getMagicDb().getVariantCards().getAllCards()) {
if (c.getRules().getType().isVanguard()) {
vgdAllAvatars.add(c);
}
}
}
return vgdAllAvatars;
}
/** Return the Vanguard avatars not flagged RemAIDeck. */
public List<PaperCard> getAllAiAvatars() {
return vgdAllAiAvatars;
}
/** Return the Vanguard avatars not flagged RemRandomDeck. */
public List<PaperCard> getNonRandomHumanAvatars() {
return nonRandomHumanAvatars;
}
/** Return the Vanguard avatars not flagged RemAIDeck or RemRandomDeck. */
public List<PaperCard> getNonRandomAiAvatars() {
return nonRandomAiAvatars;
}
/** Populate vanguard lists. */
private void populateVanguardLists() {
humanListData.add("Use deck's default avatar (random if unavailable)");
humanListData.add("Random");
aiListData.add("Use deck's default avatar (random if unavailable)");
aiListData.add("Random");
for (PaperCard cp : getAllAvatars()) {
humanListData.add(cp);
if (!cp.getRules().getAiHints().getRemRandomDecks()) {
nonRandomHumanAvatars.add(cp);
}
if (!cp.getRules().getAiHints().getRemAIDecks()) {
aiListData.add(cp);
vgdAllAiAvatars.add(cp);
if (!cp.getRules().getAiHints().getRemRandomDecks()) {
nonRandomAiAvatars.add(cp);
}
}
}
}
/** update vanguard list. */
public void updateVanguardList(int playerIndex) {
FList<Object> vgdList = getVanguardLists().get(playerIndex);
Object lastSelection = vgdList.getSelectedValue();
vgdList.setListData(isPlayerAI(playerIndex) ? aiListData : humanListData);
if (null != lastSelection) {
vgdList.setSelectedValue(lastSelection, true);
}
if (-1 == vgdList.getSelectedIndex()) {
vgdList.setSelectedIndex(0);
}
}
}

View File

@@ -0,0 +1,41 @@
package forge.screens.home.online;
import forge.UiCommand;
import forge.gui.framework.ICDoc;
import forge.screens.home.CLobby;
public enum COnlineLobby implements ICDoc {
SINGLETON_INSTANCE;
private final VOnlineLobby view = VOnlineLobby.SINGLETON_INSTANCE;
private final CLobby lobby = new CLobby(view.getLobby());
@Override
public void register() {
}
/* (non-Javadoc)
* @see forge.gui.home.ICSubmenu#initialize()
*/
@Override
public void update() {
lobby.update();
}
/* (non-Javadoc)
* @see forge.gui.home.ICSubmenu#initialize()
*/
@Override
public void initialize() {
lobby.initialize();
}
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#getCommandOnSelect()
*/
@Override
public UiCommand getCommandOnSelect() {
return null;
}
}

View File

@@ -1,48 +1,93 @@
package forge.screens.home.online;
import forge.UiCommand;
import forge.gui.framework.ICDoc;
import forge.menus.IMenuProvider;
import forge.menus.MenuUtil;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JMenu;
import forge.GuiBase;
import forge.Singletons;
import forge.UiCommand;
import forge.game.GameRules;
import forge.game.GameType;
import forge.gui.FNetOverlay;
import forge.gui.framework.FScreen;
import forge.gui.framework.ICDoc;
import forge.menus.IMenuProvider;
import forge.menus.MenuUtil;
import forge.model.FModel;
import forge.net.FGameClient;
import forge.net.FServerManager;
import forge.net.game.client.ILobbyListener;
import forge.net.game.server.RemoteClient;
import forge.properties.ForgePreferences.FPref;
import forge.screens.home.sanctioned.ConstructedGameMenu;
public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
SINGLETON_INSTANCE;
//private final VSubmenuOnlineLobby view = VSubmenuOnlineLobby.SINGLETON_INSTANCE;
@Override
public void update() {
MenuUtil.setMenuProvider(this);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final void host(final int portNumber) {
FServerManager.getInstance().startServer(portNumber);
FServerManager.getInstance().registerLobbyListener(new ILobbyListener() {
@Override public final void logout(final RemoteClient client) {
}
@Override public final void login(final RemoteClient client) {
VOnlineLobby.SINGLETON_INSTANCE.getLobby().addPlayerInFreeSlot(client.getUsername());
}
@Override public final void message(final String source, final String message) {
FNetOverlay.SINGLETON_INSTANCE.addMessage(source, message);
}
});
FServerManager.getInstance().hostGame(new GameRules(GameType.Constructed));
Singletons.getControl().setCurrentScreen(FScreen.ONLINE_LOBBY);
FNetOverlay.SINGLETON_INSTANCE.showUp("Hosting game");
}
final void join(final String hostname, final int port) {
final FGameClient client = new FGameClient(FModel.getPreferences().getPref(FPref.PLAYER_NAME), "0", GuiBase.getInterface().getNewGuiGame());
FNetOverlay.SINGLETON_INSTANCE.setGameClient(client);
client.connect(hostname, port);
Singletons.getControl().setCurrentScreen(FScreen.ONLINE_LOBBY);
FNetOverlay.SINGLETON_INSTANCE.showUp(String.format("Connected to %s:%s", hostname, port));
}
@Override
public void register() {
}
/* (non-Javadoc)
* @see forge.gui.home.ICSubmenu#initialize()
*/
@Override
public void update() {
MenuUtil.setMenuProvider(this);
}
/* (non-Javadoc)
* @see forge.gui.home.ICSubmenu#initialize()
*/
@Override
public void initialize() {
}
/* (non-Javadoc)
* @see forge.gui.framework.ICDoc#getCommandOnSelect()
*/
@Override
public UiCommand getCommandOnSelect() {
return null;
}
/* (non-Javadoc)
* @see forge.gui.menubar.IMenuProvider#getMenus()
*/
@Override
public List<JMenu> getMenus() {
List<JMenu> menus = new ArrayList<JMenu>();
menus.add(ConstructedGameMenu.getMenu());
return menus;
}
}

View File

@@ -0,0 +1,105 @@
package forge.screens.home.online;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import forge.deckchooser.DecksComboBoxEvent;
import forge.deckchooser.FDeckChooser;
import forge.deckchooser.IDecksComboBoxListener;
import forge.gui.framework.DragCell;
import forge.gui.framework.DragTab;
import forge.gui.framework.EDocID;
import forge.gui.framework.FScreen;
import forge.gui.framework.IVDoc;
import forge.gui.framework.IVTopLevelUI;
import forge.screens.home.VLobby;
import forge.toolbox.FPanel;
import forge.util.gui.SOptionPane;
import forge.view.FView;
public enum VOnlineLobby implements IVDoc<COnlineLobby>, IVTopLevelUI {
SINGLETON_INSTANCE;
private DragCell parentCell;
private final DragTab tab = new DragTab("Lobby");
// General variables
private final VLobby lobby;
private VOnlineLobby() {
this.lobby = new VLobby(true);
}
VLobby getLobby() {
return lobby;
}
@Override
public void populate() {
final JPanel outerContainer = FView.SINGLETON_INSTANCE.getPnlInsets();
outerContainer.removeAll();
final FPanel container = new FPanel(new MigLayout("insets 0, gap 0, wrap 1, ax right"));
outerContainer.add(container);
lobby.getLblTitle().setText("Online Multiplayer: Lobby");
container.add(lobby.getLblTitle(), "w 80%, h 40px!, gap 0 0 15px 15px, span 2, al right, pushx");
for (final FDeckChooser fdc : lobby.getDeckChoosers()) {
fdc.populate();
fdc.getDecksComboBox().addListener(new IDecksComboBoxListener() {
@Override public final void deckTypeSelected(final DecksComboBoxEvent ev) {
lobby.getPlayerPanelWithFocus().focusOnAvatar();
}
});
}
container.add(lobby.getConstructedFrame(), "gap 20px 20px 20px 0px, push, grow");
container.add(lobby.getPanelStart(), "gap 0 0 3.5%! 3.5%!, ax center");
if (container.isShowing()) {
container.validate();
container.repaint();
}
lobby.changePlayerFocus(0);
}
@Override
public EDocID getDocumentID() {
return EDocID.ONLINE_LOBBY;
}
@Override
public DragTab getTabLabel() {
return tab;
}
@Override
public COnlineLobby getLayoutControl() {
return COnlineLobby.SINGLETON_INSTANCE;
}
@Override
public void setParentCell(final DragCell cell0) {
parentCell = cell0;
}
@Override
public DragCell getParentCell() {
return parentCell;
}
@Override
public void instantiate() {
}
@Override
public boolean onSwitching(final FScreen fromScreen, final FScreen toScreen) {
return true;
}
@Override
public boolean onClosing(final FScreen screen) {
return SOptionPane.showConfirmDialog("Leave lobby?", "Leave");
}
}

View File

@@ -1,65 +1,85 @@
package forge.screens.home.online;
import javax.swing.JButton;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import forge.gui.framework.DragCell;
import forge.gui.framework.DragTab;
import forge.gui.framework.EDocID;
import forge.properties.ForgeConstants;
import forge.screens.home.EMenuGroup;
import forge.screens.home.IVSubmenu;
import forge.screens.home.LblHeader;
import forge.screens.home.StartButton;
import forge.screens.home.VHomeUI;
import forge.toolbox.FSkin;
import forge.toolbox.FButton;
import forge.toolbox.FLabel;
import forge.toolbox.FPanel;
import forge.toolbox.FTextField;
public enum VSubmenuOnlineLobby implements IVSubmenu<CSubmenuOnlineLobby> {
SINGLETON_INSTANCE;
private DragCell parentCell;
private final DragTab tab = new DragTab("Lobby");
// General variables
private final LblHeader lblTitle = new LblHeader("Online Multiplayer: Lobby");
private final StartButton btnStart = new StartButton();
private final JPanel pnlStart = new JPanel(new MigLayout("insets 0, gap 0, wrap 2"));
private final JPanel frame = new JPanel(new MigLayout("insets 0, gap 0, wrap 2")); // Main content frame
private final DragTab tab = new DragTab("Network Games");
private VSubmenuOnlineLobby() {
lblTitle.setBackground(FSkin.getColor(FSkin.Colors.CLR_THEME2));
frame.setOpaque(false);
pnlStart.setOpaque(false);
pnlStart.add(btnStart, "align center");
}
@Override
public void populate() {
JPanel container = VHomeUI.SINGLETON_INSTANCE.getPnlDisplay();
final JPanel container = VHomeUI.SINGLETON_INSTANCE.getPnlDisplay();
container.removeAll();
container.setLayout(new MigLayout("insets 0, gap 0, wrap 1, ax right"));
container.add(lblTitle, "w 80%, h 40px!, gap 0 0 15px 15px, span 2, al right, pushx");
container.setLayout(new MigLayout("fill", "[grow][grow]", "[grow]"));
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(frame, "gap 20px 20px 20px 0px, push, grow");
VHomeUI.SINGLETON_INSTANCE.getPnlDisplay().add(pnlStart, "gap 0 0 3.5%! 3.5%!, ax center");
final FPanel pnlHost = new FPanel(new MigLayout("insets 5px 10% 5px 10%, wrap 2", "[grow,l]10[grow,r]", "[grow,c][grow,c]"));
container.add(pnlHost, "west, w 50%!, h 100%!");
if (container.isShowing()) {
container.validate();
container.repaint();
}
}
final FLabel lblServerPort = new FLabel.Builder().text("Server port").build();
pnlHost.add(lblServerPort, "w 100!, h 50!");
public JButton getBtnStart() {
return btnStart;
final FTextField txtServerPort = new FTextField.Builder().text(String.valueOf(ForgeConstants.SERVER_PORT_NUMBER)).build();
txtServerPort.setEditable(false);
pnlHost.add(txtServerPort, "wrap");
final FButton btnHost = new FButton("Host");
btnHost.addActionListener(new ActionListener() {
@Override public final void actionPerformed(final ActionEvent e) {
getLayoutControl().host(Integer.parseInt(txtServerPort.getText()));
}
});
pnlHost.add(btnHost, "span 2, wrap, w 200!, h 50!");
final FPanel pnlJoin = new FPanel(new MigLayout("insets 5px 10% 5px 10%, wrap 2", "[grow,l]10[grow,r]", "[grow,c][grow,c][grow,c]"));
container.add(pnlJoin, "east, w 50%!, h 100%!");
final FLabel lblJoinHost = new FLabel.Builder().text("Hostname").build();
pnlJoin.add(lblJoinHost, "w 100!, h 50!");
final FTextField txtJoinHost = new FTextField.Builder().text("localhost").build();
pnlJoin.add(txtJoinHost, "wrap, w 250!");
final FLabel lblJoinPort = new FLabel.Builder().text("Host port").build();
pnlJoin.add(lblJoinPort, "w 100!, h 50!");
final FTextField txtJoinPort = new FTextField.Builder().text(String.valueOf(ForgeConstants.SERVER_PORT_NUMBER)).build();
txtJoinPort.setEditable(false);
pnlJoin.add(txtJoinPort, "wrap");
final FButton btnJoin = new FButton("Join");
btnJoin.addActionListener(new ActionListener() {
@Override public final void actionPerformed(final ActionEvent e) {
getLayoutControl().join(txtJoinHost.getText(), Integer.parseInt(txtJoinPort.getText()));
}
});
pnlJoin.add(btnJoin, "span 2, w 200!, h 50!");
}
@Override
public EMenuGroup getGroupEnum() {
return null; //EMenuGroup.ONLINE;
return EMenuGroup.ONLINE;
}
@Override
@@ -69,12 +89,12 @@ public enum VSubmenuOnlineLobby implements IVSubmenu<CSubmenuOnlineLobby> {
@Override
public EDocID getItemEnum() {
return EDocID.HOME_LOBBY;
return getDocumentID();
}
@Override
public EDocID getDocumentID() {
return EDocID.HOME_LOBBY;
return EDocID.HOME_NETWORK;
}
@Override

View File

@@ -1,46 +1,15 @@
package forge.screens.home.sanctioned;
import forge.GuiBase;
import forge.LobbyPlayer;
import forge.UiCommand;
import forge.deck.CardPool;
import forge.deck.Deck;
import forge.deck.DeckFormat;
import forge.deck.DeckSection;
import forge.deck.DeckType;
import forge.deck.DeckgenUtil;
import forge.game.GameType;
import forge.game.player.RegisteredPlayer;
import forge.gui.GuiDialog;
import forge.gui.framework.ICDoc;
import forge.interfaces.IGuiGame;
import forge.item.PaperCard;
import forge.match.HostedMatch;
import forge.menus.IMenuProvider;
import forge.menus.MenuUtil;
import forge.model.CardCollections;
import forge.model.FModel;
import forge.player.GamePlayerUtil;
import forge.properties.ForgePreferences;
import forge.properties.ForgePreferences.FPref;
import forge.toolbox.FList;
import forge.toolbox.FOptionPane;
import forge.util.Aggregates;
import forge.util.storage.IStorage;
import javax.swing.*;
import com.beust.jcommander.internal.Maps;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
//import forge.gui.home.variant.VSubmenuVanguard;
import javax.swing.JMenu;
import forge.UiCommand;
import forge.gui.framework.ICDoc;
import forge.menus.IMenuProvider;
import forge.menus.MenuUtil;
import forge.screens.home.CLobby;
/**
* Controls the constructed submenu in the home UI.
@@ -53,6 +22,7 @@ public enum CSubmenuConstructed implements ICDoc, IMenuProvider {
SINGLETON_INSTANCE;
private final VSubmenuConstructed view = VSubmenuConstructed.SINGLETON_INSTANCE;
private final CLobby lobby = new CLobby(view.getLobby());
@Override
public void register() {
@@ -64,85 +34,7 @@ public enum CSubmenuConstructed implements ICDoc, IMenuProvider {
@Override
public void update() {
MenuUtil.setMenuProvider(this);
SwingUtilities.invokeLater(new Runnable() {
@Override public void run() {
final CardCollections cColl = FModel.getDecks();
FList<Object> deckList;
Vector<Object> listData;
Object val;
for (int i = 0; i < 8; i++) {
// Commander: reinit deck list and restore last selections (if any)
deckList = view.getCommanderDeckLists().get(i);
listData = new Vector<Object>();
listData.add("Generate");
if (cColl.getCommander().size() > 0) {
listData.add("Random");
for (Deck comDeck : cColl.getCommander()) {
listData.add(comDeck);
}
}
val = deckList.getSelectedValue();
deckList.setListData(listData);
if (null != val) {
deckList.setSelectedValue(val, true);
}
if (-1 == deckList.getSelectedIndex()) {
deckList.setSelectedIndex(0);
} // End Commander
// Archenemy: reinit deck list and restore last selections (if any)
deckList = view.getSchemeDeckLists().get(i);
listData = new Vector<Object>();
listData.add("Use deck's scheme section (random if unavailable)");
listData.add("Generate");
if (cColl.getScheme().size() > 0) {
listData.add("Random");
for (Deck schemeDeck : cColl.getScheme()) {
listData.add(schemeDeck);
}
}
val = deckList.getSelectedValue();
deckList.setListData(listData);
if (null != val) {
deckList.setSelectedValue(val, true);
}
if (-1 == deckList.getSelectedIndex()) {
deckList.setSelectedIndex(0);
} // End Archenemy
// Planechase: reinit deck lists and restore last selections (if any)
deckList = view.getPlanarDeckLists().get(i);
listData = new Vector<Object>();
listData.add("Use deck's planes section (random if unavailable)");
listData.add("Generate");
if (cColl.getPlane().size() > 0) {
listData.add("Random");
for (Deck planarDeck : cColl.getPlane()) {
listData.add(planarDeck);
}
}
val = deckList.getSelectedValue();
deckList.setListData(listData);
if (null != val) {
deckList.setSelectedValue(val, true);
}
if (-1 == deckList.getSelectedIndex()) {
deckList.setSelectedIndex(0);
} // End Planechase
view.updateVanguardList(i);
}
// General updates when switching back to this view
view.updatePlayersFromPrefs();
view.getBtnStart().requestFocusInWindow();
}
});
lobby.update();
}
/* (non-Javadoc)
@@ -150,248 +42,7 @@ public enum CSubmenuConstructed implements ICDoc, IMenuProvider {
*/
@Override
public void initialize() {
view.getDeckChooser(0).initialize(FPref.CONSTRUCTED_P1_DECK_STATE, DeckType.PRECONSTRUCTED_DECK);
view.getDeckChooser(1).initialize(FPref.CONSTRUCTED_P2_DECK_STATE, DeckType.COLOR_DECK);
view.getDeckChooser(2).initialize(FPref.CONSTRUCTED_P3_DECK_STATE, DeckType.COLOR_DECK);
view.getDeckChooser(3).initialize(FPref.CONSTRUCTED_P4_DECK_STATE, DeckType.COLOR_DECK);
view.getDeckChooser(4).initialize(FPref.CONSTRUCTED_P5_DECK_STATE, DeckType.COLOR_DECK);
view.getDeckChooser(5).initialize(FPref.CONSTRUCTED_P6_DECK_STATE, DeckType.COLOR_DECK);
view.getDeckChooser(6).initialize(FPref.CONSTRUCTED_P7_DECK_STATE, DeckType.COLOR_DECK);
view.getDeckChooser(7).initialize(FPref.CONSTRUCTED_P8_DECK_STATE, DeckType.COLOR_DECK);
// Start button event handling
view.getBtnStart().addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent arg0) {
startGame(view.getAppliedVariants());
}
});
final ForgePreferences prefs = FModel.getPreferences();
// Checkbox event handling
view.getCbSingletons().addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent arg0) {
prefs.setPref(FPref.DECKGEN_SINGLETONS, String.valueOf(view.getCbSingletons().isSelected()));
prefs.save();
}
});
view.getCbArtifacts().addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent arg0) {
prefs.setPref(FPref.DECKGEN_ARTIFACTS, String.valueOf(view.getCbArtifacts().isSelected()));
prefs.save();
}
});
// Pre-select checkboxes
view.getCbSingletons().setSelected(prefs.getPrefBoolean(FPref.DECKGEN_SINGLETONS));
view.getCbArtifacts().setSelected(prefs.getPrefBoolean(FPref.DECKGEN_ARTIFACTS));
}
/** Starts a match with the applied variants. */
private void startGame(final Set<GameType> variantTypes) {
if (!view.isEnoughTeams()) {
FOptionPane.showMessageDialog("There are not enough teams! Please adjust team allocations.");
return;
}
for (final int i : view.getParticipants()) {
if (view.getDeckChooser(i).getPlayer() == null) {
FOptionPane.showMessageDialog("Please specify a deck for " + view.getPlayerName(i));
return;
}
} // Is it even possible anymore? I think current implementation assigns decks automatically.
GameType autoGenerateVariant = null;
boolean isCommanderMatch = false;
boolean isTinyLeadersMatch = false;
if (!variantTypes.isEmpty()) {
isTinyLeadersMatch = variantTypes.contains(GameType.TinyLeaders);
isCommanderMatch = isTinyLeadersMatch || variantTypes.contains(GameType.Commander);
if (!isCommanderMatch) {
for (GameType variant : variantTypes) {
if (variant.isAutoGenerated()) {
autoGenerateVariant = variant;
break;
}
}
}
}
boolean checkLegality = FModel.getPreferences().getPrefBoolean(FPref.ENFORCE_DECK_LEGALITY);
//Auto-generated decks don't need to be checked here
//Commander deck replaces regular deck and is checked later
if (checkLegality && autoGenerateVariant == null && !isCommanderMatch) {
for (final int i : view.getParticipants()) {
String name = view.getPlayerName(i);
String errMsg = GameType.Constructed.getDeckFormat().getDeckConformanceProblem(view.getDeckChooser(i).getPlayer().getDeck());
if (null != errMsg) {
FOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Deck");
return;
}
}
}
final List<RegisteredPlayer> players = new ArrayList<RegisteredPlayer>();
final Map<RegisteredPlayer, IGuiGame> guis = Maps.newHashMap();
final IGuiGame gui = GuiBase.getInterface().getNewGuiGame();
for (final int i : view.getParticipants()) {
final String name = view.getPlayerName(i);
final boolean isAI = view.isPlayerAI(i);
final LobbyPlayer lobbyPlayer = isAI
? GamePlayerUtil.createAiPlayer(name, view.getPlayerAvatar(i), view.getAiOptions(i))
: GamePlayerUtil.getGuiPlayer(name, i);
RegisteredPlayer rp = view.getDeckChooser(i).getPlayer();
if (variantTypes.isEmpty()) {
rp.setTeamNumber(view.getTeam(i));
players.add(rp.setPlayer(lobbyPlayer));
} else {
Deck deck = null;
PaperCard vanguardAvatar = null;
if (isCommanderMatch) {
final Object selected = view.getCommanderDeckLists().get(i).getSelectedValue();
if (selected instanceof String) {
final String sel = (String) selected;
final IStorage<Deck> comDecks = FModel.getDecks().getCommander();
if (sel.equals("Random") && comDecks.size() > 0) {
deck = Aggregates.random(comDecks);
}
} else {
deck = (Deck) selected;
}
GameType commanderGameType = isTinyLeadersMatch ? GameType.TinyLeaders : GameType.Commander;
if (deck == null) { //Can be null if player deselects the list selection or chose Generate
deck = DeckgenUtil.generateCommanderDeck(isAI, commanderGameType);
}
if (checkLegality) {
String errMsg = commanderGameType.getDeckFormat().getDeckConformanceProblem(deck);
if (null != errMsg) {
FOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid " + commanderGameType + " Deck");
return;
}
}
} else if (autoGenerateVariant != null) {
deck = autoGenerateVariant.autoGenerateDeck(rp);
CardPool avatarPool = deck.get(DeckSection.Avatar);
if (avatarPool != null) {
vanguardAvatar = avatarPool.get(0);
}
}
// Initialise variables for other variants
deck = deck == null ? rp.getDeck() : deck;
Iterable<PaperCard> schemes = null;
final boolean playerIsArchenemy = view.isPlayerArchenemy(i);
Iterable<PaperCard> planes = null;
//Archenemy
if (variantTypes.contains(GameType.ArchenemyRumble)
|| (variantTypes.contains(GameType.Archenemy) && playerIsArchenemy)) {
Object selected = view.getSchemeDeckLists().get(i).getSelectedValue();
CardPool schemePool = null;
if (selected instanceof String) {
String sel = (String) selected;
if (sel.contains("Use deck's scheme section")) {
if (deck.has(DeckSection.Schemes)) {
schemePool = deck.get(DeckSection.Schemes);
} else {
sel = "Random";
}
}
IStorage<Deck> sDecks = FModel.getDecks().getScheme();
if (sel.equals("Random") && sDecks.size() != 0) {
schemePool = Aggregates.random(sDecks).get(DeckSection.Schemes);
}
} else {
schemePool = ((Deck) selected).get(DeckSection.Schemes);
}
if (schemePool == null) { //Can be null if player deselects the list selection or chose Generate
schemePool = DeckgenUtil.generateSchemePool();
}
if (checkLegality) {
String errMsg = DeckFormat.getSchemeSectionConformanceProblem(schemePool);
if (null != errMsg) {
FOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Scheme Deck");
return;
}
}
schemes = schemePool.toFlatList();
}
//Planechase
if (variantTypes.contains(GameType.Planechase)) {
Object selected = view.getPlanarDeckLists().get(i).getSelectedValue();
CardPool planePool = null;
if (selected instanceof String) {
String sel = (String) selected;
if (sel.contains("Use deck's planes section")) {
if (deck.has(DeckSection.Planes)) {
planePool = deck.get(DeckSection.Planes);
} else {
sel = "Random";
}
}
IStorage<Deck> pDecks = FModel.getDecks().getPlane();
if (sel.equals("Random") && pDecks.size() != 0) {
planePool = Aggregates.random(pDecks).get(DeckSection.Planes);
}
} else {
planePool = ((Deck) selected).get(DeckSection.Planes);
}
if (planePool == null) { //Can be null if player deselects the list selection or chose Generate
planePool = DeckgenUtil.generatePlanarPool();
}
if (checkLegality) {
String errMsg = DeckFormat.getPlaneSectionConformanceProblem(planePool);
if (null != errMsg) {
FOptionPane.showErrorDialog(name + "'s deck " + errMsg, "Invalid Planar Deck");
return;
}
}
planes = planePool.toFlatList();
}
//Vanguard
if (variantTypes.contains(GameType.Vanguard)) {
Object selected = view.getVanguardLists().get(i).getSelectedValue();
if (selected instanceof String) {
String sel = (String) selected;
if (sel.contains("Use deck's default avatar") && deck.has(DeckSection.Avatar)) {
vanguardAvatar = deck.get(DeckSection.Avatar).get(0);
} else { //Only other string is "Random"
if (isAI) { //AI
vanguardAvatar = Aggregates.random(view.getNonRandomAiAvatars());
} else { //Human
vanguardAvatar = Aggregates.random(view.getNonRandomHumanAvatars());
}
}
} else {
vanguardAvatar = (PaperCard)selected;
}
if (vanguardAvatar == null) { //ERROR! null if avatar deselected on list
GuiDialog.message("No Vanguard avatar selected for " + name
+ ". Please choose one or disable the Vanguard variant");
return;
}
}
rp = RegisteredPlayer.forVariants(variantTypes, deck, schemes, playerIsArchenemy, planes, vanguardAvatar);
rp.setTeamNumber(view.getTeam(i));
players.add(rp.setPlayer(lobbyPlayer));
}
if (!isAI) {
guis.put(rp, gui);
}
view.getDeckChooser(i).saveState();
}
final HostedMatch hostedMatch = GuiBase.getInterface().hostMatch();
hostedMatch.startMatch(GameType.Constructed, variantTypes, players, guis);
lobby.initialize();
}
/* (non-Javadoc)