diff --git a/forge-gui-desktop/src/main/java/forge/control/FControl.java b/forge-gui-desktop/src/main/java/forge/control/FControl.java
index e212a29fec8..eb0b77199cf 100644
--- a/forge-gui-desktop/src/main/java/forge/control/FControl.java
+++ b/forge-gui-desktop/src/main/java/forge/control/FControl.java
@@ -110,6 +110,7 @@ public enum FControl implements KeyEventDispatcher {
}
}
}
+
/**
*
* FControl.
diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java b/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java
index ae9fd8ad681..5bcfb8d6bb3 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/home/VLobby.java
@@ -239,7 +239,8 @@ public class VLobby implements IUpdateable {
isNewPanel = true;
}
- panel.setType(slot.getType());
+ final LobbySlotType type = slot.getType();
+ panel.setType(type);
panel.setPlayerName(slot.getName());
panel.setAvatar(slot.getAvatarIndex());
panel.setTeam(slot.getTeam());
@@ -253,7 +254,7 @@ public class VLobby implements IUpdateable {
final FDeckChooser deckChooser = getDeckChooser(i);
deckChooser.setIsAi(slot.getType() == LobbySlotType.AI);
- if (fullUpdate) {
+ if (fullUpdate && (type == LobbySlotType.LOCAL || type == LobbySlotType.AI)) {
selectDeck(i);
}
if (isNewPanel) {
@@ -298,7 +299,9 @@ public class VLobby implements IUpdateable {
}
}
private void fireDeckSectionChangeListener(final int index, final DeckSection section, final CardPool cards) {
- decks[index].putSection(section, cards);
+ final Deck copy = new Deck(decks[index]);
+ copy.putSection(section, cards);
+ decks[index] = copy;
if (playerChangeListener != null) {
playerChangeListener.update(index, UpdateLobbyPlayerEvent.deckUpdate(section, cards));
}
@@ -486,7 +489,7 @@ public class VLobby implements IUpdateable {
}
private void selectPlanarDeck(final int playerIndex) {
- if (playerIndex >= activePlayersNum) {
+ if (playerIndex >= activePlayersNum || !hasVariant(GameType.Planechase)) {
return;
}
diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java b/forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java
index 35bf3517fba..a3a6c744af8 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/home/online/CSubmenuOnlineLobby.java
@@ -8,6 +8,7 @@ import javax.swing.JMenu;
import forge.GuiBase;
import forge.Singletons;
import forge.UiCommand;
+import forge.assets.FSkinProp;
import forge.gui.FNetOverlay;
import forge.gui.framework.FScreen;
import forge.gui.framework.ICDoc;
@@ -31,6 +32,7 @@ import forge.net.game.UpdateLobbyPlayerEvent;
import forge.properties.ForgePreferences.FPref;
import forge.screens.home.VLobby;
import forge.screens.home.sanctioned.ConstructedGameMenu;
+import forge.util.gui.SOptionPane;
public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
SINGLETON_INSTANCE;
@@ -64,6 +66,9 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
@Override public final void message(final String source, final String message) {
FNetOverlay.SINGLETON_INSTANCE.addMessage(source, message);
}
+ @Override public final void close() {
+ // NO-OP, server can't receive close message
+ }
});
FNetOverlay.SINGLETON_INSTANCE.setGameClient(new IRemote() {
@Override public final void send(final NetEvent event) {
@@ -79,6 +84,7 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
}
});
+ view.populate();
view.update(true);
Singletons.getControl().setCurrentScreen(FScreen.ONLINE_LOBBY);
@@ -88,6 +94,7 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
final void join(final String hostname, final int port) {
final IGuiGame gui = GuiBase.getInterface().getNewGuiGame();
final FGameClient client = new FGameClient(FModel.getPreferences().getPref(FPref.PLAYER_NAME), "0", gui);
+ VOnlineLobby.SINGLETON_INSTANCE.setClient(client);
FNetOverlay.SINGLETON_INSTANCE.setGameClient(client);
final ClientGameLobby lobby = new ClientGameLobby();
final VLobby view = VOnlineLobby.SINGLETON_INSTANCE.setLobby(lobby);
@@ -100,6 +107,11 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
lobby.setLocalPlayer(slot);
lobby.setData(state);
}
+ @Override public final void close() {
+ SOptionPane.showMessageDialog("Connection to the host was interrupted.", "Error", FSkinProp.ICO_WARNING);
+ VOnlineLobby.SINGLETON_INSTANCE.setClient(null);
+ FScreen.ONLINE_LOBBY.close();
+ }
});
view.setPlayerChangeListener(new IPlayerChangeListener() {
@Override public final void update(final int index, final UpdateLobbyPlayerEvent event) {
@@ -109,7 +121,7 @@ public enum CSubmenuOnlineLobby implements ICDoc, IMenuProvider {
client.connect(hostname, port);
Singletons.getControl().setCurrentScreen(FScreen.ONLINE_LOBBY);
- FNetOverlay.SINGLETON_INSTANCE.showUp(String.format("Connected to %s:%s", hostname, port));
+ FNetOverlay.SINGLETON_INSTANCE.showUp(String.format("Connected to %s:%d", hostname, port));
}
@Override
diff --git a/forge-gui-desktop/src/main/java/forge/screens/home/online/VOnlineLobby.java b/forge-gui-desktop/src/main/java/forge/screens/home/online/VOnlineLobby.java
index 3c43541b380..e476eb33e78 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/home/online/VOnlineLobby.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/home/online/VOnlineLobby.java
@@ -6,6 +6,7 @@ import net.miginfocom.swing.MigLayout;
import forge.deckchooser.DecksComboBoxEvent;
import forge.deckchooser.FDeckChooser;
import forge.deckchooser.IDecksComboBoxListener;
+import forge.gui.FNetOverlay;
import forge.gui.framework.DragCell;
import forge.gui.framework.DragTab;
import forge.gui.framework.EDocID;
@@ -13,6 +14,8 @@ import forge.gui.framework.FScreen;
import forge.gui.framework.IVDoc;
import forge.gui.framework.IVTopLevelUI;
import forge.match.GameLobby;
+import forge.net.FGameClient;
+import forge.net.FServerManager;
import forge.screens.home.VLobby;
import forge.toolbox.FPanel;
import forge.util.gui.SOptionPane;
@@ -26,6 +29,7 @@ public enum VOnlineLobby implements IVDoc, IVTopLevelUI {
// General variables
private VLobby lobby;
+ private FGameClient client;
private VOnlineLobby() {
}
@@ -39,10 +43,15 @@ public enum VOnlineLobby implements IVDoc, IVTopLevelUI {
return this.lobby;
}
+ void setClient(final FGameClient client) {
+ this.client = client;
+ }
+
@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");
@@ -106,7 +115,23 @@ public enum VOnlineLobby implements IVDoc, IVTopLevelUI {
@Override
public boolean onClosing(final FScreen screen) {
- return SOptionPane.showConfirmDialog("Leave lobby?", "Leave");
+ final FServerManager server = FServerManager.getInstance();
+ if (server.isHosting()) {
+ if (SOptionPane.showConfirmDialog("Leave lobby? Doing so will shut down all connections and stop hosting.", "Leave")) {
+ FServerManager.getInstance().stopServer();
+ return true;
+ }
+ } else {
+ if (client == null || SOptionPane.showConfirmDialog("Leave lobby?", "Leave")) {
+ if (client != null) {
+ client.close();
+ client = null;
+ }
+ FNetOverlay.SINGLETON_INSTANCE.setGameClient(null);
+ return true;
+ }
+ }
+ return false;
}
}
diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java
index e4458c2ac82..f1d3481f3ec 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/match/CMatchUI.java
@@ -104,6 +104,7 @@ import forge.toolbox.MouseTriggerEvent;
import forge.toolbox.special.PhaseIndicator;
import forge.toolbox.special.PhaseLabel;
import forge.trackable.TrackableCollection;
+import forge.util.FCollection;
import forge.util.FCollectionView;
import forge.util.ITriggerEvent;
import forge.util.gui.SOptionPane;
@@ -260,11 +261,6 @@ public final class CMatchUI
return FSkin.getAvatars().get(avatarIdx >= 0 ? avatarIdx : defaultIndex);
}
- private void setAvatar(VField view, SkinImage img) {
- view.getLblAvatar().setIcon(img);
- view.getLblAvatar().getResizeTimer().start();
- }
-
private void initMatch(final FCollectionView sortedPlayers, final Iterable myPlayers) {
this.sortedPlayers = sortedPlayers;
this.setLocalPlayers(myPlayers);
@@ -290,8 +286,7 @@ public final class CMatchUI
commands.add(c);
myDocs.put(commandDoc, c);
- //setAvatar(f, new ImageIcon(FSkin.getAvatars().get()));
- setAvatar(f, getPlayerAvatar(p, Integer.parseInt(indices[i > 2 ? 1 : 0])));
+ f.setAvatar(getPlayerAvatar(p, Integer.parseInt(indices[i > 2 ? 1 : 0])));
f.getLayoutControl().initialize();
c.getLayoutControl().initialize();
i++;
@@ -436,7 +431,7 @@ public final class CMatchUI
if (vHand != null) {
vHand.getLayoutControl().updateHand();
}
- vf.getDetailsPanel().updateZones();
+ vf.updateZones();
vf.updateDetails();
FloatingCardArea.refresh(owner, zt);
break;
@@ -448,7 +443,7 @@ public final class CMatchUI
break;
default:
if (vf != null) {
- vf.getDetailsPanel().updateZones();
+ vf.updateZones();
}
FloatingCardArea.refresh(owner, zt);
break;
@@ -460,7 +455,7 @@ public final class CMatchUI
@Override
public void updateManaPool(final Iterable manaPoolUpdate) {
for (final PlayerView p : manaPoolUpdate) {
- getFieldViewFor(p).getDetailsPanel().updateManaPool();
+ getFieldViewFor(p).updateManaPool();
}
}
@@ -795,7 +790,12 @@ public final class CMatchUI
final GameView gameView = getGameView();
gameView.getGameLog().addObserver(getCLog());
- initMatch(gameView.getPlayers(), myPlayers);
+ // Sort players
+ FCollectionView players = gameView.getPlayers();
+ if (players.size() == 2 && myPlayers.size() == 1 && myPlayers.get(0).equals(players.get(1))) {
+ players = new FCollection(new PlayerView[] { players.get(1), players.get(0) });
+ }
+ initMatch(players, myPlayers);
actuateMatchPreferences();
diff --git a/forge-gui-desktop/src/main/java/forge/screens/match/views/VField.java b/forge-gui-desktop/src/main/java/forge/screens/match/views/VField.java
index 6cdeb8e085f..b1978f74c1d 100644
--- a/forge-gui-desktop/src/main/java/forge/screens/match/views/VField.java
+++ b/forge-gui-desktop/src/main/java/forge/screens/match/views/VField.java
@@ -28,6 +28,7 @@ import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import net.miginfocom.swing.MigLayout;
+import forge.assets.FSkinProp;
import forge.game.player.PlayerView;
import forge.game.zone.ZoneType;
import forge.gui.framework.DragCell;
@@ -39,6 +40,7 @@ import forge.screens.match.controllers.CField;
import forge.toolbox.FLabel;
import forge.toolbox.FScrollPane;
import forge.toolbox.FSkin;
+import forge.toolbox.FSkin.SkinImage;
import forge.toolbox.FSkin.SkinnedPanel;
import forge.toolbox.special.PhaseIndicator;
import forge.toolbox.special.PlayerDetailsPanel;
@@ -50,6 +52,9 @@ import forge.view.arcane.PlayArea;
*
(V at beginning of class name denotes a view class.)
*/
public class VField implements IVDoc {
+ private final static int LIFE_CRITICAL = 5;
+ private final static int POISON_CRITICAL = 8;
+
// Fields used with interface IVDoc
private final CField control;
private DragCell parentCell;
@@ -57,7 +62,7 @@ public class VField implements IVDoc {
private final DragTab tab = new DragTab("Field");
// Other fields
- private PlayerView player = null;
+ private final PlayerView player;
// Top-level containers
private final FScrollPane scroller = new FScrollPane(false);
@@ -68,7 +73,8 @@ public class VField implements IVDoc {
// Avatar area
private final FLabel lblAvatar = new FLabel.Builder().fontAlign(SwingConstants.CENTER).iconScaleFactor(1.0f).build();
- private final FLabel lblLife = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).build();
+ private final FLabel lblLife = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).build();
+ private final FLabel lblPoison = new FLabel.Builder().fontAlign(SwingConstants.CENTER).fontStyle(Font.BOLD).icon(FSkin.getImage(FSkinProp.IMG_ZONE_POISON)).iconInBackground().build();
private final PhaseIndicator phaseIndicator = new PhaseIndicator();
@@ -100,12 +106,13 @@ public class VField implements IVDoc {
lblAvatar.setFocusable(false);
lblLife.setFocusable(false);
+ lblPoison.setFocusable(false);
avatarArea.setOpaque(false);
avatarArea.setBackground(FSkin.getColor(FSkin.Colors.CLR_HOVER));
avatarArea.setLayout(new MigLayout("insets 0, gap 0"));
avatarArea.add(lblAvatar, "w 100%-6px!, h 100%-23px!, wrap, gap 3 3 3 0");
- avatarArea.add(lblLife, "w 100%!, h 20px!");
+ avatarArea.add(lblLife, "w 100%!, h 20px!, wrap");
// Player area hover effect
avatarArea.addMouseListener(new MouseAdapter() {
@@ -170,10 +177,6 @@ public class VField implements IVDoc {
return this.parentCell;
}
- public PlayerView getPlayer() {
- return this.player;
- }
-
public PlayArea getTabletop() {
return this.tabletop;
}
@@ -182,14 +185,6 @@ public class VField implements IVDoc {
return this.avatarArea;
}
- public FLabel getLblAvatar() {
- return this.lblAvatar;
- }
-
- public FLabel getLblLife() {
- return this.lblLife;
- }
-
public PhaseIndicator getPhaseIndicator() {
return phaseIndicator;
}
@@ -198,23 +193,67 @@ public class VField implements IVDoc {
return detailsPanel;
}
- public boolean isHighlighted() {
+ private boolean isHighlighted() {
return control.getMatchUI().isHighlighted(player);
}
+ public void setAvatar(final SkinImage avatar) {
+ lblAvatar.setIcon(avatar);
+ lblAvatar.getResizeTimer().start();
+ }
+
+ public void updateManaPool() {
+ detailsPanel.updateManaPool();
+ }
+ public void updateZones() {
+ detailsPanel.updateZones();
+ }
+
+ private void addLblPoison() {
+ if (lblPoison.isShowing()) {
+ return;
+ }
+ avatarArea.remove(lblLife);
+ avatarArea.add(lblLife, "w 50%!, h 20px!, split 2");
+ avatarArea.add(lblPoison, "w 50%!, h 20px!, wrap");
+ }
+ private void removeLblPoison() {
+ if (!lblPoison.isShowing()) {
+ return;
+ }
+ avatarArea.remove(lblPoison);
+ avatarArea.remove(lblLife);
+ avatarArea.add(lblLife, "w 100%!, h 20px!, wrap");
+ }
+
public void updateDetails() {
control.getMatchUI().getCPlayers().update();
detailsPanel.updateDetails();
- this.getLblLife().setText("" + player.getLife());
- if (player.getLife() > 5) {
- this.getLblLife().setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
- }
- else {
- this.getLblLife().setForeground(Color.red);
+ // Update life total
+ final int life = player.getLife();
+ lblLife.setText(String.valueOf(life));
+ if (life > LIFE_CRITICAL) {
+ lblLife.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
+ } else {
+ lblLife.setForeground(Color.RED);
}
- boolean highlighted = isHighlighted();
+ // Update poison counters
+ final int poison = player.getPoisonCounters();
+ if (poison > 0) {
+ addLblPoison();
+ lblPoison.setText(String.valueOf(poison));
+ if (poison < POISON_CRITICAL) {
+ lblPoison.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
+ } else {
+ lblPoison.setForeground(Color.RED);
+ }
+ } else {
+ removeLblPoison();
+ }
+
+ final boolean highlighted = isHighlighted();
this.avatarArea.setBorder(highlighted ? borderAvatarHighlighted : borderAvatarSimple );
this.avatarArea.setOpaque(highlighted);
this.avatarArea.setToolTipText(player.getDetailsHtml());
diff --git a/forge-gui-desktop/src/main/java/forge/toolbox/special/PlayerDetailsPanel.java b/forge-gui-desktop/src/main/java/forge/toolbox/special/PlayerDetailsPanel.java
index 83aab0756f2..8eaeff0dbf5 100644
--- a/forge-gui-desktop/src/main/java/forge/toolbox/special/PlayerDetailsPanel.java
+++ b/forge-gui-desktop/src/main/java/forge/toolbox/special/PlayerDetailsPanel.java
@@ -1,6 +1,7 @@
package forge.toolbox.special;
import java.awt.Color;
+import java.awt.Component;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
@@ -33,23 +34,23 @@ public class PlayerDetailsPanel extends JPanel {
private final PlayerView player;
// Info labels
- private final FLabel lblHand = new DetailLabel(FSkinProp.IMG_ZONE_HAND, "99", "Cards in hand");
- private final FLabel lblGraveyard = new DetailLabel(FSkinProp.IMG_ZONE_GRAVEYARD, "99", "Cards in graveyard");
- private final FLabel lblLibrary = new DetailLabel(FSkinProp.IMG_ZONE_LIBRARY, "99", "Cards in library");
- private final FLabel lblExile = new DetailLabel(FSkinProp.IMG_ZONE_EXILE, "99", "Exiled cards");
- private final FLabel lblFlashback = new DetailLabel(FSkinProp.IMG_ZONE_FLASHBACK, "99", "Flashback cards");
- private final FLabel lblPoison = new DetailLabel(FSkinProp.IMG_ZONE_POISON, "99", "Poison counters");
+ private final DetailLabel lblHand = new DetailLabel(FSkinProp.IMG_ZONE_HAND, "Hand (%s/%s)");
+ private final DetailLabel lblGraveyard = new DetailLabel(FSkinProp.IMG_ZONE_GRAVEYARD, "Graveyard (%s)");
+ private final DetailLabel lblLibrary = new DetailLabel(FSkinProp.IMG_ZONE_LIBRARY, "Library (%s)");
+ private final DetailLabel lblExile = new DetailLabel(FSkinProp.IMG_ZONE_EXILE, "Exile (%s)");
+ private final DetailLabel lblFlashback = new DetailLabel(FSkinProp.IMG_ZONE_FLASHBACK, "Flashback cards (%s)");
+ private final DetailLabel lblPoison = new DetailLabel(FSkinProp.IMG_ZONE_POISON, "Poison counters (%s)");
private final List> manaLabels = new ArrayList>();
public PlayerDetailsPanel(final PlayerView player0) {
player = player0;
- manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_B, "99", "Black mana"), MagicColor.BLACK));
- manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_U, "99", "Blue mana"), MagicColor.BLUE));
- manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_G, "99", "Green mana"), MagicColor.GREEN));
- manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_R, "99", "Red mana"), MagicColor.RED));
- manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_W, "99", "White mana"), MagicColor.WHITE));
- manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_COLORLESS, "99", "Colorless mana"), (byte)0));
+ manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_W, "White mana (%s)"), MagicColor.WHITE));
+ manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_U, "Blue mana (%s)"), MagicColor.BLUE));
+ manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_B, "Black mana (%s)"), MagicColor.BLACK));
+ manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_R, "Red mana (%s)"), MagicColor.RED));
+ manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_G, "Green mana (%s)"), MagicColor.GREEN));
+ manaLabels.add(Pair.of(new DetailLabel(FSkinProp.IMG_MANA_COLORLESS, "Colorless mana (%s)"), MagicColor.COLORLESS));
setOpaque(false);
setLayout(new MigLayout("insets 0, gap 0, wrap"));
@@ -104,75 +105,60 @@ public class PlayerDetailsPanel extends JPanel {
add(row5, constraintsRow);
add(row6, constraintsRow);
}
-
+
+ public Component getLblLibrary() {
+ return lblLibrary;
+ }
+
/**
* Handles observer update of player Zones - hand, graveyard, etc.
*
* @param p0 {@link forge.game.player.Player}
*/
public void updateZones() {
- getLblHand().setText("" + player.getHandSize());
- final String handMaxToolTip = player.hasUnlimitedHandSize()
- ? "no maximum hand size" : String.valueOf(player.getMaxHandSize());
- getLblHand().setToolTipText("Cards in hand (max: " + handMaxToolTip + ")");
- getLblGraveyard().setText("" + player.getGraveyardSize());
- getLblLibrary().setText("" + player.getLibrarySize());
- getLblFlashback().setText("" + player.getFlashbackSize());
- getLblExile().setText("" + player.getExileSize());
+ final String handSize = String.valueOf(player.getHandSize()),
+ graveyardSize = String.valueOf(player.getGraveyardSize()),
+ librarySize = String.valueOf(player.getLibrarySize()),
+ flashbackSize = String.valueOf(player.getFlashbackSize()),
+ exileSize = String.valueOf(player.getExileSize());
+ lblHand.setText(handSize);
+ lblHand.setToolTip(handSize, player.getMaxHandString());
+ lblGraveyard.setText(graveyardSize);
+ lblGraveyard.setToolTip(graveyardSize);
+ lblLibrary.setText(librarySize);
+ lblLibrary.setToolTip(librarySize);
+ lblFlashback.setText(flashbackSize);
+ lblFlashback.setToolTip(flashbackSize);
+ lblExile.setText(exileSize);
+ lblExile.setToolTip(exileSize);
}
/**
- * Handles observer update of non-Zone details - life, poison, etc. Also
- * updates "players" panel in tabber for this player.
- *
- * @param p0 {@link forge.game.player.Player}
+ * Handles observer update of non-Zone details (poison).
*/
public void updateDetails() {
- // Poison/life
- getLblPoison().setText("" + player.getPoisonCounters());
- if (player.getPoisonCounters() < 8) {
- getLblPoison().setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
- }
- else {
- getLblPoison().setForeground(Color.red);
+ // Poison
+ final int poison = player.getPoisonCounters();
+ lblPoison.setText(String.valueOf(poison));
+ lblPoison.setToolTip(String.valueOf(poison));
+ if (poison < 8) {
+ lblPoison.setForeground(FSkin.getColor(FSkin.Colors.CLR_TEXT));
+ } else {
+ lblPoison.setForeground(Color.red);
}
}
/**
* Handles observer update of the mana pool.
- *
- * @param p0 {@link forge.game.player.Player}
*/
public void updateManaPool() {
for (final Pair label : manaLabels) {
- label.getKey().setText(Integer.toString(player.getMana(label.getRight())));
+ final String mana = String.valueOf(player.getMana(label.getRight().byteValue()));
+ label.getKey().setText(mana);
+ label.getKey().setToolTip(mana);
}
}
- public FLabel getLblHand() {
- return lblHand;
- }
-
- public FLabel getLblLibrary() {
- return lblLibrary;
- }
-
- public FLabel getLblGraveyard() {
- return lblGraveyard;
- }
-
- public FLabel getLblExile() {
- return lblExile;
- }
-
- public FLabel getLblFlashback() {
- return lblFlashback;
- }
-
- public FLabel getLblPoison() {
- return lblPoison;
- }
-
public void setupMouseActions(final ForgeAction handAction, final ForgeAction libraryAction, final ForgeAction exileAction,
final ForgeAction graveAction, final ForgeAction flashBackAction, final Function manaAction) {
// Detail label listeners
@@ -212,7 +198,8 @@ public class PlayerDetailsPanel extends JPanel {
@Override
public void onLeftClick(final MouseEvent e) {
//if shift key down, keep using mana until it runs out or no longer can be put towards the cost
- while (manaAction.apply(labelPair.getRight()) && e.isShiftDown()) {}
+ final Byte mana = labelPair.getRight();
+ while (manaAction.apply(mana) && e.isShiftDown()) {}
}
});
}
@@ -220,33 +207,39 @@ public class PlayerDetailsPanel extends JPanel {
@SuppressWarnings("serial")
private class DetailLabel extends FLabel {
- private DetailLabel(FSkinProp p0, String s0, String s1) {
- super(new FLabel.Builder().icon(FSkin.getImage(p0))
+ private final String tooltip;
+ private DetailLabel(final FSkinProp icon, final String tooltip) {
+ super(new FLabel.Builder().icon(FSkin.getImage(icon))
.opaque(false).fontSize(14).hoverable()
.fontStyle(Font.BOLD).iconInBackground()
- .text(s0).tooltip(s1).fontAlign(SwingConstants.RIGHT));
+ .fontAlign(SwingConstants.RIGHT));
+ this.tooltip = tooltip;
setFocusable(false);
}
- public void setText(String text0) {
+ public void setText(final String text0) {
super.setText(text0);
autoSizeFont();
}
+ public void setToolTip(final String... args) {
+ super.setToolTipText(String.format(tooltip, (Object[]) args));
+ }
+
protected void resetIcon() {
super.resetIcon();
autoSizeFont();
}
private void autoSizeFont() {
- String text = getText();
+ final String text = getText();
if (StringUtils.isEmpty(text)) { return; }
- Graphics g = getGraphics();
+ final Graphics g = getGraphics();
if (g == null) { return; }
- int max = getMaxTextWidth();
+ final int max = getMaxTextWidth();
SkinFont font = null;
for (int fontSize = 14; fontSize > 5; fontSize--) {
diff --git a/forge-gui/src/main/java/forge/interfaces/ILobbyListener.java b/forge-gui/src/main/java/forge/interfaces/ILobbyListener.java
index 08aa1dad4f3..74aab55bf9a 100644
--- a/forge-gui/src/main/java/forge/interfaces/ILobbyListener.java
+++ b/forge-gui/src/main/java/forge/interfaces/ILobbyListener.java
@@ -5,4 +5,5 @@ import forge.match.GameLobby.GameLobbyData;
public interface ILobbyListener {
void message(String source, String message);
void update(GameLobbyData state, int slot);
+ void close();
}
diff --git a/forge-gui/src/main/java/forge/match/GameLobby.java b/forge-gui/src/main/java/forge/match/GameLobby.java
index 5daefd93149..011d68a12e2 100644
--- a/forge-gui/src/main/java/forge/match/GameLobby.java
+++ b/forge-gui/src/main/java/forge/match/GameLobby.java
@@ -41,6 +41,7 @@ public abstract class GameLobby {
private final static int MAX_PLAYERS = 8;
private GameLobbyData data = new GameLobbyData();
+ private GameType currentGameType = GameType.Constructed;
private int lastArchenemy = 0;
private IUpdateable listener;
@@ -69,10 +70,10 @@ public abstract class GameLobby {
}
public GameType getGameType() {
- return data.currentGameMode;
+ return currentGameType;
}
public void setGameType(final GameType type) {
- data.currentGameMode = type;
+ currentGameType = type;
}
public boolean hasVariant(final GameType variant) {
@@ -90,7 +91,7 @@ public abstract class GameLobby {
}
public void applyToSlot(final int index, final UpdateLobbyPlayerEvent event) {
final LobbySlot slot = getSlot(index);
- if (slot == null) {
+ if (slot == null || event == null) {
throw new NullPointerException();
}
@@ -130,10 +131,10 @@ public abstract class GameLobby {
}
public abstract boolean hasControl();
- public abstract boolean mayEdit(final int index);
- public abstract boolean mayControl(final int index);
- public abstract boolean mayRemove(final int index);
- protected abstract IGuiGame getGui(final int index);
+ public abstract boolean mayEdit(int index);
+ public abstract boolean mayControl(int index);
+ public abstract boolean mayRemove(int index);
+ protected abstract IGuiGame getGui(int index);
protected abstract void onGameStarted();
public void addSlot() {
@@ -142,6 +143,9 @@ public abstract class GameLobby {
addSlot(new LobbySlot(type, null, newIndex, newIndex, false, !allowNetworking, Collections.emptySet()));
}
protected final void addSlot(final LobbySlot slot) {
+ if (slot == null) {
+ throw new NullPointerException();
+ }
if (data.slots.size() >= MAX_PLAYERS) {
return;
}
@@ -197,7 +201,7 @@ public abstract class GameLobby {
}
public void applyVariant(final GameType variant) {
- data.currentGameMode = variant;
+ setGameType(variant);
data.appliedVariants.add(variant);
//ensure other necessary variants are unchecked
@@ -231,17 +235,21 @@ public abstract class GameLobby {
}
public void removeVariant(final GameType variant) {
- data.appliedVariants.remove(variant);
+ final boolean changed = data.appliedVariants.remove(variant);
+ if (!changed) {
+ return;
+ }
+
if (data.appliedVariants.isEmpty()) {
data.appliedVariants.add(GameType.Constructed);
}
- if (variant == data.currentGameMode) {
+ if (variant == currentGameType) {
if (hasVariant(GameType.Commander)) {
- data.currentGameMode = GameType.Commander;
+ currentGameType = GameType.Commander;
} else if (hasVariant(GameType.TinyLeaders)) {
- data.currentGameMode = GameType.TinyLeaders;
+ currentGameType = GameType.TinyLeaders;
} else {
- data.currentGameMode = GameType.Constructed;
+ currentGameType = GameType.Constructed;
}
}
updateView(true);
@@ -275,7 +283,7 @@ public abstract class GameLobby {
}
final List activeSlots = Lists.newArrayListWithCapacity(getNumberOfSlots());
- for (final LobbySlot slot : data.getSlots()) {
+ for (final LobbySlot slot : data.slots) {
if (slot.getType() != LobbySlotType.OPEN) {
activeSlots.add(slot);
}
@@ -290,6 +298,12 @@ public abstract class GameLobby {
SOptionPane.showMessageDialog(String.format("Please specify a deck for %s", slot.getName()));
return;
}
+ if (hasVariant(GameType.Commander) || hasVariant(GameType.TinyLeaders)) {
+ if (!slot.getDeck().has(DeckSection.Commander)) {
+ SOptionPane.showMessageDialog(String.format("%s doesn't have a commander", slot.getName()));
+ return;
+ }
+ }
}
final Set variantTypes = data.appliedVariants;
@@ -391,7 +405,7 @@ public abstract class GameLobby {
return;
}
}
- schemes = schemePool.toFlatList();
+ schemes = schemePool == null ? Collections.emptyList() : schemePool.toFlatList();
}
//Planechase
@@ -404,7 +418,7 @@ public abstract class GameLobby {
return;
}
}
- planes = planePool.toFlatList();
+ planes = planePool == null ? Collections.emptyList() : planePool.toFlatList();
}
//Vanguard
@@ -441,23 +455,12 @@ public abstract class GameLobby {
}
public final static class GameLobbyData implements Serializable {
- private static final long serialVersionUID = -9038854736144187540L;
+ private static final long serialVersionUID = 9184758307999646864L;
- private transient GameType currentGameMode = GameType.Constructed;
private final Set appliedVariants = EnumSet.of(GameType.Constructed);
private final List slots = Lists.newArrayList();
- public GameType getCurrentGameMode() {
- return currentGameMode;
- }
- public void setCurrentGameMode(GameType currentGameMode) {
- this.currentGameMode = currentGameMode;
- }
- public Set getAppliedVariants() {
- return Collections.unmodifiableSet(appliedVariants);
- }
- public List getSlots() {
- return Collections.unmodifiableList(slots);
+ public GameLobbyData() {
}
}
}
diff --git a/forge-gui/src/main/java/forge/match/LobbySlot.java b/forge-gui/src/main/java/forge/match/LobbySlot.java
index c3707d6ae26..055095fce95 100644
--- a/forge-gui/src/main/java/forge/match/LobbySlot.java
+++ b/forge-gui/src/main/java/forge/match/LobbySlot.java
@@ -62,10 +62,11 @@ public final class LobbySlot implements Serializable {
setAiOptions(data.getAiOptions());
changed = true;
}
+ final Deck oldDeck = getDeck();
if (data.getDeck() != null) {
setDeck(data.getDeck());
- } else if (getDeck() != null && data.getSection() != null && data.getCards() != null) {
- getDeck().putSection(data.getSection(), data.getCards());
+ } else if (oldDeck != null && data.getSection() != null && data.getCards() != null) {
+ oldDeck.putSection(data.getSection(), data.getCards());
}
return changed;
}
diff --git a/forge-gui/src/main/java/forge/net/FGameClient.java b/forge-gui/src/main/java/forge/net/FGameClient.java
index 64879befe3b..2c1a4f43a64 100644
--- a/forge-gui/src/main/java/forge/net/FGameClient.java
+++ b/forge-gui/src/main/java/forge/net/FGameClient.java
@@ -104,6 +104,10 @@ public class FGameClient implements IToServer {
}
}
+ public void close() {
+ channel.close();
+ }
+
@Override
public void send(final NetEvent event) {
System.out.println("Client sent " + event);
@@ -382,5 +386,13 @@ public class FGameClient implements IToServer {
}
super.channelRead(ctx, msg);
}
+
+ @Override
+ public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
+ for (final ILobbyListener listener : lobbyListeners) {
+ listener.close();
+ }
+ super.channelInactive(ctx);
+ }
}
}
diff --git a/forge-gui/src/main/java/forge/net/FServerManager.java b/forge-gui/src/main/java/forge/net/FServerManager.java
index 4328f301df3..c8dab788713 100644
--- a/forge-gui/src/main/java/forge/net/FServerManager.java
+++ b/forge-gui/src/main/java/forge/net/FServerManager.java
@@ -52,6 +52,7 @@ import com.google.common.collect.Maps;
public final class FServerManager {
private static FServerManager instance = null;
+ private boolean isHosting = false;
private final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
private final EventLoopGroup workerGroup = new NioEventLoopGroup();
private final Map clients = Maps.newTreeMap();
@@ -102,6 +103,7 @@ public final class FServerManager {
}
}).start();
+ isHosting = true;
} catch (final InterruptedException e) {
e.printStackTrace();
}
@@ -110,6 +112,11 @@ public final class FServerManager {
public void stopServer() {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
+ isHosting = false;
+ }
+
+ public boolean isHosting() {
+ return isHosting;
}
public void broadcast(final NetEvent event) {