diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml index 52ff1498269..8585014cf74 100644 --- a/Mage.Client/pom.xml +++ b/Mage.Client/pom.xml @@ -42,7 +42,7 @@ net.sf.trove4j trove4j 3.0.3 - + com.mortennobel java-image-scaling @@ -73,12 +73,12 @@ forms_rt 7.0.3 - - junit - junit - jar - test - + + junit + junit + jar + test + ${project.groupId} mage-counter-plugin @@ -131,8 +131,13 @@ tritonus_share 0.3.6 + + net.java.balloontip + balloontip + 1.2.4.1 + - + @@ -140,7 +145,7 @@ file://${project.basedir}/../repository - + @@ -183,7 +188,7 @@ mage-client - + src/main/resources/META-INF/MANIFEST.MF diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index c00eb57c1ed..3492c94478c 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -128,6 +128,9 @@ import mage.remote.SessionImpl; import mage.utils.MageVersion; import mage.view.GameEndView; import mage.view.UserRequestMessage; +import net.java.balloontip.BalloonTip; +import net.java.balloontip.positioners.LeftAbovePositioner; +import net.java.balloontip.styles.EdgedBalloonStyle; import net.java.truevfs.access.TArchiveDetector; import net.java.truevfs.access.TConfig; import net.java.truevfs.kernel.spec.FsAccessOption; @@ -176,6 +179,8 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { private static long startTime; + private BalloonTip balloonTip; + /** * @return the session */ @@ -298,6 +303,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } }); + // balloonTip = new BalloonTip(desktopPane, "", new ModernBalloonStyle(0, 0, Color.WHITE, Color.YELLOW, Color.BLUE), false); + balloonTip = new BalloonTip(desktopPane, "", new EdgedBalloonStyle(Color.WHITE, Color.BLUE), false); + balloonTip.setPositioner(new LeftAbovePositioner(0, 0)); + mageToolbar.add(new javax.swing.JToolBar.Separator()); mageToolbar.add(createWindowsButton()); @@ -352,6 +361,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_CHECK, "false").equals("true")) { checkForNewImages(); } + updateMemUsageTask.execute(); LOGGER.info("Client start up time: " + ((System.currentTimeMillis() - startTime) / 1000 + " seconds")); if (autoConnect()) { @@ -360,6 +370,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { connectDialog.showDialog(); } setWindowTitle(); + } }); @@ -1043,11 +1054,9 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { if (setActive) { setActive(tablesPane); } else // if other panel was already shown, mamke sure it's topmost again - { - if (topPanebefore != null) { + if (topPanebefore != null) { setActive(topPanebefore); } - } } public void hideGames() { @@ -1291,6 +1300,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { DRAFTS.put(draftId, draftPanel); } + public BalloonTip getBalloonTip() { + return balloonTip; + } + @Override public void connected(final String message) { if (SwingUtilities.isEventDispatchThread()) { diff --git a/Mage.Client/src/main/java/mage/client/MagePane.form b/Mage.Client/src/main/java/mage/client/MagePane.form index 42bad78a9d4..725f5d510d5 100644 --- a/Mage.Client/src/main/java/mage/client/MagePane.form +++ b/Mage.Client/src/main/java/mage/client/MagePane.form @@ -1,4 +1,4 @@ - +
diff --git a/Mage.Client/src/main/java/mage/client/MagePane.java b/Mage.Client/src/main/java/mage/client/MagePane.java index 066051a149d..75e8e8fa593 100644 --- a/Mage.Client/src/main/java/mage/client/MagePane.java +++ b/Mage.Client/src/main/java/mage/client/MagePane.java @@ -24,14 +24,13 @@ * The views and conclusions contained in the software and documentation are those of the * authors and should not be interpreted as representing official policies, either expressed * or implied, of BetaSteward_at_googlemail.com. -*/ + */ -/* + /* * MagePane.java * * Created on 15-Dec-2009, 9:34:25 PM */ - package mage.client; import java.awt.KeyboardFocusManager; @@ -46,9 +45,11 @@ import org.apache.log4j.Logger; */ public abstract class MagePane extends javax.swing.JInternalFrame { - private static final Logger logger = Logger.getLogger(MagePane.class); + private static final Logger LOGGER = Logger.getLogger(MagePane.class); - /** Creates new form MagePane */ + /** + * Creates new form MagePane + */ public MagePane() { this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); initComponents(); @@ -90,10 +91,10 @@ public abstract class MagePane extends javax.swing.JInternalFrame { } - /** This method is called from within the constructor to - * initialize the form. - * WARNING: Do NOT modify this code. The content of this method is - * always regenerated by the Form Editor. + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents @@ -115,8 +116,6 @@ public abstract class MagePane extends javax.swing.JInternalFrame { pack(); }// //GEN-END:initComponents - // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables - } diff --git a/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java b/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java index 2f307ea2f78..ee060b5d4dc 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/TableWaitingDialog.java @@ -60,7 +60,8 @@ import org.apache.log4j.Logger; */ public class TableWaitingDialog extends MageDialog { - private static final Logger logger = Logger.getLogger(TableWaitingDialog.class); + private static final Logger LOGGER = Logger.getLogger(TableWaitingDialog.class); + private static final int[] DEFAULT_COLUMS_WIDTH = {20, 50, 100, 100, 100}; private UUID tableId; private UUID roomId; @@ -68,7 +69,6 @@ public class TableWaitingDialog extends MageDialog { private Session session; private final TableWaitModel tableWaitModel; private UpdateSeatsTask updateTask; - private static final int[] defaultColumnsWidth = {20, 50, 100, 100, 100}; /** * Creates new form TableWaitingDialog @@ -88,7 +88,7 @@ public class TableWaitingDialog extends MageDialog { chatPanel.useExtendedView(ChatPanelBasic.VIEW_MODE.NONE); tableSeats.createDefaultColumnsFromModel(); - TableUtil.setColumnWidthAndOrder(tableSeats, defaultColumnsWidth, KEY_TABLE_WAITING_COLUMNS_WIDTH, KEY_TABLE_WAITING_COLUMNS_ORDER); + TableUtil.setColumnWidthAndOrder(tableSeats, DEFAULT_COLUMS_WIDTH, KEY_TABLE_WAITING_COLUMNS_WIDTH, KEY_TABLE_WAITING_COLUMNS_ORDER); tableSeats.setDefaultRenderer(Icon.class, new CountryCellRenderer()); MageFrame.getUI().addButton(MageComponents.TABLE_WAITING_START_BUTTON, btnStart); @@ -280,7 +280,7 @@ public class TableWaitingDialog extends MageDialog { } } catch (Exception e) { //swallow exception - logger.error(e); + LOGGER.error(e); } closeDialog(); }//GEN-LAST:event_btnCancelActionPerformed diff --git a/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java b/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java index 543ceb53ab0..38bd28d71ea 100644 --- a/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java @@ -34,14 +34,21 @@ package mage.client.table; import java.awt.Color; +import java.awt.event.MouseEvent; +import java.awt.event.MouseMotionAdapter; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; +import java.util.Map; import javax.swing.Icon; +import javax.swing.JTable; import javax.swing.border.EmptyBorder; import javax.swing.table.AbstractTableModel; import javax.swing.table.JTableHeader; +import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; +import mage.client.MageFrame; import mage.client.chat.ChatPanelBasic; import static mage.client.chat.ChatPanelBasic.CHAT_ALPHA; import static mage.client.dialog.PreferencesDialog.KEY_USERS_COLUMNS_ORDER; @@ -52,6 +59,7 @@ import mage.client.util.gui.countryBox.CountryCellRenderer; import mage.remote.MageRemoteException; import mage.view.RoomUsersView; import mage.view.UsersView; +import net.java.balloontip.utils.ToolTipUtils; /** * @@ -79,6 +87,8 @@ public class PlayersChatPanel extends javax.swing.JPanel { jTablePlayers.setRowSorter(new MageTableRowSorter(userTableModel)); TableUtil.setColumnWidthAndOrder(jTablePlayers, DEFAULT_COLUMNS_WIDTH, KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER); + userTableModel.initHeaderTooltips(); + jTablePlayers.setDefaultRenderer(Icon.class, new CountryCellRenderer()); jScrollPaneTalk.setSystemMessagesPane(colorPaneSystem); @@ -169,10 +179,61 @@ public class PlayersChatPanel extends javax.swing.JPanel { return ""; } + public void initHeaderTooltips() { + ColumnHeaderToolTips tips = new ColumnHeaderToolTips(); + for (int c = 0; c < jTablePlayers.getColumnCount(); c++) { + String tooltipText = ""; + switch (c) { + case 0: + tooltipText = "The flag the user has assigned to his profile" + + "
You can assign the flag in the connect to server dialog window"; + break; + case 1: + tooltipText = "Name of the user" + + "
(the number behind the header text is the number of currently connected users to the server)"; + break; + case 2: + tooltipText = "Number of matches the user played so far" + + "
Q = number of matches quit" + + "
I = number of matches lost because of idle timeout" + + "
T = number of matches lost because of match timeout"; + break; + case 3: + tooltipText = "%-Ratio of matches played to matches quit" + + "
this calculation does not include tournament matches"; + break; + case 4: + tooltipText = "Number of tournaments the user played so far" + + "
D = number of tournaments left during draft phase" + + "
C = number of tournaments left during constructing phase" + + "
R = number of tournaments left during rounds"; + break; + case 5: + tooltipText = "%-Ratio of tournament matches played to tournament matches quit" + + "
this calculation does not include non tournament matches"; + break; + case 6: + tooltipText = "Current activities of the player" + + "
the header itself shows the number of currently active games" + + "
T: = number of games threads " + + "
(that can vary from active games because of sideboarding or crashed games)" + + "
limt: the maximum of games the server is configured to" + + "
(if the number of started games exceed that limit, the games have to wait" + + "
until active games end)
"; + break; + case 7: + tooltipText = "Latency of the user's connection to the server"; + break; + } + tips.setToolTip(c, tooltipText); + } + JTableHeader header = jTablePlayers.getTableHeader(); + header.addMouseMotionListener(tips); + } + @Override public String getColumnName(int columnIndex) { String colName = ""; - if (columnIndex <= getColumnCount()) { colName = columnNames[columnIndex]; } @@ -185,6 +246,9 @@ public class PlayersChatPanel extends javax.swing.JPanel { switch (columnIndex) { case 0: return Icon.class; + case 3: + case 5: + return Integer.class; default: return String.class; } @@ -290,4 +354,41 @@ public class PlayersChatPanel extends javax.swing.JPanel { private javax.swing.JTabbedPane jTabbedPaneText; private javax.swing.JTable jTablePlayers; // End of variables declaration//GEN-END:variables + + class ColumnHeaderToolTips extends MouseMotionAdapter { + + int curCol; + Map tips = new HashMap<>(); + + public void setToolTip(Integer mCol, String tooltip) { + if (tooltip == null) { + tips.remove(mCol); + } else { + tips.put(mCol, tooltip); + } + } + + @Override + public void mouseMoved(MouseEvent evt) { + JTableHeader header = (JTableHeader) evt.getSource(); + JTable table = header.getTable(); + TableColumnModel colModel = table.getColumnModel(); + int vColIndex = colModel.getColumnIndexAtX(evt.getX()); + TableColumn col = null; + if (vColIndex >= 0) { + col = colModel.getColumn(table.convertColumnIndexToModel(vColIndex)); + } + if (table.convertColumnIndexToModel(vColIndex) != curCol) { + if (col != null) { + MageFrame.getInstance().getBalloonTip().setAttachedComponent(header); + MageFrame.getInstance().getBalloonTip().setTextContents(tips.get(table.convertColumnIndexToModel(vColIndex))); + ToolTipUtils.balloonToToolTip(MageFrame.getInstance().getBalloonTip(), 600, 10000); + } else { + MageFrame.getInstance().getBalloonTip().setTextContents(""); + } + curCol = table.convertColumnIndexToModel(vColIndex); + } + } + } + } diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.form b/Mage.Client/src/main/java/mage/client/table/TablesPanel.form index 95b426c7da7..7bd3fdeea1b 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.form +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.form @@ -674,4 +674,4 @@ - \ No newline at end of file + diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index b1534720591..507a8aae612 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -100,7 +100,8 @@ import org.apache.log4j.Logger; */ public class TablesPanel extends javax.swing.JPanel { - private static final Logger logger = Logger.getLogger(TablesPanel.class); + private static final Logger LOGGER = Logger.getLogger(TablesPanel.class); + private static final int[] DEFAULT_COLUMNS_WIDTH = {35, 150, 120, 180, 80, 120, 80, 60, 40, 60}; private TableTableModel tableModel; private MatchesTableModel matchesModel; @@ -119,8 +120,6 @@ public class TablesPanel extends javax.swing.JPanel { JToggleButton[] filterButtons; - private static final int[] defaultColumnsWidth = {35, 150, 120, 180, 80, 120, 80, 60, 40, 60}; - /** * Creates new form TablesPanel */ @@ -138,7 +137,7 @@ public class TablesPanel extends javax.swing.JPanel { activeTablesSorter = new MageTableRowSorter(tableModel); tableTables.setRowSorter(activeTablesSorter); - TableUtil.setColumnWidthAndOrder(tableTables, defaultColumnsWidth, + TableUtil.setColumnWidthAndOrder(tableTables, DEFAULT_COLUMNS_WIDTH, PreferencesDialog.KEY_TABLES_COLUMNS_WIDTH, PreferencesDialog.KEY_TABLES_COLUMNS_ORDER); tableCompleted.setRowSorter(new MageTableRowSorter(matchesModel)); @@ -187,18 +186,18 @@ public class TablesPanel extends javax.swing.JPanel { try { frame.setSelected(true); } catch (PropertyVetoException ve) { - logger.error(ve); + LOGGER.error(ve); } } } } catch (InterruptedException ex) { - logger.error(ex); + LOGGER.error(ex); } return; } if (isTournament) { - logger.info("Joining tournament " + tableId); + LOGGER.info("Joining tournament " + tableId); if (deckType.startsWith("Limited")) { if (!status.endsWith("PW")) { session.joinTournamentTable(roomId, tableId, session.getUserName(), "Human", 1, null, ""); @@ -209,7 +208,7 @@ public class TablesPanel extends javax.swing.JPanel { joinTableDialog.showDialog(roomId, tableId, true, deckType.startsWith("Limited")); } } else { - logger.info("Joining table " + tableId); + LOGGER.info("Joining table " + tableId); joinTableDialog.showDialog(roomId, tableId, false, false); } break; @@ -220,18 +219,18 @@ public class TablesPanel extends javax.swing.JPanel { break; case "Show": if (isTournament) { - logger.info("Showing tournament table " + tableId); + LOGGER.info("Showing tournament table " + tableId); session.watchTable(roomId, tableId); } break; case "Watch": if (!isTournament) { - logger.info("Watching table " + tableId); + LOGGER.info("Watching table " + tableId); session.watchTable(roomId, tableId); } break; case "Replay": - logger.info("Replaying game " + gameId); + LOGGER.info("Replaying game " + gameId); session.replayGame(gameId); break; } @@ -258,7 +257,7 @@ public class TablesPanel extends javax.swing.JPanel { break; case "Show":; if (matchesModel.isTournament(modelRow)) { - logger.info("Showing tournament table " + matchesModel.getTableId(modelRow)); + LOGGER.info("Showing tournament table " + matchesModel.getTableId(modelRow)); session.watchTable(roomId, matchesModel.getTableId(modelRow)); } break; @@ -1177,7 +1176,7 @@ public class TablesPanel extends javax.swing.JPanel { }//GEN-LAST:event_btnStateFinishedActionPerformed private void handleError(Exception ex) { - logger.fatal("Error loading deck: ", ex); + LOGGER.fatal("Error loading deck: ", ex); JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Error loading deck.", "Error", JOptionPane.ERROR_MESSAGE); } diff --git a/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java b/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java index 9c50628a9c2..3a033341acd 100644 --- a/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java +++ b/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java @@ -26,7 +26,7 @@ * or implied, of BetaSteward_at_googlemail.com. */ -/* + /* * TournamentPanel.java * * Created on 20-Jan-2011, 9:18:30 PM @@ -72,7 +72,10 @@ import org.apache.log4j.Logger; */ public class TournamentPanel extends javax.swing.JPanel { - private static final Logger logger = Logger.getLogger(TournamentPanel.class); + private static final Logger LOGGER = Logger.getLogger(TournamentPanel.class); + + private static final int[] DEFAULT_COLUMNS_WIDTH_PLAYERS = {30, 150, 150, 60, 400, 100}; + private static final int[] DEFAULT_COLUMNS_WIDTH_MATCHES = {60, 140, 140, 400, 80}; private UUID tournamentId; private boolean firstInitDone = false; @@ -82,9 +85,6 @@ public class TournamentPanel extends javax.swing.JPanel { private UpdateTournamentTask updateTask; private final DateFormat df; - private static final int[] defaultColumnsWidthPlayers = {30, 150, 150, 60, 400}; - private static final int[] defaultColumnsWidthMatches = {60, 140, 140, 400, 80}; - /** * Creates new form TournamentPanel */ @@ -99,11 +99,11 @@ public class TournamentPanel extends javax.swing.JPanel { df = DateFormat.getDateTimeInstance(); tablePlayers.createDefaultColumnsFromModel(); - TableUtil.setColumnWidthAndOrder(tablePlayers, defaultColumnsWidthPlayers, KEY_TOURNAMENT_PLAYER_COLUMNS_WIDTH, KEY_TOURNAMENT_PLAYER_COLUMNS_ORDER); + TableUtil.setColumnWidthAndOrder(tablePlayers, DEFAULT_COLUMNS_WIDTH_PLAYERS, KEY_TOURNAMENT_PLAYER_COLUMNS_WIDTH, KEY_TOURNAMENT_PLAYER_COLUMNS_ORDER); tablePlayers.setDefaultRenderer(Icon.class, new CountryCellRenderer()); tableMatches.createDefaultColumnsFromModel(); - TableUtil.setColumnWidthAndOrder(tableMatches, defaultColumnsWidthMatches, KEY_TOURNAMENT_MATCH_COLUMNS_WIDTH, KEY_TOURNAMENT_MATCH_COLUMNS_ORDER); + TableUtil.setColumnWidthAndOrder(tableMatches, DEFAULT_COLUMNS_WIDTH_MATCHES, KEY_TOURNAMENT_MATCH_COLUMNS_WIDTH, KEY_TOURNAMENT_MATCH_COLUMNS_ORDER); chatPanel1.useExtendedView(ChatPanelBasic.VIEW_MODE.NONE); chatPanel1.setChatType(ChatPanelBasic.ChatType.TOURNAMENT); @@ -123,7 +123,7 @@ public class TournamentPanel extends javax.swing.JPanel { // session.replayGame(gameId); // } if (state.startsWith("Dueling") && actionText.equals("Watch")) { - logger.info("Watching game " + gameId); + LOGGER.info("Watching game " + gameId); session.watchTournamentTable(tableId); } } @@ -545,7 +545,7 @@ public class TournamentPanel extends javax.swing.JPanel { class TournamentPlayersTableModel extends AbstractTableModel { - private final String[] columnNames = new String[]{"Loc", "Player Name", "State", "Points", "Results"}; + private final String[] columnNames = new String[]{"Loc", "Player Name", "State", "Points", "Results", "History"}; private TournamentPlayerView[] players = new TournamentPlayerView[0]; public void loadData(TournamentView tournament) { @@ -576,6 +576,8 @@ class TournamentPlayersTableModel extends AbstractTableModel { return Integer.toString(players[arg0].getPoints()); case 4: return players[arg0].getResults(); + case 5: + return players[arg0].getHistory(); } return ""; } diff --git a/Mage.Common/src/mage/view/TournamentPlayerView.java b/Mage.Common/src/mage/view/TournamentPlayerView.java index 2c488cd6921..c2a8078a254 100644 --- a/Mage.Common/src/mage/view/TournamentPlayerView.java +++ b/Mage.Common/src/mage/view/TournamentPlayerView.java @@ -42,6 +42,7 @@ public class TournamentPlayerView implements Serializable, Comparable { private final String name; private final String state; private final String results; + private final String history; private final int points; private final boolean quit; @@ -57,6 +58,7 @@ public class TournamentPlayerView implements Serializable, Comparable { this.points = tournamentPlayer.getPoints(); this.results = tournamentPlayer.getResults(); this.quit = !tournamentPlayer.isInTournament(); + this.history = tournamentPlayer.getPlayer().getUserData().getHistory(); this.flagName = tournamentPlayer.getPlayer().getUserData().getFlagName(); } @@ -88,4 +90,9 @@ public class TournamentPlayerView implements Serializable, Comparable { public String getFlagName() { return flagName; } + + public String getHistory() { + return history; + } + } diff --git a/Mage.Common/src/mage/view/UsersView.java b/Mage.Common/src/mage/view/UsersView.java index cf2544767cd..650f9eb2aae 100644 --- a/Mage.Common/src/mage/view/UsersView.java +++ b/Mage.Common/src/mage/view/UsersView.java @@ -40,9 +40,9 @@ public class UsersView implements Serializable { private final String flagName; private final String userName; private final String matchHistory; - private final String matchQuitRatio; + private final int matchQuitRatio; private final String tourneyHistory; - private final String tourneyQuitRatio; + private final int tourneyQuitRatio; private final String infoGames; private final String infoPing; @@ -50,9 +50,9 @@ public class UsersView implements Serializable { String tourneyHistory, int tourneyQuitRatio, String infoGames, String infoPing) { this.flagName = flagName; this.matchHistory = matchHistory; - this.matchQuitRatio = Integer.toString(matchQuitRatio); + this.matchQuitRatio = matchQuitRatio; this.tourneyHistory = tourneyHistory; - this.tourneyQuitRatio = Integer.toString(tourneyQuitRatio); + this.tourneyQuitRatio = tourneyQuitRatio; this.userName = userName; this.infoGames = infoGames; this.infoPing = infoPing; @@ -70,7 +70,7 @@ public class UsersView implements Serializable { return matchHistory; } - public String getMatchQuitRatio() { + public int getMatchQuitRatio() { return matchQuitRatio; } @@ -78,7 +78,7 @@ public class UsersView implements Serializable { return tourneyHistory; } - public String getTourneyQuitRatio() { + public int getTourneyQuitRatio() { return tourneyQuitRatio; } diff --git a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java index 5d4d66f27f3..da804121e47 100644 --- a/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java +++ b/Mage.Server/src/main/java/mage/server/game/GamesRoomImpl.java @@ -63,9 +63,9 @@ import org.apache.log4j.Logger; */ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { - private static final Logger logger = Logger.getLogger(GamesRoomImpl.class); + private static final Logger LOGGER = Logger.getLogger(GamesRoomImpl.class); - private static final ScheduledExecutorService updateExecutor = Executors.newSingleThreadScheduledExecutor(); + private static final ScheduledExecutorService UPDATE_EXECUTOR = Executors.newSingleThreadScheduledExecutor(); private static List tableView = new ArrayList<>(); private static List matchView = new ArrayList<>(); private static List roomUsersView = new ArrayList<>(); @@ -73,13 +73,13 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { private final ConcurrentHashMap tables = new ConcurrentHashMap<>(); public GamesRoomImpl() { - updateExecutor.scheduleAtFixedRate(new Runnable() { + UPDATE_EXECUTOR.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { update(); } catch (Exception ex) { - logger.fatal("Games room update exception! " + ex.toString(), ex); + LOGGER.fatal("Games room update exception! " + ex.toString(), ex); } } @@ -118,7 +118,7 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { user.getMatchHistory(), user.getMatchQuitRatio(), user.getTourneyHistory(), user.getTourneyQuitRatio(), user.getGameInfo(), user.getPingInfo())); } catch (Exception ex) { - logger.fatal("User update exception: " + user.getName() + " - " + ex.toString(), ex); + LOGGER.fatal("User update exception: " + user.getName() + " - " + ex.toString(), ex); users.add(new UsersView( (user.getUserData() != null && user.getUserData().getFlagName() != null) ? user.getUserData().getFlagName() : "world", user.getName() != null ? user.getName() : "", @@ -197,8 +197,8 @@ public class GamesRoomImpl extends RoomImpl implements GamesRoom, Serializable { if (table != null) { table.cleanUp(); tables.remove(tableId); - if (logger.isDebugEnabled()) { - logger.debug("Table removed: " + tableId); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Table removed: " + tableId); } } } diff --git a/Mage.Sets/src/mage/sets/fatereforged/WardenOfTheFirstTree.java b/Mage.Sets/src/mage/sets/fatereforged/WardenOfTheFirstTree.java index 44ab9bd18da..ebf951f2e5c 100644 --- a/Mage.Sets/src/mage/sets/fatereforged/WardenOfTheFirstTree.java +++ b/Mage.Sets/src/mage/sets/fatereforged/WardenOfTheFirstTree.java @@ -55,12 +55,12 @@ import mage.game.permanent.token.Token; */ public class WardenOfTheFirstTree extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent(); - + private static final FilterCreaturePermanent FILTER = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent FILTER2 = new FilterCreaturePermanent(); + static { - filter.add(new SubtypePredicate("Warrior")); - filter2.add(new SubtypePredicate("Spirit")); + FILTER.add(new SubtypePredicate("Warrior")); + FILTER2.add(new SubtypePredicate("Spirit")); } public WardenOfTheFirstTree(UUID ownerId) { @@ -80,21 +80,21 @@ public class WardenOfTheFirstTree extends CardImpl { this.addAbility(new SimpleActivatedAbility( Zone.BATTLEFIELD, new ConditionalContinuousEffect( - new BecomesCreatureSourceEffect(new WardenOfTheFirstTree2(), "", Duration.Custom), - new LockedInCondition(new SourceMatchesFilterCondition(filter)), - "If {this} is a Warrior, it becomes a Human Spirit Warrior with trample and lifelink"), + new BecomesCreatureSourceEffect(new WardenOfTheFirstTree2(), "", Duration.Custom), + new LockedInCondition(new SourceMatchesFilterCondition(FILTER)), + "If {this} is a Warrior, it becomes a Human Spirit Warrior with trample and lifelink"), new ManaCostsImpl("{2}{W/B}{W/B}") - )); + )); // {3}{W/B}{W/B}{W/B}: If Warden of the First Tree is a Spirit, put five +1/+1 counters on it. this.addAbility(new SimpleActivatedAbility( Zone.BATTLEFIELD, new ConditionalOneShotEffect( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(5)), - new SourceMatchesFilterCondition(filter2), - "If {this} is a Spirit, put five +1/+1 counters on it"), + new AddCountersSourceEffect(CounterType.P1P1.createInstance(5)), + new SourceMatchesFilterCondition(FILTER2), + "If {this} is a Spirit, put five +1/+1 counters on it"), new ManaCostsImpl("{3}{W/B}{W/B}{W/B}") - )); + )); } public WardenOfTheFirstTree(final WardenOfTheFirstTree card) { diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/PulseOfMurasa.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/PulseOfMurasa.java index 52f467f75fc..e352add1cd8 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/PulseOfMurasa.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/PulseOfMurasa.java @@ -44,10 +44,10 @@ import mage.target.common.TargetCardInGraveyard; */ public class PulseOfMurasa extends CardImpl { - private static final FilterCard filter = new FilterCard("creature or land card in a graveyard"); + private static final FilterCard FILTER = new FilterCard("creature or land card in a graveyard"); static { - filter.add(Predicates.or( + FILTER.add(Predicates.or( new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.LAND))); } @@ -58,9 +58,9 @@ public class PulseOfMurasa extends CardImpl { // Return target creature or land card from a graveyard to its owner's hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInGraveyard(filter)); + this.getSpellAbility().addTarget(new TargetCardInGraveyard(FILTER)); // You gain 6 life. - getSpellAbility().addEffect(new GainLifeEffect(6)); + this.getSpellAbility().addEffect(new GainLifeEffect(6)); } public PulseOfMurasa(final PulseOfMurasa card) { diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WardenOfTheFirstTreeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WardenOfTheFirstTreeTest.java index 5e2058b2c65..e61c6fa7eda 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WardenOfTheFirstTreeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/WardenOfTheFirstTreeTest.java @@ -120,4 +120,26 @@ public class WardenOfTheFirstTreeTest extends CardTestPlayerBase { * power/toughness instead of 1/1. I have had it enter with both 2/2 and * 4/4, neither of which are actual values the card can hold. */ + @Test + public void testTwoWarden() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 7); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + // {1}{W/B}: Warden of the First Tree becomes a Human Warrior with base power and toughness 3/3. + // {2}{W/B}{W/B}: If Warden of the First Tree is a Warrior, it becomes a Human Spirit Warrior with trample and lifelink. + // {3}{W/B}{W/B}{W/B}: If Warden of the First Tree is a Spirit, put five +1/+1 counters on it. + addCard(Zone.HAND, playerA, "Warden of the First Tree", 2); // {G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Warden of the First Tree"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{W/B}:"); + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}{W/B}{W/B}:"); + + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Warden of the First Tree"); + + setStopAt(3, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Warden of the First Tree", 1, 1, Filter.ComparisonScope.Any); + assertPowerToughness(playerA, "Warden of the First Tree", 3, 3, Filter.ComparisonScope.Any); + } + } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceMatchesFilterCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceMatchesFilterCondition.java index 8c2b39a8ad3..adac2b8cf14 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SourceMatchesFilterCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceMatchesFilterCondition.java @@ -33,7 +33,6 @@ import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; - /** * Describes condition when source matches specified filter * @@ -41,17 +40,17 @@ import mage.game.permanent.Permanent; */ public class SourceMatchesFilterCondition implements Condition { - private FilterPermanent filter; + private FilterPermanent FILTER; public SourceMatchesFilterCondition(FilterPermanent filter) { - this.filter = filter; + this.FILTER = filter; } @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); if (permanent != null) { - if (filter.match(permanent, permanent.getId(), permanent.getControllerId(), game)) { + if (FILTER.match(permanent, permanent.getId(), permanent.getControllerId(), game)) { return true; } } diff --git a/Mage/src/main/java/mage/players/net/UserData.java b/Mage/src/main/java/mage/players/net/UserData.java index 572688c19e9..865ad606e98 100644 --- a/Mage/src/main/java/mage/players/net/UserData.java +++ b/Mage/src/main/java/mage/players/net/UserData.java @@ -176,7 +176,10 @@ public class UserData implements Serializable { } public String getHistory() { - return "Matches:" + this.matchHistory + " Tourneys:" + this.tourneyHistory; + if (UserGroup.COMPUTER.equals(this.groupId)) { + return ""; + } + return "Matches: " + this.matchHistory + " (" + this.matchQuitRatio + "%) Tourneys: " + this.tourneyHistory + " (" + this.tourneyQuitRatio + "%)"; } public void setMatchHistory(String history) { diff --git a/Mage/src/main/java/mage/players/net/UserGroup.java b/Mage/src/main/java/mage/players/net/UserGroup.java index 58a61d3dff4..6bbda148b2b 100644 --- a/Mage/src/main/java/mage/players/net/UserGroup.java +++ b/Mage/src/main/java/mage/players/net/UserGroup.java @@ -12,7 +12,7 @@ public enum UserGroup { ADMIN(7), OWNER(15); - private int groupId; + private final int groupId; UserGroup(int groupId) { this.groupId = groupId;