- replaced DuelDialog with new DuelPlayersScreen which improves managment of player profiles (both human and AI).

- new avatar selection screen.
- improved player stats presentation.
- Now uses persistent AI personas with their own stats.
- If a duel consists of X games then is played as best of X instead of first to X.
- can now play a single game duel.
- improved layout of player tabs in DuelDecksScreen. Current score is now integrated into the tabs.
master
Lodici 2014-03-06 09:45:19 +00:00
parent b0856158c0
commit 363333adda
70 changed files with 3820 additions and 659 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

View File

Before

Width:  |  Height:  |  Size: 849 B

After

Width:  |  Height:  |  Size: 849 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

Before

Width:  |  Height:  |  Size: 687 B

After

Width:  |  Height:  |  Size: 687 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

View File

Before

Width:  |  Height:  |  Size: 362 B

After

Width:  |  Height:  |  Size: 362 B

View File

Before

Width:  |  Height:  |  Size: 519 B

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 737 B

View File

Before

Width:  |  Height:  |  Size: 465 B

After

Width:  |  Height:  |  Size: 465 B

View File

Before

Width:  |  Height:  |  Size: 550 B

After

Width:  |  Height:  |  Size: 550 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 233 B

After

Width:  |  Height:  |  Size: 233 B

View File

@ -6,7 +6,6 @@ import magic.data.DeckGenerators;
import magic.data.DeckUtils;
import magic.data.DuelConfig;
import magic.data.GeneralConfig;
import magic.data.History;
import magic.data.KeywordDefinitions;
import magic.model.MagicGameLog;
import magic.test.TestGameBuilder;
@ -43,6 +42,8 @@ public class MagicMain {
private static final String SCRIPTS_PATH = "scripts";
private static final String LOGS_PATH = "logs";
private static final String SAVED_DUELS_PATH = "duels";
private static final String PLAYER_PROFILES_PATH = "players";
private static final String AVATAR_SETS_PATH = "avatars";
private static final String GAME_PATH =
(System.getProperty("magarena.dir") != null ?
System.getProperty("magarena.dir") :
@ -113,9 +114,7 @@ public class MagicMain {
if (testGame != null) {
magicFrame.openGame(TestGameBuilder.buildGame(testGame));
}
// add "-DselfMode=true" VM argument for AI vs AI mode.
// in selfMode start game immediately based on configuration from duel.cfg
if (Boolean.getBoolean("selfMode")) {
if (MagicUtility.isAiVersusAi()) {
final DuelConfig config = DuelConfig.getInstance();
config.load();
magicFrame.newDuel(config);
@ -156,6 +155,14 @@ public class MagicMain {
return getDataPath(SAVED_DUELS_PATH);
}
public static String getPlayerProfilesPath() {
return getDataPath(PLAYER_PROFILES_PATH);
}
public static String getAvatarSetsPath() {
return getDataPath(AVATAR_SETS_PATH);
}
/**
* Gets path to a specified data directory. If the directory does not exist it
* attempts to create it. If that fails then it uses the GAME_PATH directory instead.
@ -201,7 +208,6 @@ public class MagicMain {
}
DeckUtils.createDeckFolder();
History.createHistoryFolder();
initializeEngine();
}

View File

@ -1,16 +1,43 @@
package magic;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.GradientPaint;
import java.awt.Paint;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
final public class MagicUtility {
private MagicUtility() {}
public static final boolean IS_WINDOWS_OS = System.getProperty("os.name").toLowerCase().startsWith("windows");
private static final Paint debugBorderPaint = new GradientPaint(0, 0, Color.red, 100, 100, Color.white, true);
public static void setBusyMouseCursor(final boolean b) {
MagicMain.rootFrame.setCursor(
b ? Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR) :
Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
public static void setDebugBorder(final JComponent component) {
component.setBorder(BorderFactory.createDashedBorder(debugBorderPaint));
}
public static boolean isTestGame() {
return (System.getProperty("testGame") != null);
}
public static boolean isDevMode() {
return Boolean.getBoolean("devMode");
}
/**
* add "-DselfMode=true" VM argument for AI vs AI mode.
*/
public static boolean isAiVersusAi() {
return Boolean.getBoolean("selfMode");
}
}

View File

@ -14,7 +14,7 @@ public enum MagicAIImpl {
MCTSC2("monte carlo tree search (cheat)", new MCTSAI2(true)),
;
private static final MagicAIImpl[] SUPPORTED_AIS = {MMAB, MMABC, MCTS, MCTSC, VEGAS, VEGASC};
public static final MagicAIImpl[] SUPPORTED_AIS = {MMAB, MMABC, MCTS, MCTSC, VEGAS, VEGASC};
private final String name;
private final MagicAI ai;
@ -49,4 +49,10 @@ public enum MagicAIImpl {
}
return names;
}
@Override
public String toString() {
return name;
}
}

View File

@ -5,6 +5,8 @@ import magic.ai.MagicAI;
import magic.ai.MagicAIImpl;
import magic.model.MagicColor;
import magic.model.MagicPlayerProfile;
import magic.model.player.PlayerProfile;
import magic.model.player.PlayerProfiles;
import java.io.File;
import java.io.IOException;
@ -19,9 +21,7 @@ public class DuelConfig {
private static final String ANY_TWO="**";
private static final String ANY_ONE="*";
private static final String CONFIG_FILENAME="duel.cfg";
private static final String AVATAR="avatar";
private static final String NAME="name";
private static final String CONFIG_FILENAME="newduel.cfg";
private static final String START_LIFE="life";
private static final String HAND_SIZE="hand";
private static final String GAMES="games";
@ -30,44 +30,46 @@ public class DuelConfig {
private static final String CUBE="cube";
private static final String AI="ai";
private int avatar;
private String name="Player";
private int startLife=20;
private int handSize=7;
private int games=7;
private String playerColors=ANY_THREE;
private String opponentColors=ANY_THREE;
private String cube=CubeDefinitions.DEFAULT_NAME;
private String ai="minimax";
// default values.
private int startLife = 20;
private int handSize = 7;
private int games = 7;
private String playerOneDeckGenerator = ANY_THREE;
private String playerTwoDeckGenerator = ANY_THREE;
private String cube = CubeDefinitions.getCubeNames()[0];
private String ai = "minimax";
private PlayerProfile playerOne = null;
private PlayerProfile playerTwo = null;
// CTR
public DuelConfig() {
// Ensure DuelConfig has valid PlayerProfile references.
// If missing then creates default profiles.
PlayerProfiles.refreshMap();
}
// CTR: copy constructor - a common way of creating a copy of an existing object.
public DuelConfig(final DuelConfig duelConfig) {
avatar=duelConfig.avatar;
startLife=duelConfig.startLife;
handSize=duelConfig.handSize;
games=duelConfig.games;
playerColors=duelConfig.playerColors;
opponentColors=duelConfig.opponentColors;
playerOneDeckGenerator=duelConfig.playerOneDeckGenerator;
playerTwoDeckGenerator=duelConfig.playerTwoDeckGenerator;
ai=duelConfig.ai;
}
public int getAvatar() {
return avatar;
public PlayerProfile getPlayerOneProfile() {
return playerOne;
}
public void setPlayerOneProfile(PlayerProfile playerProfile) {
this.playerOne = playerProfile;
}
public void setAvatar(final int avatar) {
this.avatar = avatar;
public PlayerProfile getPlayerTwoProfile() {
return playerTwo;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name=name;
public void setPlayerTwoProfile(PlayerProfile playerProfile) {
this.playerTwo = playerProfile;
}
public int getStartLife() {
@ -94,7 +96,7 @@ public class DuelConfig {
return games;
}
private static MagicPlayerProfile getProfile(final String colorText) {
private static MagicPlayerProfile getMagicPlayerProfile(final String colorText) {
if (ANY_DECK.equals(colorText)) {
return new MagicPlayerProfile("");
} else if (ANY_THREE.equals(colorText)) {
@ -110,28 +112,28 @@ public class DuelConfig {
return new MagicPlayerProfile(colorText);
}
public String getPlayerColors() {
return playerColors;
public MagicPlayerProfile getMagicPlayerProfile() {
return getMagicPlayerProfile(playerOneDeckGenerator);
}
public void setPlayerColors(final String colors) {
playerColors=colors;
public String getPlayerOneDeckGenerator() {
return playerOneDeckGenerator;
}
public MagicPlayerProfile getPlayerProfile() {
return getProfile(playerColors);
public void setPlayerOneDeckGenerator(final String deckGenerator) {
playerOneDeckGenerator = deckGenerator;
}
public String getOpponentColors() {
return opponentColors;
public String getPlayerTwoDeckGenerator() {
return playerTwoDeckGenerator;
}
public void setOpponentColors(final String colors) {
opponentColors=colors;
public void setPlayerTwoDeckGenerator(final String deckGenerator) {
playerTwoDeckGenerator = deckGenerator;
}
public MagicPlayerProfile getOpponentProfile() {
return getProfile(opponentColors);
public MagicPlayerProfile getMagicOpponentProfile() {
return getMagicPlayerProfile(playerTwoDeckGenerator);
}
public String getCube() {
@ -156,31 +158,33 @@ public class DuelConfig {
}
public void load(final Properties properties) {
avatar=Integer.parseInt(properties.getProperty(AVATAR,Integer.toString(avatar)));
name=properties.getProperty(NAME,name);
setPlayerOneProfile(PlayerProfile.getHumanPlayer(properties.getProperty("HumanPlayer")));
setPlayerTwoProfile(PlayerProfile.getAiPlayer(properties.getProperty("AiPlayer")));
startLife=Integer.parseInt(properties.getProperty(START_LIFE,Integer.toString(startLife)));
handSize=Integer.parseInt(properties.getProperty(HAND_SIZE,Integer.toString(handSize)));
games=Integer.parseInt(properties.getProperty(GAMES,Integer.toString(games)));
playerColors=properties.getProperty(PLAYER,playerColors);
opponentColors=properties.getProperty(OPPONENT,opponentColors);
playerOneDeckGenerator=properties.getProperty(PLAYER,playerOneDeckGenerator);
playerTwoDeckGenerator=properties.getProperty(OPPONENT,playerTwoDeckGenerator);
cube=properties.getProperty(CUBE,cube);
ai=properties.getProperty(AI,ai);
}
public void load() {
load(FileIO.toProp(getConfigFile()));
final File configFile = getConfigFile();
final Properties properties = configFile.exists() ? FileIO.toProp(configFile) : new Properties();
load(properties);
}
public void save(final Properties properties) {
properties.setProperty(AVATAR,Integer.toString(avatar));
properties.setProperty(NAME,name);
properties.setProperty(START_LIFE,Integer.toString(startLife));
properties.setProperty(HAND_SIZE,Integer.toString(handSize));
properties.setProperty("HumanPlayer", getPlayerOneProfile().getId());
properties.setProperty("AiPlayer", getPlayerTwoProfile().getId());
properties.setProperty(START_LIFE, Integer.toString(startLife));
properties.setProperty(HAND_SIZE, Integer.toString(handSize));
properties.setProperty(GAMES, Integer.toString(games));
properties.setProperty(PLAYER,playerColors);
properties.setProperty(OPPONENT,opponentColors);
properties.setProperty(CUBE,cube);
properties.setProperty(AI,ai);
properties.setProperty(PLAYER, playerOneDeckGenerator);
properties.setProperty(OPPONENT, playerTwoDeckGenerator);
properties.setProperty(CUBE, cube);
properties.setProperty(AI, ai);
}
public void save() {

View File

@ -19,15 +19,22 @@ public class IconImages {
public static final BufferedImage OPAL=loadImage("textures/opal.jpg");
public static final BufferedImage OPAL2=loadImage("textures/opal2.jpg");
// Icons used by various components of AbstractScreen.
public static final ImageIcon HEADER_ICON = loadIcon("headerIcon.png");
public static final ImageIcon OPTIONS_ICON = loadIcon("book.png");
public static final ImageIcon REFRESH_ICON = loadIcon("refresh.png");
public static final ImageIcon MULLIGAN_ICON = loadIcon("mulligan.png");
public static final ImageIcon HAND_ICON = loadIcon("hand.png");
public static final ImageIcon TILED_ICON = loadIcon("tiled.png");
public static final ImageIcon SAVE_ICON = loadIcon("save.png");
public static final ImageIcon LOAD_ICON = loadIcon("load.png");
// White transparent icons used by various components of AbstractScreen.
public static final ImageIcon HEADER_ICON = loadIcon("headerIcon.png");
public static final ImageIcon OPTIONS_ICON = loadIcon("w_book.png");
public static final ImageIcon REFRESH_ICON = loadIcon("w_refresh.png");
public static final ImageIcon MULLIGAN_ICON = loadIcon("w_mulligan.png");
public static final ImageIcon HAND_ICON = loadIcon("w_hand.png");
public static final ImageIcon TILED_ICON = loadIcon("w_tiled.png");
public static final ImageIcon SAVE_ICON = loadIcon("w_save.png");
public static final ImageIcon LOAD_ICON = loadIcon("w_load.png");
public static final ImageIcon SWAP_ICON = loadIcon("w_swap.png");
public static final ImageIcon DECK_ICON = loadIcon("w_deck.png");
public static final ImageIcon NEXT_ICON = loadIcon("w_next.png");
public static final ImageIcon BACK_ICON = loadIcon("w_back.png");
public static final ImageIcon LIFE_ICON = loadIcon("w_life.png");
public static final ImageIcon TARGET_ICON = loadIcon("w_target.png");
public static final ImageIcon CUBE_ICON = loadIcon("w_cube.png");
public static final ImageIcon ARENA=loadIcon("arena.png");
public static final ImageIcon CUBE=loadIcon("cube.png");

View File

@ -1,23 +1,23 @@
package magic.model;
import magic.MagicMain;
import magic.MagicUtility;
import magic.ai.MagicAI;
import magic.data.CubeDefinitions;
import magic.data.DeckUtils;
import magic.data.DuelConfig;
import magic.data.GeneralConfig;
import magic.data.History;
import magic.generator.DefaultDeckGenerator;
import magic.model.phase.MagicDefaultGameplay;
import magic.ui.theme.Theme;
import magic.ui.theme.ThemeFactory;
import magic.model.player.PlayerProfile;
import magic.ui.viewer.DeckStrengthViewer;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Properties;
import java.util.TreeSet;
public class MagicDuel {
@ -26,10 +26,8 @@ public class MagicDuel {
private static final String PLAYED="played";
private static final String WON="won";
private static final String START="start";
private static final String COMPUTER="Computer";
private final DuelConfig configuration;
private final History history;
private MagicPlayerDefinition[] playerDefinitions;
private MagicAI[] ais;
private int opponentIndex;
@ -41,7 +39,6 @@ public class MagicDuel {
public MagicDuel(final DuelConfig configuration) {
this.configuration=configuration;
history = new History(this);
ais=configuration.getPlayerAIs();
restart();
}
@ -59,10 +56,6 @@ public class MagicDuel {
return configuration;
}
private MagicPlayerDefinition getOpponent() {
return playerDefinitions[opponentIndex];
}
public int getGameNr() {
return gameNr;
}
@ -87,10 +80,6 @@ public class MagicDuel {
this.startPlayer=startPlayer;
}
private int getStartPlayer() {
return startPlayer;
}
public void setAIs(final MagicAI[] aAIs) {
this.ais = aAIs;
}
@ -126,7 +115,16 @@ public class MagicDuel {
}
public boolean isFinished() {
return getGamesPlayed()==getGamesTotal();
if (MagicUtility.isAiVersusAi()) {
return getGamesPlayed()==getGamesTotal();
} else {
// if a duel consists of a total of X games, then in an interactive
// game it should be "best of" X games, not first to X.
final int player1GamesWon = getGamesWon();
final int player2GamesWon = getGamesPlayed() - player1GamesWon;
final int gamesRequiredToWin = (int)Math.ceil(getGamesTotal()/2.0);
return (player1GamesWon >= gamesRequiredToWin) || (player2GamesWon >= gamesRequiredToWin);
}
}
void advance(final boolean won, final MagicGame game) {
@ -143,35 +141,17 @@ public class MagicDuel {
opponentIndex++;
determineStartPlayer();
}
if (!DeckStrengthViewer.isRunning()) {
history.update(won,game,configuration);
}
}
private static List<Integer> getAvatarIndices(final int avatars) {
final List<Integer> indices=new ArrayList<Integer>();
for (int index=0;index<avatars;index++) {
indices.add(index);
if (!DeckStrengthViewer.isRunning() && !MagicUtility.isTestGame()) {
configuration.getPlayerOneProfile().getStats().update(won, game.getPlayer(0), game);
configuration.getPlayerTwoProfile().getStats().update(!won, game.getPlayer(1), game);
}
return indices;
}
private MagicPlayerDefinition[] createPlayers() {
final Theme theme=ThemeFactory.getInstance().getCurrentTheme();
final List<Integer> avatars=getAvatarIndices(theme.getNumberOfAvatars());
final MagicPlayerDefinition[] players=new MagicPlayerDefinition[2];
final int playerFace=configuration.getAvatar()%theme.getNumberOfAvatars();
final MagicPlayerDefinition player=new MagicPlayerDefinition(configuration.getName(),false,configuration.getPlayerProfile(),playerFace);
players[0]=player;
avatars.remove(playerFace);
final int findex=MagicRandom.nextRNGInt(avatars.size());
final Integer computerFace=avatars.get(findex);
players[1]=new MagicPlayerDefinition(COMPUTER,true,configuration.getOpponentProfile(),computerFace);
players[0] = new MagicPlayerDefinition(configuration.getPlayerOneProfile().getPlayerName(), false, configuration.getMagicPlayerProfile());
players[1] = new MagicPlayerDefinition(configuration.getPlayerTwoProfile().getPlayerName(), true,configuration.getMagicOpponentProfile());
return players;
}
@ -212,6 +192,7 @@ public class MagicDuel {
return playerDefinitions;
}
// only used by magic.test classes.
public void setPlayers(final MagicPlayerDefinition[] aPlayerDefinitions) {
this.playerDefinitions=aPlayerDefinitions;
}
@ -241,11 +222,13 @@ public class MagicDuel {
public void initialize() {
playerDefinitions=createPlayers();
buildDecks();
history.loadHistory(configuration.getName());
}
public static final File getDuelFile(final String filename) {
return new File(MagicMain.getSavedDuelsPath(), filename);
}
public static final File getDuelFile() {
return new File(MagicMain.getSavedDuelsPath(),"duel.txt");
return getDuelFile("saved.duel");
}
private static String getPlayerPrefix(final int index) {
@ -267,16 +250,25 @@ public class MagicDuel {
}
public void save(final File file) {
final Properties properties=new Properties();
final Properties properties = getNewSortedProperties();
save(properties);
try { //save to file
try {
magic.data.FileIO.toFile(file, properties, "Duel");
System.err.println("Saved duel");
} catch (final IOException ex) {
System.err.println("ERROR! Unable save duel to " + file);
}
}
@SuppressWarnings("serial")
private Properties getNewSortedProperties() {
return new Properties() {
@Override
public synchronized Enumeration<Object> keys() {
return Collections.enumeration(new TreeSet<Object>(super.keySet()));
}
};
}
private void load(final Properties properties) {
configuration.load(properties);
@ -291,7 +283,6 @@ public class MagicDuel {
playerDefinitions[index]=new MagicPlayerDefinition();
playerDefinitions[index].load(properties,getPlayerPrefix(index));
}
history.loadHistory(configuration.getName());
}
public void load(final File file) {
@ -305,4 +296,18 @@ public class MagicDuel {
gamesWon=0;
determineStartPlayer();
}
public PlayerProfile getWinningPlayerProfile() {
if (!isFinished()) {
return null;
} else {
final int playerOneGamesWon = getGamesWon();
final int playerTwoGamesWon = getGamesPlayed() - playerOneGamesWon;
if (playerOneGamesWon > playerTwoGamesWon) {
return getConfiguration().getPlayerOneProfile();
} else {
return getConfiguration().getPlayerTwoProfile();
}
}
}
}

View File

@ -102,6 +102,7 @@ public class MagicGame {
private long[] keys;
private long stateId;
private long time = 1000000;
private boolean isConceded = false;
public static MagicGame getInstance() {
@ -1289,4 +1290,11 @@ public class MagicGame {
executeTrigger(trigger,permanent,permanent,data);
}
}
public void setConceded(final boolean b) {
isConceded = true;
}
public boolean isConceded() {
return isConceded;
}
}

View File

@ -3,7 +3,7 @@ package magic.model;
import magic.data.CardDefinitions;
import magic.data.DeckGenerators;
import magic.generator.DefaultDeckGenerator;
import magic.ui.theme.PlayerAvatar;
import java.util.Properties;
public class MagicPlayerDefinition {
@ -14,21 +14,24 @@ public class MagicPlayerDefinition {
private static final String NAME="name";
private static final String ARTIFICIAL="artificial";
private static final String COLORS="colors";
private static final String FACE="face";
private String name;
private boolean artificial;
private MagicPlayerProfile profile;
private int face;
private final MagicDeck deck = new MagicDeck();
private PlayerAvatar avatar;
MagicPlayerDefinition() {}
MagicPlayerDefinition() {
public MagicPlayerDefinition(final String name,final boolean artificial,final MagicPlayerProfile profile,final int face) {
}
public MagicPlayerDefinition(final String name,final boolean artificial,final MagicPlayerProfile profile) {
this.name=name;
this.artificial=artificial;
this.profile=profile;
this.face=face;
}
public MagicPlayerDefinition(final String name,final boolean artificial,final MagicPlayerProfile profile,final int face) {
this(name, artificial, profile);
this.avatar = new PlayerAvatar(face);
}
public String getName() {
@ -51,10 +54,6 @@ public class MagicPlayerDefinition {
return profile;
}
public int getFace() {
return face;
}
private void addBasicLandsToDeck() {
// Calculate statistics per color.
final int[] colorCount=new int[MagicColor.NR_COLORS];
@ -140,7 +139,6 @@ public class MagicPlayerDefinition {
artificial=Boolean.parseBoolean(properties.getProperty(prefix+ARTIFICIAL,"true"));
final String colors=properties.getProperty(prefix+COLORS,"");
profile=new MagicPlayerProfile(colors);
face=Integer.parseInt(properties.getProperty(prefix+FACE));
final MagicDeck unsupported = new MagicDeck();
deck.clear();
@ -164,11 +162,18 @@ public class MagicPlayerDefinition {
properties.setProperty(prefix+NAME,name);
properties.setProperty(prefix+ARTIFICIAL,Boolean.toString(artificial));
properties.setProperty(prefix+COLORS,getProfile().getColorText());
properties.setProperty(prefix+FACE,Integer.toString(face));
int index=1;
for (final MagicCardDefinition cardDefinition : deck) {
properties.setProperty(getDeckPrefix(prefix,index++),cardDefinition.getFullName());
}
}
public void setAvatar(final PlayerAvatar avatar) {
this.avatar = avatar;
}
public PlayerAvatar getAvatar() {
return avatar;
}
}

View File

@ -0,0 +1,76 @@
package magic.model.player;
import java.util.Properties;
import magic.ai.MagicAIImpl;
public class AiPlayer extends PlayerProfile {
private static final String PLAYER_TYPE = "ai";
private static final String KEY_EXTRA_LIFE = "extraLife";
private static final String KEY_AI_LEVEL = "aiLevel";
private static final String KEY_AI_TYPE = "aiType";
private static final int DEFAULT_EXTRA_LIFE = 0;
private static final int DEFAULT_AI_LEVEL = 6;
private static final MagicAIImpl DEFAULT_AI_TYPE = MagicAIImpl.MMAB;
private int extraLife = DEFAULT_EXTRA_LIFE;
private int aiLevel = DEFAULT_AI_LEVEL;
private MagicAIImpl aiType = DEFAULT_AI_TYPE;
public AiPlayer(final String profileId) {
super(profileId);
loadProperties();
}
public AiPlayer() {
this(null);
}
public int getExtraLife() {
return extraLife;
}
public void setExtraLife(final int value) {
extraLife = value;
}
public int getAiLevel() {
return aiLevel;
}
public void setAiLevel(final int value) {
aiLevel = value;
}
public MagicAIImpl getAiType() {
return aiType;
}
public void setAiType(final MagicAIImpl value) {
aiType = value;
}
@Override
public void save() {
final Properties properties = new Properties();
properties.setProperty(KEY_EXTRA_LIFE, String.valueOf(getExtraLife()));
properties.setProperty(KEY_AI_LEVEL, String.valueOf(getAiLevel()));
properties.setProperty(KEY_AI_TYPE, getAiType().name());
saveProperties(properties);
}
@Override
protected void loadProperties() {
final Properties properties = loadPlayerProperties();
extraLife = Integer.parseInt(properties.getProperty(KEY_EXTRA_LIFE, Integer.toString(DEFAULT_EXTRA_LIFE)));
aiLevel = Integer.parseInt(properties.getProperty(KEY_AI_LEVEL, Integer.toString(DEFAULT_AI_LEVEL)));
aiType = MagicAIImpl.valueOf(properties.getProperty(KEY_AI_TYPE, DEFAULT_AI_TYPE.name()));
}
/* (non-Javadoc)
* @see magic.model.player.PlayerProfile#getPlayerType()
*/
@Override
protected String getPlayerType() {
return PLAYER_TYPE;
}
}

View File

@ -0,0 +1,36 @@
package magic.model.player;
import java.util.Properties;
public class HumanPlayer extends PlayerProfile {
private static final String PLAYER_TYPE = "human";
public HumanPlayer(final String profileId) {
super(profileId);
loadProperties();
}
public HumanPlayer() {
this(null);
}
@Override
public void save() {
saveProperties(new Properties());
}
@Override
protected void loadProperties() {
loadPlayerProperties();
}
/* (non-Javadoc)
* @see magic.model.player.PlayerProfile#getPlayerType()
*/
@Override
protected String getPlayerType() {
return PLAYER_TYPE;
}
}

View File

@ -0,0 +1,143 @@
package magic.model.player;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Properties;
import magic.MagicMain;
import magic.data.FileIO;
import magic.data.IconImages;
import magic.model.MagicGameReport;
import magic.ui.theme.PlayerAvatar;
public abstract class PlayerProfile {
private static String lastId = "";
private Path profilePath = null;
private String playerName = "";
private PlayerStatistics stats;
private PlayerAvatar avatar;
abstract protected void loadProperties();
abstract public void save();
abstract protected String getPlayerType();
protected PlayerProfile(final String profileId) {
setProfilePath(profileId == null ? PlayerProfile.getNewPlayerProfileId() : profileId);
loadStats();
loadAvatar();
}
public String getId() {
return profilePath.getFileName().toString();
}
private void setProfilePath(final String profileId) {
profilePath = Paths.get(MagicMain.getPlayerProfilesPath()).resolve(getPlayerType());
verifyProfilePath();
profilePath = profilePath.resolve(profileId);
}
private void verifyProfilePath() {
if (!Files.exists(profilePath)) {
try {
Files.createDirectory(profilePath);
} catch (IOException e) {
MagicGameReport.reportException(Thread.currentThread(), e);
}
}
}
protected void saveProperties(final Properties properties) {
properties.setProperty("playerName", String.valueOf(getPlayerName()));
final File file = new File(getProfilePath().resolve("player.profile").toString());
verifyProfilePath();
try {
FileIO.toFile(file, properties, "Player profile settings");
} catch (IOException e) {
MagicGameReport.reportException(Thread.currentThread(), e);
}
}
protected Properties loadPlayerProperties() {
final File propertiesFile = new File(getProfilePath().resolve("player.profile").toString());
final Properties properties = propertiesFile.exists() ? FileIO.toProp(propertiesFile) : new Properties();
playerName = properties.getProperty("playerName", "");
return properties;
}
public Path getProfilePath() {
return profilePath;
}
public String getPlayerName() {
return playerName;
}
public void setPlayerName(final String playerName) {
this.playerName = playerName == null ? "" : playerName;
}
public PlayerStatistics getStats() {
return stats;
}
public PlayerAvatar getAvatar() {
return avatar;
}
private void loadAvatar() {
final File file = new File(profilePath.resolve("player.avatar").toString());
if (file.exists()) {
avatar = new PlayerAvatar(FileIO.toImg(file, IconImages.MISSING));
} else {
avatar = new PlayerAvatar(IconImages.MISSING);
}
}
private void loadStats() {
stats = new PlayerStatistics(this);
}
public static String getNewPlayerProfileId() {
String id = Long.toHexString(System.currentTimeMillis()).toUpperCase();
while (id.equals(lastId)) {
// wait a bit in order to generate a unique id based on current time.
// required because currentTimeMillis() granularity dependent on OS.
sleep(100);
id = Long.toHexString(System.currentTimeMillis()).toUpperCase();
}
lastId = id;
return id;
}
private static void sleep(final long milliseconds) {
try {
Thread.sleep(milliseconds);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static PlayerProfile getHumanPlayer(final String playerId) {
if (playerId != null && PlayerProfiles.getPlayerProfile(playerId) != null) {
return new HumanPlayer(playerId);
} else {
return PlayerProfiles.getDefaultHumanPlayer();
}
}
public static PlayerProfile getAiPlayer(final String playerId) {
if (playerId != null && PlayerProfiles.getPlayerProfile(playerId) != null) {
return new AiPlayer(playerId);
} else {
return PlayerProfiles.getDefaultAiPlayer();
}
}
}

View File

@ -0,0 +1,179 @@
package magic.model.player;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.DirectoryStream.Filter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import magic.MagicMain;
import magic.ai.MagicAIImpl;
import magic.model.MagicGameReport;
public final class PlayerProfiles {
private PlayerProfiles() {}
// default AI avatars.
private static final Path AVATARS_PATH = Paths.get(MagicMain.getAvatarSetsPath());
private static final Path AVATAR_LesVegas = AVATARS_PATH.resolve("tux").resolve("tux25.png");
private static final Path AVATAR_MontyCarlo = AVATARS_PATH.resolve("default").resolve("face09.png");
private static final Path AVATAR_MiniMax = AVATARS_PATH.resolve("default").resolve("face18.png");
private static final Path profilesPath = Paths.get(MagicMain.getPlayerProfilesPath());
private static final HashMap<String, PlayerProfile> profilesMap = new HashMap<String, PlayerProfile>();
public static void refreshMap() {
setProfilesMap();
}
private static void setProfilesMap() {
profilesMap.clear();
// Humans
for (Path path : getProfilePaths("human")) {
final String profileId = path.getFileName().toString();
final HumanPlayer player = new HumanPlayer(profileId);
profilesMap.put(profileId, player);
}
// AIs
for (Path path : getProfilePaths("ai")) {
final String profileId = path.getFileName().toString();
final AiPlayer player = new AiPlayer(profileId);
profilesMap.put(profileId, player);
}
}
private static List<Path> getProfilePaths(final String playerType) {
final Path playersPath = profilesPath.resolve(playerType);
List<Path> profilePaths = getDirectoryPaths(playersPath);
if (profilePaths.size() == 0) {
try {
if (playerType.equals("human")) {
createDefaultHumanPlayerProfiles();
} else {
createDefaultAiPlayerProfiles();
}
profilePaths = getDirectoryPaths(playersPath);
} catch (IOException e) {
MagicGameReport.reportException(Thread.currentThread(), e);
}
}
return profilePaths;
}
private static List<Path> getDirectoryPaths(final Path rootPath) {
final List<Path> paths = new ArrayList<Path>();
if (Files.exists(rootPath)) {
try (DirectoryStream<Path> ds = Files.newDirectoryStream(rootPath, new DirectoriesFilter())) {
for (Path p : ds) {
paths.add(p.getFileName());
}
} catch (IOException e) {
e.printStackTrace();
}
}
return paths;
}
private static class DirectoriesFilter implements Filter<Path> {
@Override
public boolean accept(Path entry) throws IOException {
return Files.isDirectory(entry);
}
}
private static void createDefaultHumanPlayerProfiles() throws IOException {
final HumanPlayer profile = new HumanPlayer();
profile.setPlayerName(getDefaultPlayerProfileName());
profile.save();
}
private static String getDefaultPlayerProfileName() {
final String systemUserName = System.getProperty("user.name");
return systemUserName == null ? "Player" : systemUserName;
}
private static void createDefaultAiPlayerProfiles() throws IOException {
// Les Vegas
AiPlayer profile = new AiPlayer();
profile.setPlayerName("Les Vegas");
profile.setAiType(MagicAIImpl.VEGAS);
profile.setAiLevel(6);
profile.save();
setPlayerAvatar(profile, PlayerProfiles.AVATAR_LesVegas);
// Mini Max
profile = new AiPlayer();
profile.setPlayerName("Mini Max");
profile.setAiType(MagicAIImpl.MMAB);
profile.setAiLevel(6);
profile.save();
setPlayerAvatar(profile, PlayerProfiles.AVATAR_MiniMax);
// Monty Carlo
profile = new AiPlayer();
profile.setPlayerName("Monty Carlo");
profile.setAiType(MagicAIImpl.MCTS);
profile.setAiLevel(6);
profile.save();
setPlayerAvatar(profile, PlayerProfiles.AVATAR_MontyCarlo);
}
public static void setPlayerAvatar(final PlayerProfile profile, final Path avatarPath) {
final Path targetPath = profile.getProfilePath().resolve("player.avatar");
try {
Files.copy(avatarPath, targetPath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static PlayerProfile getDefaultHumanPlayer() {
return getHumanPlayerProfiles().values().iterator().next();
}
public static PlayerProfile getDefaultAiPlayer() {
return getAiPlayerProfiles().values().iterator().next();
}
public static HashMap<String, PlayerProfile> getHumanPlayerProfiles() {
final HashMap<String, PlayerProfile> filteredProfiles = new HashMap<String, PlayerProfile>();
final Iterator<PlayerProfile> itr = profilesMap.values().iterator();
while (itr.hasNext()) {
final PlayerProfile profile = itr.next();
if (profile instanceof HumanPlayer) {
filteredProfiles.put(profile.getId(), profile);
}
}
return filteredProfiles;
}
public static HashMap<String, PlayerProfile> getAiPlayerProfiles() {
final HashMap<String, PlayerProfile> filteredProfiles = new HashMap<String, PlayerProfile>();
final Iterator<PlayerProfile> itr = profilesMap.values().iterator();
while (itr.hasNext()) {
final PlayerProfile profile = itr.next();
if (profile instanceof AiPlayer) {
filteredProfiles.put(profile.getId(), profile);
}
}
return filteredProfiles;
}
/**
* @param duelConfigId
* @return
*/
public static PlayerProfile getPlayerProfile(String duelConfigId) {
return profilesMap.get(duelConfigId);
}
public static HashMap<String, PlayerProfile> getPlayerProfiles() {
return profilesMap;
}
}

View File

@ -0,0 +1,243 @@
package magic.model.player;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import magic.data.FileIO;
import magic.model.MagicCardDefinition;
import magic.model.MagicColor;
import magic.model.MagicDeck;
import magic.model.MagicGame;
import magic.model.MagicPlayer;
import magic.model.player.PlayerProfile;
public class PlayerStatistics {
private static final String TIMESTAMP = "timestamp";
private static final String GAMES_PLAYED = "gamesPlayed";
private static final String GAMES_WON = "gamesWon";
private static final String GAMES_CONCEDED = "gamesConceded";
private static final String DUELS_PLAYED = "duelsPlayed";
private static final String DUELS_WON = "duelsWon";
private static final String TURNS_PLAYED = "turnsPlayed";
private static final String COLOR_BLACK = "colorBlack";
private static final String COLOR_BLUE = "colorBlue";
private static final String COLOR_GREEN = "colorGreen";
private static final String COLOR_RED = "colorRed";
private static final String COLOR_WHITE = "colorWhite";
private long millisecTimestamp;
private final Path statsFilePath;
private final PlayerProfile playerProfile;
public int gamesPlayed;
public int gamesWon;
public int gamesConceded;
public int turnsPlayed;
public int duelsPlayed;
public int duelsWon;
public int colorBlack;
public int colorBlue;
public int colorGreen;
public int colorRed;
public int colorWhite;
public PlayerStatistics(final PlayerProfile playerProfile) {
this.playerProfile = playerProfile;
statsFilePath = playerProfile.getProfilePath().resolve("player.stats");
loadStats();
}
private void loadStats() {
final File statsFile = new File(statsFilePath.toString());
final Properties properties = statsFile.exists() ? FileIO.toProp(statsFile) : new Properties();
gamesPlayed = Integer.parseInt(properties.getProperty(GAMES_PLAYED,"0"));
gamesWon = Integer.parseInt(properties.getProperty(GAMES_WON,"0"));
gamesConceded = Integer.parseInt(properties.getProperty(GAMES_CONCEDED,"0"));
turnsPlayed = Integer.parseInt(properties.getProperty(TURNS_PLAYED,"0"));
duelsPlayed = Integer.parseInt(properties.getProperty(DUELS_PLAYED,"0"));
duelsWon = Integer.parseInt(properties.getProperty(DUELS_WON,"0"));
colorBlack = Integer.parseInt(properties.getProperty(COLOR_BLACK,"0"));
colorBlue = Integer.parseInt(properties.getProperty(COLOR_BLUE,"0"));
colorGreen = Integer.parseInt(properties.getProperty(COLOR_GREEN,"0"));
colorRed = Integer.parseInt(properties.getProperty(COLOR_RED,"0"));
colorWhite = Integer.parseInt(properties.getProperty(COLOR_WHITE,"0"));
millisecTimestamp = Long.parseLong(properties.getProperty(TIMESTAMP, "0"));
}
public void save() {
final Properties properties = new Properties();
properties.setProperty(GAMES_PLAYED, String.valueOf(gamesPlayed));
properties.setProperty(GAMES_WON, String.valueOf(gamesWon));
properties.setProperty(GAMES_CONCEDED, String.valueOf(gamesConceded));
properties.setProperty(TURNS_PLAYED, String.valueOf(turnsPlayed));
properties.setProperty(DUELS_PLAYED, String.valueOf(duelsPlayed));
properties.setProperty(DUELS_WON, String.valueOf(duelsWon));
properties.setProperty(COLOR_BLACK, String.valueOf(colorBlack));
properties.setProperty(COLOR_BLUE, String.valueOf(colorBlue));
properties.setProperty(COLOR_GREEN, String.valueOf(colorGreen));
properties.setProperty(COLOR_RED, String.valueOf(colorRed));
properties.setProperty(COLOR_WHITE, String.valueOf(colorWhite));
properties.setProperty(TIMESTAMP, String.valueOf(System.currentTimeMillis()));
final File file = new File(statsFilePath.toString());
try {
FileIO.toFile(file, properties, "Player Statistics");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void update(
final boolean isPlayerWinner,
final MagicPlayer player,
final MagicGame game) {
gamesPlayed++;
if (isPlayerWinner) {
gamesWon++;
}
if (!player.getPlayerDefinition().isArtificial()) {
if (game.isConceded()) {
gamesConceded++;
}
}
turnsPlayed += game.getTurn();
if (game.getDuel().isFinished()) {
duelsPlayed++;
if (isPlayerWinner) {
duelsWon++;
}
}
final int[] colorCount = new int[MagicColor.NR_COLORS];
final MagicDeck deck = player.getPlayerDefinition().getDeck();
for (final MagicCardDefinition card : deck) {
if (!card.isLand()) {
for (final MagicColor color : MagicColor.values()) {
if (color.hasColor(card.getColorFlags())) {
colorCount[color.ordinal()]++;
switch (color) {
case Black:
colorBlack++;
break;
case Blue:
colorBlue++;
break;
case Green:
colorGreen++;
break;
case Red:
colorRed++;
break;
case White:
colorWhite++;
break;
}
}
}
}
}
save();
}
@Override
public String toString() {
final int gamesLost = gamesPlayed - gamesWon;
final int gamesWinPercentage = getPercentage(gamesWon, gamesPlayed);
final int averageTurns = (gamesPlayed > 0) ? turnsPlayed / gamesPlayed : 0;
final int duelsLost = duelsPlayed - duelsWon;
final int duelsWinPercentage = getPercentage(duelsWon, duelsPlayed);
final int[] colorCount = new int[MagicColor.NR_COLORS];
colorCount[0] = colorWhite;
colorCount[1] = colorBlue;
colorCount[2] = colorBlack;
colorCount[3] = colorGreen;
colorCount[4] = colorRed;
int mostCount = Integer.MIN_VALUE;
MagicColor mostColor = null;
for (final MagicColor color : MagicColor.values()) {
final int count = colorCount[color.ordinal()];
if (count > mostCount) {
mostCount = count;
mostColor = color;
}
}
final boolean showStatValues = (gamesPlayed > 0);
final StatsFormatter f = new StatsFormatter(showStatValues);
final StringBuilder sb = new StringBuilder();
sb.append(f.getStatLine("Last played:\t", f.getTimestampString(millisecTimestamp)));
sb.append(f.getStatLine("\nDuels completed:\t", duelsPlayed));
sb.append(f.getStatLine("\nDuels won / lost:\t", duelsWon, " / ", duelsLost, " (", duelsWinPercentage, "%)"));
sb.append(f.getStatLine("\nGames played:\t", gamesPlayed));
sb.append(f.getStatLine("\nGames won / lost\t", gamesWon, " / ", gamesLost, " (", gamesWinPercentage, "%)"));
sb.append(f.getStatLine("\nGames conceded:\t", playerProfile instanceof HumanPlayer ? gamesConceded : StatsFormatter.NO_VALUE));
sb.append(f.getStatLine("\nTurns played:\t", turnsPlayed));
sb.append(f.getStatLine("\nAverage turns per game:\t", averageTurns));
sb.append(f.getStatLine("\nMost used color:\t", mostColor.getName()));
return sb.toString();
}
private static final int getPercentage(final int value, final int total) {
return total>0 ? (value*100)/total : 0;
}
public String getLastPlayed() {
final StatsFormatter f = new StatsFormatter(gamesPlayed > 0);
return f.getTimestampString(millisecTimestamp);
}
private class StatsFormatter {
public static final String NO_VALUE = "---";
private final boolean showValues;
public StatsFormatter(final boolean showValues) {
this.showValues = showValues;
}
public String getStatLine(final String stat, final Object...values) {
final StringBuilder sb = new StringBuilder(stat);
if (showValues) {
for (Object obj : values) {
sb.append(obj);
}
} else {
sb.append(NO_VALUE);
}
return sb.toString();
}
public String getTimestampString(final long millisecs) {
if (millisecs > 0) {
final Date timestampDate = new Date(millisecTimestamp);
String timestampString = new SimpleDateFormat("yyyy-MM-dd").format(timestampDate);
final String currentString = new SimpleDateFormat("yyyy-MM-dd").format(System.currentTimeMillis());
if (timestampString.equals(currentString)) {
timestampString = new SimpleDateFormat("HH:mm").format(timestampDate);
}
return timestampString;
} else {
return NO_VALUE;
}
}
}
}

View File

@ -0,0 +1,67 @@
package magic.ui;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.ImageIcon;
import magic.data.IconImages;
import magic.ui.theme.PlayerAvatar;
public class AvatarImageSet {
private final static String IMAGES_FILTER = "*.{png,jpg}";
private final Path path;
private ImageIcon sampleImage = IconImages.MISSING_ICON;
public AvatarImageSet(final Path path) {
this.path = path;
loadSampleImage();
}
public String getName() {
return path.getFileName().toString();
}
public ImageIcon getSampleImage() {
return sampleImage;
}
private void loadSampleImage() {
// find first image file in directory using a try-with-resource block for safety.
try (DirectoryStream<Path> ds = Files.newDirectoryStream(this.path, IMAGES_FILTER)) {
final Iterator<Path> itr = ds.iterator();
if (itr.hasNext()) {
final String filePath = itr.next().toAbsolutePath().toString();
final InputStream ins = new FileInputStream(new File(filePath));
final BufferedImage image = magic.data.FileIO.toImg(ins, IconImages.MISSING);
this.sampleImage = new ImageIcon(magic.ui.utility.GraphicsUtilities.scale(image, PlayerAvatar.MEDIUM_SIZE, PlayerAvatar.MEDIUM_SIZE));
}
} catch (IOException e) {
e.printStackTrace();
}
}
public List<Path> getImagePaths() {
final List<Path> paths = new ArrayList<Path>();
try (DirectoryStream<Path> ds = Files.newDirectoryStream(this.path, IMAGES_FILTER)) {
for (Path path : ds) {
paths.add(path);
}
} catch (IOException e) {
e.printStackTrace();
}
return paths;
}
}

View File

@ -1,69 +0,0 @@
package magic.ui;
import magic.data.IconImages;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class DuelDialog extends JDialog implements ActionListener {
private static final long serialVersionUID = 1L;
private final MagicFrame frame;
private final JButton okButton;
private final JButton cancelButton;
private final DuelSetupPanel duelSetupPanel;
public DuelDialog(final MagicFrame frame) {
super(frame,true);
this.frame=frame;
this.setTitle("New duel");
this.setSize(500,500);
this.setLocationRelativeTo(frame);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
final JPanel buttonPanel=new JPanel();
buttonPanel.setPreferredSize(new Dimension(0,45));
buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT,15,0));
okButton=new JButton("OK");
okButton.setFocusable(false);
okButton.setIcon(IconImages.OK);
okButton.addActionListener(this);
buttonPanel.add(okButton);
cancelButton=new JButton("Cancel");
cancelButton.setFocusable(false);
cancelButton.setIcon(IconImages.CANCEL);
cancelButton.addActionListener(this);
buttonPanel.add(cancelButton);
duelSetupPanel = new DuelSetupPanel();
duelSetupPanel.setOpaque(false);
getContentPane().setLayout(new BorderLayout());
getContentPane().add(duelSetupPanel,BorderLayout.CENTER);
getContentPane().add(buttonPanel,BorderLayout.SOUTH);
setVisible(true);
}
public void actionPerformed(final ActionEvent event) {
final Object source=event.getSource();
if (source==okButton) {
frame.newDuel(duelSetupPanel.getNewDuelConfig());
dispose();
} else if (source==cancelButton) {
dispose();
}
}
}

View File

@ -1,32 +1,39 @@
package magic.ui;
import magic.data.CardImagesProvider;
import magic.data.DuelConfig;
import magic.model.MagicCardDefinition;
import magic.model.MagicDeck;
import magic.model.MagicDuel;
import magic.model.MagicPlayerDefinition;
import magic.ui.theme.Theme;
import magic.ui.theme.ThemeFactory;
import magic.model.player.HumanPlayer;
import magic.model.player.PlayerProfile;
import magic.ui.viewer.CardViewer;
import magic.ui.viewer.DeckDescriptionViewer;
import magic.ui.viewer.DeckStatisticsViewer;
import magic.ui.viewer.DeckStrengthViewer;
import magic.ui.viewer.DuelDifficultyViewer;
import magic.ui.viewer.HistoryViewer;
import magic.ui.widget.FontsAndBorders;
import magic.ui.widget.PlayerDetailsPanel;
import magic.ui.widget.TexturedPanel;
import net.miginfocom.swing.MigLayout;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SpringLayout;
import javax.swing.SwingConstants;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
@ -40,7 +47,6 @@ public class DuelPanel extends TexturedPanel {
private final MagicDuel duel;
private final JTabbedPane tabbedPane;
private final DeckStrengthViewer strengthViewer;
private final HistoryViewer historyViewer;
private final DeckDescriptionViewer[] deckDescriptionViewers;
private final CardViewer cardViewer;
private final DuelDifficultyViewer duelDifficultyViewer;
@ -80,9 +86,6 @@ public class DuelPanel extends TexturedPanel {
// games won info
duelDifficultyViewer=new DuelDifficultyViewer(duel);
duelDifficultyViewer.setAlignmentX(Component.LEFT_ALIGNMENT);
duelDifficultyViewer.setMaximumSize(DuelDifficultyViewer.PREFERRED_SIZE);
leftPanel.add(duelDifficultyViewer);
// add scrolling to left side
final JScrollPane leftScrollPane = new JScrollPane(leftPanel);
@ -94,7 +97,6 @@ public class DuelPanel extends TexturedPanel {
// create tabs for each player
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
final Theme theme=ThemeFactory.getInstance().getCurrentTheme();
final MagicPlayerDefinition[] players = duel.getPlayers();
cardTables = new CardTable[players.length];
@ -106,12 +108,16 @@ public class DuelPanel extends TexturedPanel {
strengthViewer=new DeckStrengthViewer(duel);
strengthViewer.setAlignmentX(Component.LEFT_ALIGNMENT);
historyViewer = new HistoryViewer();
historyViewer.setAlignmentX(Component.LEFT_ALIGNMENT);
for(int i = 0; i < players.length; i++) {
final MagicPlayerDefinition player = players[i];
if (player.isArtificial()) {
player.setAvatar(duel.getConfiguration().getPlayerTwoProfile().getAvatar());
} else {
player.setAvatar(duel.getConfiguration().getPlayerOneProfile().getAvatar());
}
// deck description
deckDescriptionViewers[i] = new DeckDescriptionViewer();
deckDescriptionViewers[i].setPlayer(player);
@ -150,9 +156,6 @@ public class DuelPanel extends TexturedPanel {
rightPanel.add(strengthViewer);
rightPanel.add(Box.createVerticalStrut(SPACING));
rightPanel.add(historyViewer);
rightPanel.add(Box.createVerticalStrut(SPACING));
// show card
cardViewer.setCard(player.getDeck().get(0),0);
}
@ -201,7 +204,10 @@ public class DuelPanel extends TexturedPanel {
-SPACING, SpringLayout.SOUTH, tabPanel);
// add as a tab
tabbedPane.addTab(player.getName() + " ", theme.getAvatarIcon(player.getFace(), 2), tabPanel);
tabbedPane.addTab(null, tabPanel);
final DuelConfig duelConfig = duel.getConfiguration();
final PlayerProfile profile = (i == 0 ? duelConfig.getPlayerOneProfile() : duelConfig.getPlayerTwoProfile());
tabbedPane.setTabComponentAt(i, new PlayerPanel(profile));
}
add(tabbedPane);
@ -268,4 +274,33 @@ public class DuelPanel extends TexturedPanel {
strengthViewer.halt();
}
@SuppressWarnings("serial")
private class PlayerPanel extends JPanel {
public PlayerPanel(final PlayerProfile profile) {
setLayout(new MigLayout("insets 0"));
setOpaque(false);
add(new JLabel(profile.getAvatar().getIcon(4)));
add(new PlayerDetailsPanel(profile, Color.BLACK), "w 100%");
add(getScoreLabel(getScore(profile)), "w 100%");
setPreferredSize(new Dimension(250, 54));
}
private int getScore(final PlayerProfile profile) {
if (profile instanceof HumanPlayer) {
return duel.getGamesWon();
} else {
return duel.getGamesPlayed() - duel.getGamesWon();
}
}
private JLabel getScoreLabel(final int score) {
final JLabel lbl = new JLabel(Integer.toString(score));
lbl.setFont(new Font("Dialog", Font.PLAIN, 24));
lbl.setHorizontalAlignment(SwingConstants.RIGHT);
return lbl;
}
}
}

View File

@ -1,315 +0,0 @@
package magic.ui;
import magic.ai.MagicAIImpl;
import magic.data.CubeDefinitions;
import magic.data.DeckGenerators;
import magic.data.DuelConfig;
import magic.data.IconImages;
import magic.model.MagicColor;
import magic.ui.theme.Theme;
import magic.ui.theme.ThemeFactory;
import magic.ui.widget.FontsAndBorders;
import magic.ui.widget.SliderPanel;
import magic.ui.widget.TexturedPanel;
import java.util.Vector;
import javax.swing.JComboBox;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class DuelSetupPanel extends TexturedPanel {
private static final long serialVersionUID = 1L;
private static final String SEPARATOR = "----";
private final AvatarPanel avatarPanel;
private final JTextField nameTextField;
private final SliderPanel lifeSlider;
private final SliderPanel handSlider;
private final SliderPanel gameSlider;
private final ColorsChooser playerColorsChooser;
private final ColorsChooser opponentColorsChooser;
private final JComboBox<String> cubeComboBox;
private final JComboBox<String> aiComboBox;
private final Theme theme;
public DuelSetupPanel() {
theme=ThemeFactory.getInstance().getCurrentTheme();
final DuelConfig config=DuelConfig.getInstance();
config.load();
final JPanel mainPanel=new JPanel();
mainPanel.setOpaque(false);
mainPanel.setLayout(null);
nameTextField=new JTextField(config.getName());
nameTextField.setPreferredSize(new Dimension(0,25));
nameTextField.setBounds(35,20,120,25);
mainPanel.add(nameTextField);
avatarPanel=new AvatarPanel(config.getAvatar());
avatarPanel.setBounds(35,50,120,180);
mainPanel.add(avatarPanel);
avatarPanel.setOpaque(false);
lifeSlider=new SliderPanel("Life",theme.getIcon(Theme.ICON_LIFE),10,30,5,config.getStartLife());
lifeSlider.setBounds(190,25,270,50);
mainPanel.add(lifeSlider);
lifeSlider.setOpaque(false);
handSlider=new SliderPanel("Hand",theme.getIcon(Theme.ICON_HAND),6,8,1,config.getHandSize());
handSlider.setBounds(190,95,270,50);
mainPanel.add(handSlider);
handSlider.setOpaque(false);
gameSlider=new SliderPanel("Games",IconImages.NUMBER,3,11,2,config.getNrOfGames());
gameSlider.setBounds(190,165,270,50);
mainPanel.add(gameSlider);
gameSlider.setOpaque(false);
playerColorsChooser=new ColorsChooser(config.getPlayerColors());
playerColorsChooser.setBounds(55,255,130,50);
mainPanel.add(playerColorsChooser);
final JLabel versusLabel=new JLabel("versus");
versusLabel.setHorizontalAlignment(JLabel.CENTER);
versusLabel.setFont(FontsAndBorders.FONT4);
versusLabel.setBounds(185,255,120,50);
mainPanel.add(versusLabel);
opponentColorsChooser=new ColorsChooser(config.getOpponentColors());
opponentColorsChooser.setBounds(305,255,130,50);
mainPanel.add(opponentColorsChooser);
final JLabel cubeLabel=new JLabel("Cube");
cubeLabel.setIcon(IconImages.CUBE);
cubeLabel.setBounds(55,330,80,25);
mainPanel.add(cubeLabel);
cubeComboBox=new JComboBox<String>(CubeDefinitions.getCubeNames());
cubeComboBox.setFocusable(false);
cubeComboBox.setBounds(135,330,300,25);
cubeComboBox.setSelectedItem(config.getCube());
mainPanel.add(cubeComboBox);
final JLabel aiLabel=new JLabel("AI");
aiLabel.setBounds(55,365,80,25);
aiLabel.setIcon(IconImages.DIFFICULTY);
mainPanel.add(aiLabel);
aiComboBox=new JComboBox<String>(MagicAIImpl.getNames());
aiComboBox.setFocusable(false);
aiComboBox.setBounds(135,365,300,25);
aiComboBox.setSelectedItem(config.getAI());
mainPanel.add(aiComboBox);
setLayout(new BorderLayout());
add(mainPanel,BorderLayout.CENTER);
}
private class AvatarPanel extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L;
private final JLabel avatarLabel;
private final JButton leftButton;
private final JButton rightButton;
private int avatar;
public AvatarPanel(final int avatar) {
this.avatar=avatar;
setLayout(new BorderLayout(0,5));
avatarLabel=new JLabel();
avatarLabel.setIcon(theme.getAvatarIcon(avatar,3));
add(avatarLabel,BorderLayout.CENTER);
final JPanel buttonPanel=new JPanel();
buttonPanel.setLayout(new GridLayout(1,2,10,0));
add(buttonPanel,BorderLayout.SOUTH);
buttonPanel.setOpaque(false);
leftButton=new JButton(IconImages.LEFT);
leftButton.setFocusable(false);
leftButton.addActionListener(this);
buttonPanel.add(leftButton,BorderLayout.WEST);
rightButton=new JButton(IconImages.RIGHT);
rightButton.setFocusable(false);
rightButton.addActionListener(this);
buttonPanel.add(rightButton,BorderLayout.EAST);
}
public int getAvatar() {
return avatar;
}
public void actionPerformed(final ActionEvent event) {
final Object source=event.getSource();
if (source==leftButton) {
avatar--;
if (avatar<0) {
avatar=theme.getNumberOfAvatars()-1;
}
} else {
avatar++;
if (avatar==theme.getNumberOfAvatars()) {
avatar=0;
}
}
avatarLabel.setIcon(theme.getAvatarIcon(avatar,3));
}
}
private static class ColorsChooser extends JComboBox<String> implements ListCellRenderer<String> {
private static final long serialVersionUID = 1L;
private String lastSelected;
public ColorsChooser(final String colors) {
setRenderer(this);
final Vector<String> items = new Vector<String>();
items.add("bug");
items.add("bur");
items.add("buw");
items.add("bgr");
items.add("bgw");
items.add("brw");
items.add("ugw");
items.add("ugr");
items.add("urw");
items.add("grw");
items.add("***");
items.add("bu");
items.add("bg");
items.add("br");
items.add("bw");
items.add("ug");
items.add("ur");
items.add("uw");
items.add("gr");
items.add("gw");
items.add("rw");
items.add("**");
items.add("b");
items.add("u");
items.add("g");
items.add("r");
items.add("w");
items.add("*");
items.add("@");
if (DeckGenerators.getInstance().getNrGenerators() > 0) {
items.add(SEPARATOR);
for(final String generatorName : DeckGenerators.getInstance().getGeneratorNames()) {
items.add(generatorName);
}
}
setModel(new DefaultComboBoxModel<String>(items));
setSelectedItem(colors);
lastSelected = colors;
this.setFocusable(false);
addActionListener(this);
}
@Override
public String getSelectedItem() {
return getItemAt(getSelectedIndex());
}
@Override
public Component getListCellRendererComponent(
final JList<? extends String> list,
final String selectedVal,
final int index,
final boolean isSelected,
final boolean cellHasFocus) {
if(selectedVal.equals(SEPARATOR)) {
return new javax.swing.JSeparator(javax.swing.JSeparator.HORIZONTAL);
} else if(DeckGenerators.getInstance().getGeneratorNames().contains(selectedVal)) {
final JPanel panel=new JPanel(new GridLayout(1,1));
panel.setBorder(FontsAndBorders.EMPTY_BORDER);
if (isSelected) {
panel.setBackground(Color.LIGHT_GRAY);
}
final JLabel label = new JLabel(selectedVal, JLabel.CENTER);
label.setFont(FontsAndBorders.FONT1);
panel.add(label);
return panel;
} else {
final JPanel panel=new JPanel(new GridLayout(1,3));
for (int i=0;i<selectedVal.length();i++) {
final char ch = selectedVal.charAt(i);
final ImageIcon icon;
switch (ch) {
case '*': icon=IconImages.ANY; break;
case '@': icon=IconImages.FOLDER; break;
default: icon=MagicColor.getColor(ch).getIcon(); break;
}
panel.add(new JLabel(icon));
}
panel.setBorder(FontsAndBorders.EMPTY_BORDER);
if (isSelected) {
panel.setBackground(Color.LIGHT_GRAY);
}
return panel;
}
}
public void actionPerformed(final ActionEvent e) {
final String tempItem = getSelectedItem();
if (SEPARATOR.equals(tempItem)) {
// don't select separator
setSelectedItem(lastSelected);
} else {
lastSelected = tempItem;
}
}
}
public DuelConfig getNewDuelConfig() {
final DuelConfig config=DuelConfig.getInstance();
final String playerColors=playerColorsChooser.getSelectedItem();
final String opponentColors=opponentColorsChooser.getSelectedItem();
config.setAvatar(avatarPanel.getAvatar());
config.setName(nameTextField.getText());
config.setStartLife(lifeSlider.getValue());
config.setHandSize(handSlider.getValue());
config.setNrOfGames(gameSlider.getValue());
config.setPlayerColors(playerColors);
config.setOpponentColors(opponentColors);
config.setCube(cubeComboBox.getItemAt(cubeComboBox.getSelectedIndex()));
config.setAI(aiComboBox.getItemAt(aiComboBox.getSelectedIndex()));
config.save();
return config;
}
}

View File

@ -466,6 +466,7 @@ public class GameController implements ILogBookListener {
public void concede() {
if (!gameConceded.get() && !game.isFinished()) {
game.setLosingPlayer(game.getPlayer(0));
game.setConceded(true);
game.clearUndoPoints();
gameConceded.set(true);
resume(true);

View File

@ -12,21 +12,29 @@ import magic.model.MagicDeckConstructionRule;
import magic.model.MagicDuel;
import magic.model.MagicGame;
import magic.model.MagicGameLog;
import magic.model.player.PlayerProfile;
import magic.ui.choice.MulliganChoicePanel;
import magic.ui.dialog.PreferencesDialog;
import magic.ui.screen.AvatarImagesScreen;
import magic.ui.screen.CardExplorerScreen;
import magic.ui.screen.CardZoneScreen;
import magic.ui.screen.DeckEditorScreen;
import magic.ui.screen.DeckViewScreen;
import magic.ui.screen.DuelDecksScreen;
import magic.ui.screen.DuelGameScreen;
import magic.ui.screen.DuelPlayersScreen;
import magic.ui.screen.HelpMenuScreen;
import magic.ui.screen.KeywordsScreen;
import magic.ui.screen.AbstractScreen;
import magic.ui.screen.MulliganScreen;
import magic.ui.screen.SampleHandScreen;
import magic.ui.screen.SelectAiPlayerScreen;
import magic.ui.screen.SelectHumanPlayerScreen;
import magic.ui.screen.SettingsMenuScreen;
import magic.ui.screen.MainMenuScreen;
import magic.ui.screen.ReadmeScreen;
import magic.ui.screen.interfaces.IAvatarImageConsumer;
import magic.ui.screen.interfaces.IPlayerProfileConsumer;
import magic.ui.utility.GraphicsUtilities;
import net.miginfocom.swing.MigLayout;
@ -100,6 +108,18 @@ public class MagicFrame extends JFrame {
//
// The various (Mag)screens that can currently be displayed.
//
public void showDuelPlayersScreen() {
activateMagScreen(new DuelPlayersScreen());
}
public void showSelectAiProfileScreen(final IPlayerProfileConsumer consumer, final PlayerProfile profile) {
activateMagScreen(new SelectAiPlayerScreen(consumer, profile));
}
public void showAvatarImagesScreen(final IAvatarImageConsumer consumer) {
activateMagScreen(new AvatarImagesScreen(consumer));
}
public void showSelectHumanPlayerScreen(final IPlayerProfileConsumer consumer, final PlayerProfile profile) {
activateMagScreen(new SelectHumanPlayerScreen(consumer, profile));
}
public void showDeckView(final MagicDeck deck) {
activateMagScreen(new DeckViewScreen(deck));
}
@ -205,10 +225,6 @@ public class MagicFrame extends JFrame {
}
}
public void showNewDuelDialog() {
new DuelDialog(this);
}
public void newDuel(final DuelConfig configuration) {
duel = new MagicDuel(configuration);
duel.initialize();

View File

@ -0,0 +1,169 @@
package magic.ui;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
/**
* FlowLayout subclass that fully supports wrapping of components.
*/
@SuppressWarnings("serial")
public class WrapLayout extends FlowLayout {
/**
* Constructs a new <code>WrapLayout</code> with a left
* alignment and a default 5-unit horizontal and vertical gap.
*/
public WrapLayout() {
super();
}
/**
* Constructs a new <code>FlowLayout</code> with the specified
* alignment and a default 5-unit horizontal and vertical gap.
* The value of the alignment argument must be one of
* <code>FlowLayout.LEFT</code>, <code>FlowLayout.CENTER</code>,
* or <code>FlowLayout.RIGHT</code>.
* @param align the alignment value
*/
public WrapLayout(int align) {
super(align);
}
/**
* Creates a new flow layout manager with the indicated alignment
* and the indicated horizontal and vertical gaps.
* <p>
* The value of the alignment argument must be one of
* <code>FlowLayout.LEFT</code>, <code>FlowLayout.CENTER</code>,
* or <code>FlowLayout.RIGHT</code>.
* @param align the alignment value
* @param hgap the horizontal gap between components
* @param vgap the vertical gap between components
*/
public WrapLayout(int align, int hgap, int vgap) {
super(align, hgap, vgap);
}
/**
* Returns the preferred dimensions for this layout given the
* <i>visible</i> components in the specified target container.
* @param target the component which needs to be laid out
* @return the preferred dimensions to lay out the
* subcomponents of the specified container
*/
@Override
public Dimension preferredLayoutSize(Container target) {
return layoutSize(target, true);
}
/**
* Returns the minimum dimensions needed to layout the <i>visible</i>
* components contained in the specified target container.
* @param target the component which needs to be laid out
* @return the minimum dimensions to lay out the
* subcomponents of the specified container
*/
@Override
public Dimension minimumLayoutSize(Container target) {
Dimension minimum = layoutSize(target, false);
minimum.width -= (getHgap() + 1);
return minimum;
}
/**
* Returns the minimum or preferred dimension needed to layout the target
* container.
*
* @param target target to get layout size for
* @param preferred should preferred size be calculated
* @return the dimension to layout the target container
*/
private Dimension layoutSize(Container target, boolean preferred) {
synchronized (target.getTreeLock()) {
// Each row must fit with the width allocated to the container.
// When the container width = 0, the preferred width of the container
// has not yet been calculated so we use a width guaranteed to be less
// than we need so that it gets recalculated later when the widget is
// shown.
int hgap = getHgap();
Insets insets = target.getInsets();
int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2);
int targetWidth = Math.max(horizontalInsetsAndGap, target.getSize().width);
int maxWidth = targetWidth - horizontalInsetsAndGap;
// Fit components into the allowed width
Dimension dim = new Dimension(0, 0);
int rowWidth = 0;
int rowHeight = 0;
final int nmembers = target.getComponentCount();
for (int i = 0; i < nmembers; i++) {
Component m = target.getComponent(i);
if (!m.isVisible()) {
continue;
}
Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize();
// can't add the component to current row. Start a new row if
// there's at least one component in this row.
if (0 < rowWidth && rowWidth + d.width > maxWidth) {
addRow(dim, rowWidth, rowHeight);
rowWidth = 0;
rowHeight = 0;
}
// Add a horizontal gap for all components after the first
if (rowWidth != 0) {
rowWidth += hgap;
}
rowWidth += d.width;
rowHeight = Math.max(rowHeight, d.height);
}
// add last row
addRow(dim, rowWidth, rowHeight);
dim.width += horizontalInsetsAndGap;
dim.height += insets.top + insets.bottom + getVgap() * 2;
// When using a scroll pane or the DecoratedLookAndFeel we need to
// make sure the preferred size is less than the size of the
// target container so shrinking the container size works
// correctly. Removing the horizontal gap is an easy way to do this.
Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target);
if (scrollPane != null) {
dim.width -= (hgap + 1);
}
return dim;
}
}
/*
* A new row has been completed. Use the dimensions of this row
* to update the preferred size for the container.
*
* @param dim update the width and height when appropriate
* @param rowWidth the width of the row to add
* @param rowHeight the height of the row to add
*/
private void addRow(Dimension dim, int rowWidth, int rowHeight) {
dim.width = Math.max(dim.width, rowWidth);
if (dim.height > 0) {
dim.height += getVgap();
}
dim.height += rowHeight;
}
}

View File

@ -0,0 +1,163 @@
package magic.ui.dialog;
import magic.ai.MagicAIImpl;
import magic.model.player.AiPlayer;
import magic.model.player.PlayerProfile;
import magic.ui.MagicFrame;
import magic.ui.widget.SliderPanel;
import net.miginfocom.swing.MigLayout;
import javax.swing.AbstractAction;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import java.awt.event.ActionEvent;
@SuppressWarnings("serial")
public class AiPropertiesDialog extends JDialog {
private AiPlayer playerProfile;
private final JTextField playerNameTextField;
private final SliderPanel aiLevelSliderPanel;
private final SliderPanel lifeSliderPanel;
private final JComboBox<MagicAIImpl> aiComboBox;
// CTR : edit an existing profile.
public AiPropertiesDialog(final MagicFrame frame, final AiPlayer profile) {
super(frame, true);
this.setTitle("AI Profile");
this.setSize(300, 260);
this.setLocationRelativeTo(frame);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
this.playerProfile = profile == null ? new AiPlayer() : profile;
playerNameTextField = new JTextField(playerProfile.getPlayerName());
lifeSliderPanel = new SliderPanel("Life+", null, 0, 10, 1, playerProfile.getExtraLife());
aiLevelSliderPanel = new SliderPanel("AI Level", null, 1, 8, 1, playerProfile.getAiLevel());
aiComboBox = new JComboBox<MagicAIImpl>();
aiComboBox.setModel(new DefaultComboBoxModel<MagicAIImpl>(MagicAIImpl.SUPPORTED_AIS));
aiComboBox.setLightWeightPopupEnabled(false);
aiComboBox.setFocusable(false);
aiComboBox.setSelectedItem(playerProfile.getAiType());
getContentPane().setLayout(new MigLayout("insets 0, flowy", "", "[][45!]"));
getContentPane().add(getDataPanel(), "w 100%, h 100%");
getContentPane().add(getButtonPanel(), "w 100%, h 40!");
setEscapeKeyAction();
setVisible(true);
}
public AiPropertiesDialog(final MagicFrame frame) {
this(frame, null);
}
public PlayerProfile getPlayerProfile() {
return playerProfile;
}
private void setEscapeKeyAction() {
JRootPane root = getRootPane();
root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), "closeDialog");
root.getActionMap().put("closeDialog", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
dispose();
}
});
}
private JPanel getButtonPanel() {
final JPanel buttonPanel = new JPanel(new MigLayout("alignx right"));
buttonPanel.add(getSaveButton(), "w 80!");
buttonPanel.add(getCancelButton(), "w 80!");
return buttonPanel;
}
private JButton getCancelButton() {
final JButton btn = new JButton("Cancel");
btn.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
playerProfile = null;
dispose();
}
});
return btn;
}
private JButton getSaveButton() {
final JButton btn = new JButton("Save");
btn.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
if (isPlayerNameValid()) {
savePlayerProfile();
dispose();
}
}
});
return btn;
}
private boolean isPlayerNameValid() {
final String newName = playerNameTextField.getText().trim();
return !newName.isEmpty();
}
private void savePlayerProfile() {
playerProfile.setPlayerName(getVerifiedPlayerName(this.playerNameTextField.getText(), playerProfile.getPlayerName()));
playerProfile.setExtraLife(lifeSliderPanel.getValue());
playerProfile.setAiLevel(aiLevelSliderPanel.getValue());
playerProfile.setAiType((MagicAIImpl)aiComboBox.getSelectedItem());
playerProfile.save();
}
private String getVerifiedPlayerName(String newName, String oldName) {
if (newName == null) {
newName = oldName;
} else {
newName = newName.trim();
if (newName == null || newName.isEmpty() || newName.equalsIgnoreCase(oldName) ) {
newName = oldName;
}
}
return newName;
}
private JPanel getDataPanel() {
final JPanel panel = new JPanel(new MigLayout("flowy"));
panel.add(getPlayerNamePanel(), "w 100%");
panel.add(getAiTypePanel(), "w 100%");
panel.add(lifeSliderPanel, "w 100%");
panel.add(aiLevelSliderPanel, "w 100%");
return panel;
}
private JPanel getAiTypePanel() {
final JPanel panel = new JPanel(new MigLayout());
panel.add(new JLabel("AI Type:"));
panel.add(aiComboBox, "w 100%, left");
return panel;
}
private JPanel getPlayerNamePanel() {
final JPanel panel = new JPanel(new MigLayout());
panel.add(new JLabel("AI Name:"));
panel.add(playerNameTextField, "w 100%, left");
return panel;
}
}

View File

@ -0,0 +1,134 @@
package magic.ui.dialog;
import magic.data.CubeDefinitions;
import magic.ui.MagicFrame;
import magic.ui.widget.SliderPanel;
import net.miginfocom.swing.MigLayout;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;
import java.awt.event.ActionEvent;
@SuppressWarnings("serial")
public class DuelPropertiesDialog extends JDialog {
private final SliderPanel handSizeSliderPanel;
private final SliderPanel lifeSliderPanel;
private final SliderPanel winsSliderPanel;
private final JComboBox<String> cubeComboBox;
private boolean isCancelled = false;
// CTR : edit an existing profile.
public DuelPropertiesDialog(
final MagicFrame frame,
final int handSize,
final int initialLife,
final int maxGames,
final String cube) {
super(frame, true);
this.setTitle("Duel Properties");
this.setSize(300, 280);
this.setLocationRelativeTo(frame);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
lifeSliderPanel = new SliderPanel("Initial life:", null, 10, 30, 5, initialLife);
handSizeSliderPanel = new SliderPanel("Hand size:", null, 6, 8, 1, handSize);
winsSliderPanel = new SliderPanel("Max. games:", null, 1, 11, 2, maxGames);
cubeComboBox = new JComboBox<String>(CubeDefinitions.getCubeNames());
cubeComboBox.setLightWeightPopupEnabled(false);
cubeComboBox.setFocusable(false);
cubeComboBox.setSelectedItem(cube);
getContentPane().setLayout(new MigLayout("flowy", "", "[][45!]"));
getContentPane().add(lifeSliderPanel, "w 100%");
getContentPane().add(handSizeSliderPanel, "w 100%");
getContentPane().add(winsSliderPanel, "w 100%");
getContentPane().add(getCubePanel(), "w 100%");
getContentPane().add(getButtonPanel(), "w 100%, h 40!");
setEscapeKeyAction();
setVisible(true);
}
private JPanel getCubePanel() {
final JPanel panel = new JPanel(new MigLayout());
panel.add(new JLabel("Cube:"));
panel.add(cubeComboBox, "w 100%");
return panel;
}
private void setEscapeKeyAction() {
JRootPane root = getRootPane();
root.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ESCAPE"), "closeDialog");
root.getActionMap().put("closeDialog", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
dispose();
}
});
}
private JPanel getButtonPanel() {
final JPanel buttonPanel = new JPanel(new MigLayout("alignx right"));
buttonPanel.add(getSaveButton(), "w 80!");
buttonPanel.add(getCancelButton(), "w 80!");
return buttonPanel;
}
private JButton getCancelButton() {
final JButton btn = new JButton("Cancel");
btn.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
isCancelled = true;
dispose();
}
});
return btn;
}
private JButton getSaveButton() {
final JButton btn = new JButton("Save");
btn.addActionListener(new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
return btn;
}
public boolean isCancelled() {
return isCancelled;
}
public int getStartLife() {
return lifeSliderPanel.getValue();
}
public int getHandSize() {
return handSizeSliderPanel.getValue();
}
public int getNrOfGames() {
return winsSliderPanel.getValue();
}
public String getCube() {
return cubeComboBox.getItemAt(cubeComboBox.getSelectedIndex());
}
}

View File

@ -1,8 +1,8 @@
package magic.ui;
package magic.ui.dialog;
import magic.data.AvatarImages;
import magic.data.GeneralConfig;
import magic.data.IconImages;
import magic.ui.MagicFrame;
import magic.ui.theme.ThemeFactory;
import magic.ui.widget.SliderPanel;
import net.miginfocom.swing.MigLayout;
@ -37,7 +37,6 @@ public class PreferencesDialog extends JDialog implements ActionListener {
private final MagicFrame frame;
private JComboBox<String> themeComboBox;
private JComboBox<String> avatarComboBox;
private JComboBox<String> highlightComboBox;
private JCheckBox confirmExitCheckBox;
private JCheckBox soundCheckBox;
@ -229,17 +228,6 @@ public class PreferencesDialog extends JDialog implements ActionListener {
themeComboBox.setSelectedItem(config.getTheme());
panel.add(themeComboBox);
Y += 35;
final JLabel avatarLabel=new JLabel("Avatar");
avatarLabel.setBounds(X,Y,W,H);
avatarLabel.setIcon(IconImages.AVATAR);
panel.add(avatarLabel);
avatarComboBox=new JComboBox<String>(AvatarImages.getInstance().getNames());
avatarComboBox.setFocusable(false);
avatarComboBox.setBounds(X2,Y,W2,H);
avatarComboBox.setSelectedItem(config.getAvatar());
panel.add(avatarComboBox);
Y += 35;
final JLabel highlightLabel = new JLabel("Highlight");
highlightLabel.setBounds(X,Y,W,H);
@ -288,7 +276,6 @@ public class PreferencesDialog extends JDialog implements ActionListener {
if (source==okButton) {
final GeneralConfig config=GeneralConfig.getInstance();
config.setTheme(themeComboBox.getItemAt(themeComboBox.getSelectedIndex()));
config.setAvatar(avatarComboBox.getItemAt(avatarComboBox.getSelectedIndex()));
config.setHighlight(highlightComboBox.getItemAt(highlightComboBox.getSelectedIndex()));
config.setConfirmExit(confirmExitCheckBox.isSelected());
config.setSound(soundCheckBox.isSelected());

View File

@ -32,6 +32,7 @@ public abstract class AbstractScreen extends JPanel {
private JPanel content;
private final MagicFrame frame;
private ActionBar actionbar;
// CTR
public AbstractScreen() {
@ -41,13 +42,19 @@ public abstract class AbstractScreen extends JPanel {
setEscapeKeyInputMap();
}
protected void refreshActionBar() {
actionbar.refreshLayout();
}
protected void setContent(final JPanel content) {
this.content = content;
doMagScreenLayout();
doMigLayout();
revalidate();
repaint();
setBusy(false);
}
private void doMagScreenLayout() {
private void doMigLayout() {
removeAll();
setLayout(new MigLayout("insets 0, gap 0, flowy"));
layoutMagStatusBar();
@ -63,7 +70,8 @@ public abstract class AbstractScreen extends JPanel {
private void layoutMagActionBar() {
if (hasActionBar()) {
add(new ActionBar((IActionBar)this), "w 100%");
this.actionbar = new ActionBar((IActionBar)this);
add(actionbar, "w 100%");
} else if (!(this instanceof DuelGameScreen)) {
add(getKeysStrip(), "w 100%");
}

View File

@ -0,0 +1,358 @@
package magic.ui.screen;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.DirectoryStream.Filter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import net.miginfocom.swing.MigLayout;
import magic.MagicMain;
import magic.data.IconImages;
import magic.data.URLUtils;
import magic.ui.AvatarImageSet;
import magic.ui.WrapLayout;
import magic.ui.screen.interfaces.IActionBar;
import magic.ui.screen.interfaces.IAvatarImageConsumer;
import magic.ui.screen.interfaces.IStatusBar;
import magic.ui.screen.widget.ActionBarButton;
import magic.ui.screen.widget.MenuButton;
import magic.ui.theme.PlayerAvatar;
import magic.ui.utility.GraphicsUtilities;
import magic.ui.widget.FontsAndBorders;
import magic.ui.widget.TexturedPanel;
@SuppressWarnings("serial")
public class AvatarImagesScreen
extends AbstractScreen
implements IStatusBar, IActionBar {
private JPanel viewer;
private MenuButton rightActionButton = null;
private JLabel selectedImageLabel = null;
private final IAvatarImageConsumer consumer;
private final Map<JLabel, Path> imagePathMap = new HashMap<JLabel, Path>();
public AvatarImagesScreen(final IAvatarImageConsumer consumer) {
this.consumer = consumer;
setContent(getScreenContent());
}
public AvatarImagesScreen() {
this(null);
}
private JPanel getScreenContent() {
// Layout content.
final JPanel content = new JPanel(new MigLayout("insets 0, gap 0"));
content.setOpaque(false);
content.add(getAvatarImageSetsPanel(), "w 240!, h 100%");
content.add(getAvatarImageSetViewer(), "w 100%, h 100%");
return content;
}
private JScrollPane getAvatarImageSetViewer() {
viewer = new TexturedPanel();
viewer.setLayout(new WrapLayout());
viewer.setBorder(FontsAndBorders.BLACK_BORDER);
viewer.setBackground(FontsAndBorders.MAGSCREEN_FADE_COLOR);
final JScrollPane scroller = new JScrollPane(viewer);
scroller.getViewport().setOpaque(false);
scroller.setBorder(BorderFactory.createEmptyBorder());
scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scroller.getVerticalScrollBar().setUnitIncrement(20);
return scroller;
}
private void displayImageSetIcons(final AvatarImageSet imageSet) {
viewer.removeAll();
imagePathMap.clear();
for (Path imagePath : imageSet.getImagePaths()) {
final String filePath = imagePath.toAbsolutePath().toString();
try (final InputStream ins = new FileInputStream(new File(filePath))) {
final BufferedImage image = magic.data.FileIO.toImg(ins, IconImages.MISSING);
final ImageIcon icon = new ImageIcon(GraphicsUtilities.scale(image, PlayerAvatar.LARGE_SIZE, PlayerAvatar.LARGE_SIZE));
final JLabel iconLabel = new JLabel(icon);
imagePathMap.put(iconLabel, imagePath);
iconLabel.setBorder(FontsAndBorders.EMPTY_BORDER);
viewer.add(iconLabel);
iconLabel.addMouseListener(new MouseAdapter() {
private final Border defaultBorder = iconLabel.getBorder();
@Override
public void mouseEntered(MouseEvent e) {
iconLabel.setBorder(BorderFactory.createLineBorder(Color.BLACK, 2));
iconLabel.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
@Override
public void mouseExited(MouseEvent e) {
iconLabel.setBorder(defaultBorder);
}
@Override
public void mouseReleased(MouseEvent e) {
if (e.getButton() == 1) {
final JLabel imageLabel = (JLabel)e.getSource();
if (imageLabel != selectedImageLabel) {
setSelectedAvatar((JLabel)e.getSource());
} else {
notifyConsumer(imageLabel);
getFrame().closeActiveScreen(false);
}
}
}
});
} catch (IOException e) {
e.printStackTrace();
};
}
viewer.revalidate();
viewer.repaint();
}
private void setSelectedAvatar(final JLabel iconLabel) {
final Icon icon = iconLabel.getIcon();
final BufferedImage bi = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), BufferedImage.TYPE_INT_RGB);
final Graphics g = bi.createGraphics();
// paint the Icon to the BufferedImage.
icon.paintIcon(null, g, 0,0);
g.dispose();
rightActionButton =
new ActionBarButton(
new ImageIcon(GraphicsUtilities.scale(bi, 46, 46)),
"Select Avatar", "Click to select this avatar image.",
new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
notifyConsumer(iconLabel);
getFrame().closeActiveScreen(false);
}
});
refreshActionBar();
this.selectedImageLabel = iconLabel;
}
private void notifyConsumer(final JLabel selectedLabel) {
if (consumer != null) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
consumer.setSelectedAvatarPath(imagePathMap.get(selectedLabel));
}
});
}
}
private JPanel getAvatarImageSetsPanel() {
// List of avatar image sets.
final JList<AvatarImageSet> imageSetsList = new JList<AvatarImageSet>(getAvatarImageSetsArray());
imageSetsList.setOpaque(false);
imageSetsList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
displayImageSetIcons(imageSetsList.getSelectedValue());
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
});
}
}
});
imageSetsList.setSelectedIndex(0);
final ImageSetsListRenderer renderer = new ImageSetsListRenderer();
imageSetsList.setCellRenderer(renderer);
final JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(imageSetsList);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
final JPanel container = new TexturedPanel();
container.setLayout(new MigLayout("insets 0, gap 0, flowy"));
container.setBorder(FontsAndBorders.BLACK_BORDER);
container.setBackground(FontsAndBorders.MENUPANEL_COLOR);
container.add(scrollPane, "w 100%, h 100%");
return container;
}
private AvatarImageSet[] getAvatarImageSetsArray() {
final List<AvatarImageSet> imageSetsList = getAvatarImageSetsList();
return imageSetsList.toArray(new AvatarImageSet[imageSetsList.size()]);
}
private List<AvatarImageSet> getAvatarImageSetsList() {
final List<AvatarImageSet> imageSets = new ArrayList<AvatarImageSet>();
List<Path> directoryPaths = getDirectoryPaths(MagicMain.getAvatarSetsPath());
for (Path path : directoryPaths) {
imageSets.add(loadImageSet(path));
}
return imageSets;
}
private AvatarImageSet loadImageSet(final Path imageSetDirectory) {
final AvatarImageSet imageSet = new AvatarImageSet(imageSetDirectory);
return imageSet;
}
private List<Path> getDirectoryPaths(final String rootDirectory) {
final List<Path> paths = new ArrayList<Path>();
try (DirectoryStream<Path> ds =
Files.newDirectoryStream(
FileSystems.getDefault().getPath(rootDirectory),
new DirectoriesOnlyFilter())) {
for (Path p : ds) {
paths.add(p);
}
} catch (IOException e) {
e.printStackTrace();
}
return paths;
}
private static class DirectoriesOnlyFilter implements Filter<Path> {
@Override
public boolean accept(Path entry) throws IOException {
return Files.isDirectory(entry);
}
}
private class ImageSetsListRenderer extends JLabel implements ListCellRenderer<AvatarImageSet> {
public ImageSetsListRenderer() {
setOpaque(false);
}
/* (non-Javadoc)
* @see javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean)
*/
@Override
public Component getListCellRendererComponent(
JList<? extends AvatarImageSet> list, AvatarImageSet value, int index,
boolean isSelected, boolean cellHasFocus) {
final Color foreColor = isSelected ? Color.YELLOW : Color.WHITE;
final JLabel setNameLabel = new JLabel(value.getName());
setNameLabel.setFont(FontsAndBorders.FONT2);
setNameLabel.setForeground(foreColor);
setNameLabel.setVerticalAlignment(SwingConstants.TOP);
final JPanel infoPanel = new JPanel(new MigLayout("insets 0, gap 0, flowy"));
infoPanel.setOpaque(false);
infoPanel.setForeground(foreColor);
infoPanel.add(setNameLabel, "w 100%, gapbottom 4");
final JPanel itemPanel = new JPanel(new MigLayout("insets 0 0 0 6, gap 0"));
itemPanel.setPreferredSize(new Dimension(0, 70));
itemPanel.setOpaque(false);
itemPanel.setForeground(foreColor);
itemPanel.setBorder(isSelected ? BorderFactory.createLineBorder(Color.YELLOW, 1) : null);
itemPanel.add(new JLabel(value.getSampleImage()), "w 70!, h 70!");
itemPanel.add(infoPanel, "w 100%");
return itemPanel;
}
}
/* (non-Javadoc)
* @see magic.ui.IMagStatusBar#getScreenCaption()
*/
@Override
public String getScreenCaption() {
return "Avatars";
}
/* (non-Javadoc)
* @see magic.ui.IMagActionBar#getLeftAction()
*/
@Override
public MenuButton getLeftAction() {
return new MenuButton("Cancel", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().closeActiveScreen(false);
}
});
}
/* (non-Javadoc)
* @see magic.ui.IMagActionBar#getRightAction()
*/
@Override
public MenuButton getRightAction() {
return rightActionButton;
}
/* (non-Javadoc)
* @see magic.ui.IMagActionBar#getMiddleActions()
*/
@Override
public List<MenuButton> getMiddleActions() {
final List<MenuButton> buttons = new ArrayList<MenuButton>();
buttons.add(new MenuButton("Avatars online...", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
URLUtils.openURL("http://www.slightlymagic.net/forum/viewforum.php?f=89");
}
}, "Get more avatars from the Magarena forum."));
return buttons;
}
/* (non-Javadoc)
* @see magic.ui.MagScreen#canScreenClose()
*/
@Override
public boolean isScreenReadyToClose(final AbstractScreen nextScreen) {
return true;
}
/* (non-Javadoc)
* @see magic.ui.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
return null;
}
}

View File

@ -4,6 +4,7 @@ import java.awt.event.ActionEvent;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JPanel;
import magic.ui.ExplorerPanel;
import magic.ui.MagicFrame;
@ -92,4 +93,12 @@ public class CardExplorerScreen
}
/* (non-Javadoc)
* @see magic.ui.screen.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
return null;
}
}

View File

@ -6,6 +6,7 @@ import java.util.Collections;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JPanel;
import magic.data.GeneralConfig;
import magic.model.MagicCardList;
@ -80,4 +81,12 @@ public class CardZoneScreen
return true;
}
/* (non-Javadoc)
* @see magic.ui.screen.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
return null;
}
}

View File

@ -10,6 +10,7 @@ import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import magic.data.DeckUtils;
import magic.data.GeneralConfig;
@ -342,4 +343,12 @@ public class DeckEditorScreen
}
}
/* (non-Javadoc)
* @see magic.ui.screen.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
return null;
}
}

View File

@ -8,6 +8,7 @@ import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import magic.data.GeneralConfig;
import magic.data.IconImages;
@ -120,4 +121,12 @@ public class DeckViewScreen
return true;
}
/* (non-Javadoc)
* @see magic.ui.screen.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
return null;
}
}

View File

@ -6,7 +6,11 @@ import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import magic.MagicUtility;
import magic.data.DuelConfig;
import magic.data.IconImages;
import magic.model.MagicDeck;
import magic.model.MagicDeckConstructionRule;
import magic.model.MagicDuel;
@ -18,9 +22,10 @@ import magic.ui.ScreenOptionsOverlay;
import magic.ui.screen.interfaces.IActionBar;
import magic.ui.screen.interfaces.IOptionsMenu;
import magic.ui.screen.interfaces.IStatusBar;
import magic.ui.screen.widget.ActionBarButton;
import magic.ui.screen.widget.DuelSettingsPanel;
import magic.ui.screen.widget.MenuButton;
import magic.ui.screen.widget.MenuPanel;
import magic.ui.widget.FontsAndBorders;
@SuppressWarnings("serial")
public class DuelDecksScreen
@ -32,6 +37,9 @@ public class DuelDecksScreen
public DuelDecksScreen(final MagicDuel duel) {
this.screenContent = new DuelPanel(duel);
setContent(this.screenContent);
if (duel.getGamesPlayed() > 0) {
saveDuel(false);
}
}
/* (non-Javadoc)
@ -39,7 +47,7 @@ public class DuelDecksScreen
*/
@Override
public String getScreenCaption() {
return "Deck Settings";
return "Duel Decks";
}
/* (non-Javadoc)
@ -48,17 +56,17 @@ public class DuelDecksScreen
@Override
public MenuButton getLeftAction() {
if (screenContent.getDuel().getGamesPlayed() == 0) {
return new MenuButton("< Main menu", new AbstractAction() {
return new MenuButton("Main menu", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().closeActiveScreen(false);
}
});
} else {
return new MenuButton("< Quit duel", new AbstractAction() {
return new MenuButton("Main Menu", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().closeActiveScreen(false);
getFrame().showMainMenuScreen();
}
});
}
@ -69,7 +77,7 @@ public class DuelDecksScreen
*/
@Override
public void showOptionsMenuOverlay() {
new ScreenOptions(getFrame(), this);
new ScreenOptions(getFrame());
}
/* (non-Javadoc)
@ -78,32 +86,29 @@ public class DuelDecksScreen
@Override
public MenuButton getRightAction() {
if (!screenContent.getDuel().isFinished()) {
return new MenuButton(getStartDuelCaption() + " >", new AbstractAction() {
return new MenuButton(getStartDuelCaption(), new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
final MagicPlayerDefinition[] players = screenContent.getDuel().getPlayers();
if(isLegalDeckAndShowErrors(players[0].getDeck(), players[0].getName()) &&
isLegalDeckAndShowErrors(players[1].getDeck(), players[1].getName())) {
saveDuel(false);
getFrame().nextGame();
}
}
});
} else {
return new MenuButton("New Duel", new AbstractAction() {
return new MenuButton("Restart duel", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().showNewDuelDialog();
getFrame().restartDuel();
}
});
}
}
private String getStartDuelCaption() {
if (screenContent.getDuel().getGamesPlayed() == 0) {
return "Start duel";
} else {
return "Start game " + (screenContent.getDuel().getGamesPlayed() + 1);
}
return "Game " + (screenContent.getDuel().getGamesPlayed() + 1);
}
/* (non-Javadoc)
@ -113,32 +118,42 @@ public class DuelDecksScreen
public List<MenuButton> getMiddleActions() {
final List<MenuButton> buttons = new ArrayList<MenuButton>();
if (screenContent.getDuel().getGamesPlayed() == 0) {
buttons.add(new MenuButton("Deck Editor", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().showDeckEditor(screenContent.getSelectedPlayer().getDeck());
}
}));
buttons.add(new MenuButton("Swap Decks", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
swapDecks();
}
}));
buttons.add(
new ActionBarButton(
IconImages.DECK_ICON,
"Deck Editor", "Open the Deck Editor.",
new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().showDeckEditor(screenContent.getSelectedPlayer().getDeck());
}
})
);
buttons.add(
new ActionBarButton(
IconImages.SWAP_ICON,
"Swap Decks", "Swap your deck with your opponent's.",
new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
swapDecks();
}
})
);
} else {
buttons.add(new MenuButton("Save Duel", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
saveDuel();
}
}));
buttons.add(new MenuButton("Restart duel", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().restartDuel();
}
}));
if (screenContent.getDuel().isFinished()) {
final MagicDuel duel = screenContent.getDuel();
buttons.add(new MenuButton(duel.getWinningPlayerProfile().getPlayerName() + " wins the duel", null));
} else {
buttons.add(new MenuButton("Restart duel", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().restartDuel();
}
}));
}
}
return buttons;
}
@ -177,20 +192,17 @@ public class DuelDecksScreen
return screenContent.getDuel().getGamesPlayed();
}
public void saveDuel() {
public void saveDuel(final boolean confirmSave) {
screenContent.getDuel().save(MagicDuel.getDuelFile());
JOptionPane.showMessageDialog(this, "Duel saved. Use Load Duel option in Main Menu to restore.", "Save Duel", JOptionPane.INFORMATION_MESSAGE);
if (confirmSave) {
JOptionPane.showMessageDialog(this, "<html><b>Duel saved.</b><br><br>Please use Resume Duel option in Main Menu to restore.", "Save Duel", JOptionPane.INFORMATION_MESSAGE);
}
}
private class ScreenOptions extends ScreenOptionsOverlay {
private final MagicFrame frame;
private final DuelDecksScreen screen;
public ScreenOptions(final MagicFrame frame0, final DuelDecksScreen screen0) {
super(frame0);
this.frame = frame0;
this.screen = screen0;
public ScreenOptions(final MagicFrame frame) {
super(frame);
}
/* (non-Javadoc)
@ -198,43 +210,7 @@ public class DuelDecksScreen
*/
@Override
protected MenuPanel getScreenMenu() {
final MenuPanel menu = new MenuPanel("Duel Options");
menu.addMenuItem("New Duel", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
hideAllMenuPanels();
frame.showNewDuelDialog();
hideOverlay();
}
});
menu.addMenuItem("Load Duel", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
frame.loadDuel();
hideOverlay();
}
});
menu.addMenuItem("Save Duel", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
screen.saveDuel();
hideOverlay();
}
});
menu.addBlankItem();
menu.addMenuItem("Close menu", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
hideOverlay();
}
});
menu.refreshLayout();
menu.setBackground(FontsAndBorders.IMENUOVERLAY_MENUPANEL_COLOR);
return menu;
return null;
}
}
@ -255,4 +231,15 @@ public class DuelDecksScreen
return true;
}
/* (non-Javadoc)
* @see magic.ui.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
final DuelConfig config = screenContent.getDuel().getConfiguration();
final DuelSettingsPanel panel = new DuelSettingsPanel(getFrame(), config);
panel.setEnabled(false);
return panel;
}
}

View File

@ -0,0 +1,173 @@
package magic.ui.screen;
import java.awt.event.ActionEvent;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JPanel;
import net.miginfocom.swing.MigLayout;
import magic.data.DuelConfig;
import magic.model.player.PlayerProfile;
import magic.ui.MagicFrame;
import magic.ui.screen.AbstractScreen;
import magic.ui.screen.interfaces.IActionBar;
import magic.ui.screen.interfaces.IStatusBar;
import magic.ui.screen.widget.DuelSettingsPanel;
import magic.ui.screen.widget.MenuButton;
import magic.ui.widget.DeckComboPanel;
import magic.ui.widget.DuelPlayerPanel;
@SuppressWarnings("serial")
public class DuelPlayersScreen
extends AbstractScreen
implements IStatusBar, IActionBar {
private static final DuelConfig duelConfig = DuelConfig.getInstance();
private ScreenContent content;
public DuelPlayersScreen() {
duelConfig.load();
content = new ScreenContent(duelConfig, getFrame());
setContent(content);
}
/* (non-Javadoc)
* @see magic.ui.IMagStatusBar#getScreenCaption()
*/
@Override
public String getScreenCaption() {
return "New Duel Settings";
}
/* (non-Javadoc)
* @see magic.ui.IMagActionBar#getLeftAction()
*/
@Override
public MenuButton getLeftAction() {
return new MenuButton("Main Menu", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().closeActiveScreen(false);
}
});
}
/* (non-Javadoc)
* @see magic.ui.IMagActionBar#getRightAction()
*/
@Override
public MenuButton getRightAction() {
return new MenuButton("Next", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
saveDuelConfig();
getFrame().closeActiveScreen(false);
getFrame().newDuel(duelConfig);
}
});
}
private void saveDuelConfig() {
duelConfig.setStartLife(content.getStartLife());
duelConfig.setHandSize(content.getHandSize());
duelConfig.setNrOfGames(content.getNrOfGames());
duelConfig.setCube(content.getCube());
duelConfig.setPlayerOneProfile(content.getPlayerProfile(0));
duelConfig.setPlayerTwoProfile(content.getPlayerProfile(1));
duelConfig.setPlayerOneDeckGenerator(content.getPlayerDeckGenerator(0));
duelConfig.setPlayerTwoDeckGenerator(content.getPlayerDeckGenerator(1));
duelConfig.save();
}
/* (non-Javadoc)
* @see magic.ui.IMagActionBar#getMiddleActions()
*/
@Override
public List<MenuButton> getMiddleActions() {
return null;
}
/* (non-Javadoc)
* @see magic.ui.MagScreen#canScreenClose()
*/
@Override
public boolean isScreenReadyToClose(final AbstractScreen nextScreen) {
saveDuelConfig();
return true;
}
private class ScreenContent extends JPanel {
private final DuelSettingsPanel duelSettingsPanel;
private final DuelPlayerPanel[] playerPanels = new DuelPlayerPanel[2];
private final DeckComboPanel[] playerDeckPanels = new DeckComboPanel[2];
public ScreenContent(final DuelConfig config, final MagicFrame frame) {
duelSettingsPanel = new DuelSettingsPanel(frame, config);
playerPanels[0] = new DuelPlayerPanel(frame, config.getPlayerOneProfile());
playerPanels[1] = new DuelPlayerPanel(frame, config.getPlayerTwoProfile());
playerDeckPanels[0] = new DeckComboPanel(config.getPlayerOneDeckGenerator());
playerDeckPanels[1] = new DeckComboPanel(config.getPlayerTwoDeckGenerator());
setOpaque(false);
doMigLayout();
}
public String getCube() {
return duelSettingsPanel.getCube();
}
public int getNrOfGames() {
return duelSettingsPanel.getNrOfGames();
}
public int getHandSize() {
return duelSettingsPanel.getHandSize();
}
public int getStartLife() {
return duelSettingsPanel.getStartLife();
}
public String getPlayerDeckGenerator(final int index) {
return playerDeckPanels[index].getDeckGenerator();
}
public PlayerProfile getPlayerProfile(final int index) {
return playerPanels[index].getPlayerProfile();
}
private void doMigLayout() {
setLayout(new MigLayout("insets 0, center, center, wrap 2"));
add(duelSettingsPanel, "w 548!, h 40!, span 2, gapbottom 4");
layoutPlayerPanels();
layoutPlayerDeckPanels();
}
private void layoutPlayerPanels() {
for (final DuelPlayerPanel panel : playerPanels) {
add(panel, "w 270!, h 270!, gapright 4");
}
}
private void layoutPlayerDeckPanels() {
for (final DeckComboPanel panel : playerDeckPanels) {
add(panel, "w 270!");
}
}
}
/* (non-Javadoc)
* @see magic.ui.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
return null;
}
}

View File

@ -189,4 +189,12 @@ public class KeywordsScreen extends AbstractScreen implements IStatusBar, IActio
return true;
}
/* (non-Javadoc)
* @see magic.ui.screen.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
return null;
}
}

View File

@ -39,10 +39,11 @@ public class MainMenuScreen extends AbstractScreen {
menuPanel.addMenuItem("New duel", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().showNewDuelDialog();
getFrame().showDuelPlayersScreen();
}
});
menuPanel.addMenuItem("Load duel", new AbstractAction() {
menuPanel.addMenuItem("Resume duel", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().loadDuel();
@ -51,7 +52,6 @@ public class MainMenuScreen extends AbstractScreen {
menuPanel.addMenuItem("Card explorer", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
System.out.println(getFrame());
getFrame().showCardExplorerScreen();
}
});

View File

@ -164,4 +164,12 @@ public class MulliganScreen
}
}
/* (non-Javadoc)
* @see magic.ui.screen.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
return null;
}
}

View File

@ -111,4 +111,12 @@ public class ReadmeScreen extends AbstractScreen implements IStatusBar, IActionB
return true;
}
/* (non-Javadoc)
* @see magic.ui.screen.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
return null;
}
}

View File

@ -7,6 +7,8 @@ import java.util.Collections;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JPanel;
import magic.data.GeneralConfig;
import magic.data.IconImages;
import magic.model.MagicCard;
@ -115,4 +117,12 @@ public class SampleHandScreen
return true;
}
/* (non-Javadoc)
* @see magic.ui.screen.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
return null;
}
}

View File

@ -0,0 +1,262 @@
package magic.ui.screen;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JPanel;
import magic.ai.MagicAIImpl;
import magic.model.player.AiPlayer;
import magic.model.player.PlayerProfile;
import magic.model.player.PlayerProfiles;
import magic.ui.dialog.AiPropertiesDialog;
import magic.ui.screen.interfaces.IActionBar;
import magic.ui.screen.interfaces.IPlayerProfileConsumer;
import magic.ui.screen.interfaces.IStatusBar;
import magic.ui.screen.widget.MenuButton;
import magic.ui.widget.AiPlayerJList;
@SuppressWarnings("serial")
public class SelectAiPlayerScreen
extends SelectPlayerAbstractScreen
implements IStatusBar, IActionBar {
private AiPlayerJList profilesJList;
private IPlayerProfileConsumer consumer;
private final PlayerProfile playerProfile;
// CTR
public SelectAiPlayerScreen(final IPlayerProfileConsumer consumer, final PlayerProfile playerProfile) {
this.consumer = consumer;
this.playerProfile = playerProfile;
refreshProfilesJList(playerProfile.getId());
}
/* (non-Javadoc)
* @see magic.ui.screen.PlayerScreenUtil#getProfilesListPanel()
*/
@Override
protected JPanel getProfilesListPanel() {
profilesJList = new AiPlayerJList();
profilesJList.addMouseListener(getMouseAdapter());
return getContainerPanel(profilesJList);
}
private MouseAdapter getMouseAdapter() {
return new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
doNextAction();
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
};
}
private void refreshProfilesJList(final String selectedProfileId) {
profilesJList.setListData(getPlayerProfilesArray());
setSelectedListItem(selectedProfileId);
}
private void refreshProfilesJList() {
refreshProfilesJList(null);
}
private void setSelectedListItem(final String selectedProfileId) {
if (selectedProfileId == null || selectedProfileId.isEmpty()) {
profilesJList.setSelectedIndex(0);
} else {
profilesJList.setSelectedValue(profilesMap.get(selectedProfileId), true);
}
setFocusInProfilesJList(profilesJList);
}
private AiPlayer[] getPlayerProfilesArray() {
setProfilesMap();
final List<PlayerProfile> profilesByName = new ArrayList<PlayerProfile>(profilesMap.values());
Collections.sort(profilesByName, new Comparator<PlayerProfile>() {
@Override
public int compare(PlayerProfile o1, PlayerProfile o2) {
return o1.getPlayerName().toLowerCase().compareTo(o2.getPlayerName().toLowerCase());
}
});
return profilesByName.toArray(new AiPlayer[profilesByName.size()]);
}
private void setProfilesMap() {
profilesMap = PlayerProfiles.getAiPlayerProfiles();
}
/* (non-Javadoc)
* @see magic.ui.screen.SelectPlayerAbstractScreen#createDefaultPlayerProfiles()
*/
@Override
protected void createDefaultPlayerProfiles() throws IOException {
// Les Vegas
AiPlayer profile = new AiPlayer();
profile.setPlayerName("Les Vegas");
profile.setAiType(MagicAIImpl.VEGAS);
profile.setAiLevel(6);
profile.save();
// Mini Max
profile = new AiPlayer();
profile.setPlayerName("Mini Max");
profile.setAiType(MagicAIImpl.MMAB);
profile.setAiLevel(6);
profile.save();
// Monty Carlo
profile = new AiPlayer();
profile.setPlayerName("Monty Carlo");
profile.setAiType(MagicAIImpl.MCTS);
profile.setAiLevel(6);
profile.save();
}
/* (non-Javadoc)
* @see magic.ui.IMagStatusBar#getScreenCaption()
*/
@Override
public String getScreenCaption() {
return "Select AI Player";
}
/* (non-Javadoc)
* @see magic.ui.IMagActionBar#getLeftAction()
*/
@Override
public MenuButton getLeftAction() {
return new MenuButton("Cancel", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().closeActiveScreen(false);
}
});
}
/* (non-Javadoc)
* @see magic.ui.IMagActionBar#getRightAction()
*/
@Override
public MenuButton getRightAction() {
return new MenuButton("Select", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
doNextAction();
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
});
}
/* (non-Javadoc)
* @see magic.ui.IMagActionBar#getMiddleActions()
*/
@Override
public List<MenuButton> getMiddleActions() {
final List<MenuButton> buttons = new ArrayList<MenuButton>();
buttons.add(new MenuButton("New", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
createNewPlayerProfile();
}
}, "Create a new player profile."));
buttons.add(new MenuButton("Edit", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
new AiPropertiesDialog(getFrame(), getSelectedPlayerProfile());
profilesJList.repaint();
if (getSelectedPlayerProfile().getId().equals(playerProfile.getId())) {
consumer.setPlayerProfile(getSelectedPlayerProfile());
}
}
}, "Update name and duel settings for selected player."));
buttons.add(new MenuButton("Delete", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
deleteSelectedPlayerProfile();
}
}, "Delete selected player profile."));
buttons.add(getAvatarActionButton());
return buttons;
}
private void deleteSelectedPlayerProfile() {
final PlayerProfile profile = getSelectedPlayerProfile();
if (deleteSelectedPlayerProfile(profile)) {
PlayerProfiles.getPlayerProfiles().remove(profile.getId());
refreshProfilesJList();
if (profile.getId().equals(playerProfile.getId())) {
consumer.setPlayerProfile(getSelectedPlayerProfile());
}
}
}
private void createNewPlayerProfile() {
final AiPropertiesDialog dialog = new AiPropertiesDialog(getFrame());
final PlayerProfile newProfile = dialog.getPlayerProfile();
if (newProfile != null) {
PlayerProfiles.getPlayerProfiles().put(newProfile.getId(), newProfile);
refreshProfilesJList(newProfile.getId());
}
}
private AiPlayer getSelectedPlayerProfile() {
return profilesJList.getSelectedValue();
}
/* (non-Javadoc)
* @see magic.ui.MagScreen#canScreenClose()
*/
@Override
public boolean isScreenReadyToClose(final AbstractScreen nextScreen) {
return true;
}
/* (non-Javadoc)
* @see magic.ui.screen.IAvatarImageConsumer#setSelectedAvatarPath(java.nio.file.Path)
*/
@Override
public void setSelectedAvatarPath(final Path imagePath) {
final PlayerProfile profile = getSelectedPlayerProfile();
updateAvatarImage(imagePath, profile);
PlayerProfiles.refreshMap();
refreshProfilesJList(profile.getId());
consumer.setPlayerProfile(getSelectedPlayerProfile());
}
/* (non-Javadoc)
* @see magic.ui.screen.SelectPlayerScreen#getPlayerType()
*/
@Override
protected String getPlayerType() {
return "ai";
}
/* (non-Javadoc)
* @see magic.ui.screen.SelectPlayerAbstractScreen#doNextAction()
*/
@Override
protected void doNextAction() {
consumer.setPlayerProfile(getSelectedPlayerProfile());
getFrame().closeActiveScreen(false);
}
/* (non-Javadoc)
* @see magic.ui.screen.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
return null;
}
}

View File

@ -0,0 +1,272 @@
package magic.ui.screen;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import magic.model.player.HumanPlayer;
import magic.model.player.PlayerProfile;
import magic.model.player.PlayerProfiles;
import magic.ui.screen.interfaces.IActionBar;
import magic.ui.screen.interfaces.IPlayerProfileConsumer;
import magic.ui.screen.interfaces.IStatusBar;
import magic.ui.screen.widget.MenuButton;
import magic.ui.widget.HumanPlayerJList;
@SuppressWarnings("serial")
public class SelectHumanPlayerScreen
extends SelectPlayerAbstractScreen
implements IStatusBar, IActionBar {
private HumanPlayerJList profilesJList;
private IPlayerProfileConsumer consumer;
private final PlayerProfile playerProfile;
// CTR
public SelectHumanPlayerScreen(final IPlayerProfileConsumer consumer, final PlayerProfile playerProfile) {
this.consumer = consumer;
this.playerProfile = playerProfile;
refreshProfilesJList(playerProfile.getId());
}
/* (non-Javadoc)
* @see magic.ui.screen.PlayerScreenUtil#getProfilesListPanel()
*/
@Override
protected JPanel getProfilesListPanel() {
profilesJList = new HumanPlayerJList();
profilesJList.addMouseListener(getMouseAdapter());
return getContainerPanel(profilesJList);
}
private MouseAdapter getMouseAdapter() {
return new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
doNextAction();
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
};
}
private void refreshProfilesJList(final String selectedProfileId) {
profilesJList.setListData(getPlayerProfilesArray());
setSelectedListItem(selectedProfileId);
}
private void refreshProfilesJList() {
refreshProfilesJList(null);
}
private void setSelectedListItem(final String selectedProfileId) {
if (selectedProfileId == null || selectedProfileId.isEmpty()) {
profilesJList.setSelectedIndex(0);
} else {
profilesJList.setSelectedValue(profilesMap.get(selectedProfileId), true);
}
setFocusInProfilesJList(profilesJList);
}
private HumanPlayer[] getPlayerProfilesArray() {
setProfilesMap();
final List<PlayerProfile> profilesByName = new ArrayList<PlayerProfile>(profilesMap.values());
Collections.sort(profilesByName, new Comparator<PlayerProfile>() {
@Override
public int compare(PlayerProfile o1, PlayerProfile o2) {
return o1.getPlayerName().toLowerCase().compareTo(o2.getPlayerName().toLowerCase());
}
});
return profilesByName.toArray(new HumanPlayer[profilesByName.size()]);
}
private void setProfilesMap() {
profilesMap = PlayerProfiles.getHumanPlayerProfiles();
}
/* (non-Javadoc)
* @see magic.ui.screen.SelectPlayerAbstractScreen#createDefaultPlayerProfiles()
*/
@Override
protected void createDefaultPlayerProfiles() throws IOException {
final HumanPlayer profile = new HumanPlayer();
profile.setPlayerName(getDefaultPlayerProfileName());
profile.save();
}
private String getDefaultPlayerProfileName() {
final String systemUserName = System.getProperty("user.name");
return systemUserName == null ? "Player" : systemUserName;
}
/* (non-Javadoc)
* @see magic.ui.IMagStatusBar#getScreenCaption()
*/
@Override
public String getScreenCaption() {
return "Select Player";
}
/* (non-Javadoc)
* @see magic.ui.IMagActionBar#getLeftAction()
*/
@Override
public MenuButton getLeftAction() {
return new MenuButton("Cancel", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
getFrame().closeActiveScreen(false);
}
});
}
/* (non-Javadoc)
* @see magic.ui.IMagActionBar#getRightAction()
*/
@Override
public MenuButton getRightAction() {
return new MenuButton("Select", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
doNextAction();
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
});
}
/* (non-Javadoc)
* @see magic.ui.IMagActionBar#getMiddleActions()
*/
@Override
public List<MenuButton> getMiddleActions() {
final List<MenuButton> buttons = new ArrayList<MenuButton>();
buttons.add(new MenuButton("New", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
doNewPlayerProfile();
}
}, "Create a new player profile."));
buttons.add(new MenuButton("Edit", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
doEditPlayerProfile();
profilesJList.repaint();
}
}, "Update name and duel settings for selected player."));
buttons.add(new MenuButton("Delete", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
deleteSelectedPlayerProfile();
}
}, "Delete selected player profile."));
buttons.add(getAvatarActionButton());
return buttons;
}
private void doNewPlayerProfile() {
final String newName = (String)JOptionPane.showInputDialog(
getFrame(),
"<html><b>Player Name</b><br></html>",
"New Player",
JOptionPane.PLAIN_MESSAGE,
null, null, null);
if (newName != null && !newName.trim().isEmpty()) {
final PlayerProfile newProfile = new HumanPlayer();
newProfile.setPlayerName(newName);
newProfile.save();
PlayerProfiles.getPlayerProfiles().put(newProfile.getId(), newProfile);
refreshProfilesJList(newProfile.getId());
}
}
private void doEditPlayerProfile() {
final PlayerProfile profile = getSelectedPlayerProfile();
final String newName = (String)JOptionPane.showInputDialog(
getFrame(),
"<html><b>Player Name</b><br></html>",
"Update Player",
JOptionPane.PLAIN_MESSAGE,
null, null, profile.getPlayerName());
if (newName != null && !newName.trim().isEmpty()) {
profile.setPlayerName(newName.trim());
profile.save();
if (profile.getId().equals(playerProfile.getId())) {
consumer.setPlayerProfile(getSelectedPlayerProfile());
}
}
}
private void deleteSelectedPlayerProfile() {
final PlayerProfile profile = getSelectedPlayerProfile();
if (deleteSelectedPlayerProfile(profile)) {
PlayerProfiles.getPlayerProfiles().remove(profile.getId());
refreshProfilesJList();
if (profile.getId().equals(playerProfile.getId())) {
consumer.setPlayerProfile(getSelectedPlayerProfile());
}
}
}
private HumanPlayer getSelectedPlayerProfile() {
return profilesJList.getSelectedValue();
}
/* (non-Javadoc)
* @see magic.ui.MagScreen#canScreenClose()
*/
@Override
public boolean isScreenReadyToClose(final AbstractScreen nextScreen) {
return true;
}
/* (non-Javadoc)
* @see magic.ui.screen.IAvatarImageConsumer#setSelectedAvatarPath(java.nio.file.Path)
*/
@Override
public void setSelectedAvatarPath(final Path imagePath) {
final PlayerProfile profile = getSelectedPlayerProfile();
updateAvatarImage(imagePath, profile);
PlayerProfiles.refreshMap();
refreshProfilesJList(profile.getId());
consumer.setPlayerProfile(getSelectedPlayerProfile());
}
/* (non-Javadoc)
* @see magic.ui.screen.SelectPlayerScreen#getPlayerType()
*/
@Override
protected String getPlayerType() {
return "human";
}
/* (non-Javadoc)
* @see magic.ui.screen.SelectPlayerAbstractScreen#doNextAction()
*/
@Override
protected void doNextAction() {
consumer.setPlayerProfile(getSelectedPlayerProfile());
getFrame().closeActiveScreen(false);
}
/* (non-Javadoc)
* @see magic.ui.screen.interfaces.IStatusBar#getStatusPanel()
*/
@Override
public JPanel getStatusPanel() {
return null;
}
}

View File

@ -0,0 +1,207 @@
package magic.ui.screen;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.StandardCopyOption;
import java.nio.file.DirectoryStream.Filter;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import magic.MagicMain;
import magic.model.player.AiPlayer;
import magic.model.player.HumanPlayer;
import magic.model.player.PlayerProfile;
import magic.model.player.PlayerProfiles;
import magic.ui.screen.interfaces.IAvatarImageConsumer;
import magic.ui.screen.widget.MenuButton;
import magic.ui.widget.FontsAndBorders;
import magic.ui.widget.TexturedPanel;
import net.miginfocom.swing.MigLayout;
@SuppressWarnings("serial")
public abstract class SelectPlayerAbstractScreen
extends AbstractScreen
implements IAvatarImageConsumer {
protected final Path playersPath;
protected HashMap<String, PlayerProfile> profilesMap = new HashMap<String, PlayerProfile>();
protected abstract JPanel getProfilesListPanel();
protected abstract String getPlayerType();
protected abstract void createDefaultPlayerProfiles() throws IOException;
protected abstract void doNextAction();
// CTR
protected SelectPlayerAbstractScreen() {
this.playersPath = Paths.get(MagicMain.getPlayerProfilesPath()).resolve(getPlayerType());
setContent(getScreenContent());
setEnterKeyInputMap();
}
private void setEnterKeyInputMap() {
getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "EnterAction");
getActionMap().put("EnterAction", new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
doNextAction();
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
});
}
private JPanel getScreenContent() {
final JPanel content = new JPanel();
content.setLayout(new MigLayout("insets 2, center, center"));
content.setOpaque(false);
content.add(getProfilesListPanel(), "w 460!, h 400!");
return content;
}
protected JPanel getContainerPanel(final JList<? extends PlayerProfile> profilesJList) {
profilesJList.setOpaque(false);
final JPanel container = new TexturedPanel();
container.setLayout(new MigLayout("insets 0, gap 0, flowy"));
container.setBorder(FontsAndBorders.BLACK_BORDER);
container.setBackground(FontsAndBorders.MENUPANEL_COLOR);
container.add(getScrollPane(profilesJList), "w 100%, h 100%");
return container;
}
private JScrollPane getScrollPane(final JList<? extends PlayerProfile> profilesJList) {
final JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(profilesJList);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
scrollPane.setOpaque(false);
scrollPane.getViewport().setOpaque(false);
return scrollPane;
}
protected void setFocusInProfilesJList(final JList<? extends PlayerProfile> profilesJList) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
profilesJList.requestFocusInWindow();
}
});
}
protected void updateAvatarImage(final Path imagePath, final PlayerProfile playerProfile) {
final Path targetPath = playerProfile.getProfilePath().resolve("player.avatar");
try {
Files.copy(imagePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* Deletes all directory contents and then directory itself.
*/
protected void deleteDirectory(final Path root) {
try {
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if(exc == null){
Files.delete(dir);
return FileVisitResult.CONTINUE;
}
throw exc;
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
protected boolean deleteSelectedPlayerProfile(final PlayerProfile playerProfile) {
boolean isInvalidAction = false;
if (playerProfile instanceof HumanPlayer) {
isInvalidAction = (PlayerProfiles.getHumanPlayerProfiles().size() <= 1);
} else if (playerProfile instanceof AiPlayer) {
isInvalidAction = (PlayerProfiles.getAiPlayerProfiles().size() <= 1);
}
if (isInvalidAction) {
JOptionPane.showMessageDialog(this, "There must be at least one player.", "Invalid Action", JOptionPane.WARNING_MESSAGE);
return false;
}
if (playerProfile instanceof AiPlayer) {
if (PlayerProfiles.getAiPlayerProfiles().size() <= 1) {
JOptionPane.showMessageDialog(this, "There must be at least one player.");
return false;
}
}
final int action = JOptionPane.showOptionDialog(
this,
"<html>This will delete the <b>" + playerProfile.getPlayerName() + "</b> player profile.<br>" +
"All associated information such as player stats will also be removed.<br><br>" +
"<b>This action cannot be undone!</b></html>",
"Delete Player Profile?",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
new String[] {"Delete", "Cancel"}, "Cancel");
if (action == JOptionPane.YES_OPTION) {
final Path profilePath = playersPath.resolve(playerProfile.getId());
deleteDirectory(profilePath);
return true;
} else {
return false;
}
}
protected List<Path> getDirectoryPaths(final Path rootPath) {
final List<Path> paths = new ArrayList<Path>();
try (DirectoryStream<Path> ds = Files.newDirectoryStream(rootPath, new DirectoriesFilter())) {
for (Path p : ds) {
paths.add(p.getFileName());
}
} catch (IOException e) {
e.printStackTrace();
}
return paths;
}
private static class DirectoriesFilter implements Filter<Path> {
@Override
public boolean accept(Path entry) throws IOException {
return Files.isDirectory(entry);
}
}
protected MenuButton getAvatarActionButton() {
return new MenuButton("Avatar", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
getFrame().showAvatarImagesScreen(SelectPlayerAbstractScreen.this);
}
}, "Update avatar image of selected player profile.");
}
}

View File

@ -0,0 +1,7 @@
package magic.ui.screen.interfaces;
import java.nio.file.Path;
public interface IAvatarImageConsumer {
void setSelectedAvatarPath(final Path imagePath);
}

View File

@ -0,0 +1,10 @@
/**
*
*/
package magic.ui.screen.interfaces;
import magic.model.player.PlayerProfile;
public interface IPlayerProfileConsumer {
void setPlayerProfile(final PlayerProfile selectedPlayerProfile);
}

View File

@ -1,11 +1,17 @@
package magic.ui.screen.interfaces;
import javax.swing.JPanel;
/**
* A (Mag)screen that implements this interface will display MagStatusBar.
* A screen that implements this interface will display MagStatusBar.
*/
public interface IStatusBar {
/**
* Name of the screen. If null then MagStatusBar will be hidden.
*/
String getScreenCaption();
/**
* Can use to display a panel of info in central section of status bar.
*/
JPanel getStatusPanel();
}

View File

@ -7,7 +7,9 @@ import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import magic.data.IconImages;
import magic.ui.screen.interfaces.IActionBar;
import magic.ui.widget.FontsAndBorders;
import magic.ui.widget.TexturedPanel;
@ -36,11 +38,20 @@ public class ActionBar extends TexturedPanel {
addRightAction();
}
public void refreshLayout() {
setMagActionBarLayout();
validate();
repaint();
}
private void addRightAction() {
MenuButton action = actionProvider.getRightAction();
if (action != null) {
action.setEnabled(action.isRunnable());
if (action.getIcon() == null) {
action.setIcon(IconImages.NEXT_ICON);
}
action.setHorizontalTextPosition(SwingConstants.LEFT);
add(action);
}
}
@ -68,6 +79,8 @@ public class ActionBar extends TexturedPanel {
MenuButton action = actionProvider.getLeftAction();
if (action != null) {
action.setEnabled(action.isRunnable());
action.setIcon(IconImages.BACK_ICON);
action.setHorizontalTextPosition(SwingConstants.RIGHT);
add(action);
} else {
JLabel lbl = new JLabel();

View File

@ -0,0 +1,170 @@
package magic.ui.screen.widget;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import net.miginfocom.swing.MigLayout;
import magic.MagicUtility;
import magic.data.CubeDefinitions;
import magic.data.DuelConfig;
import magic.data.IconImages;
import magic.ui.MagicFrame;
import magic.ui.dialog.DuelPropertiesDialog;
import magic.ui.widget.FontsAndBorders;
import magic.ui.widget.TexturedPanel;
@SuppressWarnings("serial")
public class DuelSettingsPanel extends TexturedPanel {
private final MagicFrame frame;
private final DuelConfig config;
private int startLife;
private int handSize;
private int maxGames = 7;
private String cube = CubeDefinitions.getCubeNames()[0];
private final MouseAdapter mouseAdapter = getMouseAdapter();
public DuelSettingsPanel(final MagicFrame frame, final DuelConfig config) {
this.frame = frame;
this.config = config;
startLife = config.getStartLife();
handSize = config.getHandSize();
maxGames = config.getNrOfGames();
cube = config.getCube();
setBorder(FontsAndBorders.BLACK_BORDER);
setBackground(FontsAndBorders.MAGSCREEN_BAR_COLOR);
addMouseListener(mouseAdapter);
setLayout(new MigLayout("insets 0 5 0 0, gap 30, center"));
refreshDisplay();
}
@Override
public void setEnabled(boolean enabled) {
removeMouseListener(mouseAdapter);
if (enabled) {
addMouseListener(mouseAdapter);
} else {
setBorder(null);
setBackground(FontsAndBorders.TEXTAREA_TRANSPARENT_COLOR_HACK);
final StringBuilder sb = new StringBuilder();
sb.append("<html><b>Duel Settings</b><br>");
sb.append("Initial Player life: ").append(startLife).append("<br>");
sb.append("Initial Hand size: ").append(handSize).append("<br>");
sb.append("Maximum games: ").append(maxGames).append(" (first to ").append(getGamesRequiredToWinDuel()).append(")<br>");
sb.append("Cube: ").append(cube).append("</html>");
setToolTipText(sb.toString());
}
}
private int getGamesRequiredToWinDuel() {
return (int)Math.ceil(maxGames/2.0);
}
private void refreshDisplay() {
removeAll();
add(getDuelSettingsLabel(IconImages.LIFE_ICON, "" + startLife), "h 100%");
add(getDuelSettingsLabel(IconImages.HAND_ICON, "" + handSize), "h 100%");
add(getDuelSettingsLabel(IconImages.TARGET_ICON, "" + maxGames), "h 100%");
add(getDuelSettingsLabel(IconImages.CUBE_ICON, " " + getCubeNameWithoutSize()), "h 100%");
revalidate();
repaint();
}
private MouseAdapter getMouseAdapter() {
return new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
MagicUtility.setBusyMouseCursor(true);
updateDuelSettings();
MagicUtility.setBusyMouseCursor(false);
}
@Override
public void mouseEntered(MouseEvent e) {
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
setBorder(BorderFactory.createLineBorder(Color.YELLOW, 2));
setBackground(FontsAndBorders.MENUPANEL_COLOR);
}
@Override
public void mouseExited(MouseEvent e) {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
setBackground(FontsAndBorders.MAGSCREEN_BAR_COLOR);
}
};
}
private JLabel getDuelSettingsLabel(final ImageIcon icon, final String text) {
final JLabel lbl = new JLabel(text);
lbl.setIcon(icon);
lbl.setForeground(Color.WHITE);
lbl.setFont(new Font("Dialog", Font.PLAIN, 18));
lbl.setHorizontalAlignment(SwingConstants.CENTER);
return lbl;
}
public void updateDuelSettings() {
final DuelPropertiesDialog dialog =
new DuelPropertiesDialog(frame, handSize, startLife, maxGames, cube);
if (!dialog.isCancelled()) {
startLife = dialog.getStartLife();
handSize = dialog.getHandSize();
maxGames = dialog.getNrOfGames();
cube = dialog.getCube();
saveSettings();
refreshDisplay();
}
}
private void saveSettings() {
config.setStartLife(startLife);
config.setHandSize(handSize);
config.setNrOfGames(maxGames);
config.setCube(cube);
config.save();
}
public String getCube() {
return cube;
}
public int getStartLife() {
return startLife;
}
public int getHandSize() {
return handSize;
}
public int getNrOfGames() {
return maxGames;
}
private String getCubeNameWithoutSize() {
String verboseCubeName = toTitleCase(cube);
final int toIndex = verboseCubeName.indexOf("(");
if (toIndex == -1) {
return verboseCubeName;
} else {
return verboseCubeName.substring(0, toIndex).trim();
}
}
private String toTitleCase(final String text) {
return text.substring(0, 1).toUpperCase() + text.substring(1);
}
}

View File

@ -28,8 +28,8 @@ public class MenuButton extends JButton {
setButtonTransparent();
setFocusable(true);
setToolTipText(tooltip);
setMouseAdapter();
if (isRunnable) {
setMouseAdapter();
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
addActionListener(action);
}

View File

@ -7,6 +7,7 @@ import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import net.miginfocom.swing.MigLayout;
@ -34,10 +35,15 @@ public class StatusBar extends TexturedPanel {
private void layoutMagStatusBar() {
removeAll();
setLayout(new MigLayout("insets 0 0 0 6, gap 6, flowx, aligny 50%", "[grow, fill][][]"));
setLayout(new MigLayout("insets 0 0 0 6, gap 6, flowx, aligny 50%", "[32%][36%, center][32%, right]"));
if (magScreen != null) {
final IStatusBar screen = (IStatusBar)magScreen;
add(new CaptionPanel(screen.getScreenCaption()));
if (screen.getStatusPanel() != null) {
add(screen.getStatusPanel());
} else {
add(new JLabel());
}
if (magScreen.hasOptionsMenu()) {
add(getOptionsIconButton((IOptionsMenu)magScreen));
}

View File

@ -5,15 +5,16 @@ import java.awt.image.BufferedImage;
public class PlayerAvatar {
private static final int LARGE_SIZE = 120;
private static final int MEDIUM_SIZE = LARGE_SIZE/2;
public static final int LARGE_SIZE = 120;
public static final int MEDIUM_SIZE = LARGE_SIZE/2;
private static final int SMALL_SIZE = LARGE_SIZE/4;
private static final int CUSTOM_SIZE = 54;
public static final int CUSTOM_SIZE = 54;
private final ImageIcon largeIcon;
private final ImageIcon mediumIcon;
private final ImageIcon smallIcon;
private final ImageIcon turnIcon;
private ImageIcon largeIcon;
private ImageIcon mediumIcon;
private ImageIcon smallIcon;
private ImageIcon turnIcon;
private int face = 0;
public PlayerAvatar(final BufferedImage image) {
largeIcon = new ImageIcon(magic.ui.utility.GraphicsUtilities.scale(
@ -26,13 +27,21 @@ public class PlayerAvatar {
image,CUSTOM_SIZE,CUSTOM_SIZE));
}
public PlayerAvatar(final int face) {
this.face = face;
}
public ImageIcon getIcon(final int size) {
switch (size) {
if (face > 0) {
return ThemeFactory.getInstance().getCurrentTheme().getAvatarIcon(face, size);
} else {
switch (size) {
case 1: return smallIcon;
case 2: return mediumIcon;
case 3: return largeIcon;
case 4: return turnIcon;
default: throw new RuntimeException("PlayerAvatar.getIcon: invalid size " + size);
}
}
}
}

View File

@ -6,8 +6,6 @@ import magic.model.MagicCardDefinition;
import magic.model.MagicGame;
import magic.model.phase.MagicPhaseType;
import magic.ui.GameController;
import magic.ui.theme.Theme;
import magic.ui.theme.ThemeFactory;
import magic.ui.widget.TextLabel;
import magic.ui.widget.TitleBar;
@ -47,7 +45,6 @@ public class GameViewer extends JPanel implements ActionListener {
private final CardLayout actionCardLayout;
private final JPanel contentPanel;
private boolean actionEnabled;
private final Theme theme = ThemeFactory.getInstance().getCurrentTheme();
public GameViewer(final MagicGame game,final GameController controller) {
@ -196,7 +193,7 @@ public class GameViewer extends JPanel implements ActionListener {
* for use with the GameDuelViewer component.
*/
public ImageIcon getTurnSizedPlayerAvatar() {
return theme.getAvatarIcon(game.getTurnPlayer().getPlayerDefinition().getFace(), 4);
return game.getTurnPlayer().getPlayerDefinition().getAvatar().getIcon(4);
}
}

View File

@ -0,0 +1,135 @@
package magic.ui.widget;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.SwingConstants;
import magic.model.player.AiPlayer;
import net.miginfocom.swing.MigLayout;
@SuppressWarnings("serial")
public class AiPlayerJList
extends JList<AiPlayer> {
public AiPlayerJList() {
setOpaque(false);
setCellRenderer(new AiPlayerListRenderer());
}
private class AiPlayerListRenderer extends JLabel implements ListCellRenderer<AiPlayer> {
private Color foreColor;
private AiPlayer profile;
public AiPlayerListRenderer() {
setOpaque(false);
}
@Override
public Component getListCellRendererComponent(
JList<? extends AiPlayer> list,
AiPlayer profile,
int index,
boolean isSelected,
boolean cellHasFocus) {
this.profile = profile;
foreColor = isSelected ? Color.YELLOW : Color.WHITE;
final JPanel panel = new JPanel(new MigLayout("insets 0 0 0 6, gap 0"));
panel.setPreferredSize(new Dimension(0, 70));
panel.setOpaque(false);
panel.setForeground(foreColor);
panel.setBorder(isSelected ? BorderFactory.createLineBorder(Color.YELLOW, 1) : null);
panel.add(getAvatarPortrait(), "w 70!, h 70!");
panel.add(getNamePanel(), "w 100%");
panel.add(getDefaultDuelSettingsPanel(), "w 100%");
panel.add(getMiniStatsPanel());
panel.setToolTipText(profile.getAiType().toString());
return panel;
}
private JPanel getDefaultDuelSettingsPanel() {
final JPanel panel = new JPanel(new MigLayout("debug, insets 0 20 0 0, flowy"));
panel.setOpaque(false);
panel.add(getLabel("AI: " + profile.getAiType().name()), "w 100%");
panel.add(getLabel("Level: " + profile.getAiLevel() + " / 8"), "w 100%");
panel.add(getLabel("Extra Life: " + profile.getExtraLife()), "w 100%");
return panel;
}
private JLabel getLabel(final String caption) {
final JLabel lbl = new JLabel(caption);
lbl.setForeground(foreColor);
return lbl;
}
private JLabel getAvatarPortrait() {
return new JLabel(profile.getAvatar().getIcon(2));
}
private JPanel getMiniStatsPanel() {
final JPanel panel = new JPanel(new MigLayout("insets 0, gap 0, wrap 4", "[][30!]"));
panel.setOpaque(false);
panel.setForeground(foreColor);
panel.add(new JLabel());
panel.add(getStatsLabel("P", foreColor), "w 100%");
panel.add(getStatsLabel("W", foreColor), "w 100%");
panel.add(getStatsLabel("L", foreColor), "w 100%");
panel.add(getStatsLabel("Duels", foreColor), "w 60!");
panel.add(getStatsLabel(Integer.toString(profile.getStats().duelsPlayed), foreColor), "w 100%");
panel.add(getStatsLabel(Integer.toString(profile.getStats().duelsWon), foreColor), "w 100%");
panel.add(getStatsLabel(Integer.toString(profile.getStats().duelsPlayed - profile.getStats().duelsWon), foreColor), "w 100%");
panel.add(getStatsLabel("Games", foreColor), "w 60!");
panel.add(getStatsLabel(Integer.toString(profile.getStats().gamesPlayed), foreColor), "w 100%");
panel.add(getStatsLabel(Integer.toString(profile.getStats().gamesWon), foreColor), "w 100%");
panel.add(getStatsLabel(Integer.toString(profile.getStats().gamesPlayed - profile.getStats().gamesWon), foreColor), "w 100%");
return panel;
}
private JPanel getNamePanel() {
final JPanel panel = new JPanel(new MigLayout("insets 0, gap 0, flowy"));
panel.setOpaque(false);
panel.setForeground(foreColor);
panel.add(getPlayerNameLabel(), "gapbottom 4");
// panel.add(getAiTypeLabel());
panel.add(getTimestampLabel());
return panel;
}
private JLabel getTimestampLabel() {
final JLabel lbl = new JLabel("Last played: Never");
lbl.setForeground(foreColor);
// lbl.setBorder(BorderFactory.createDashedBorder(null));
return lbl;
}
private JLabel getPlayerNameLabel() {
final JLabel lbl = new JLabel(profile.getPlayerName());
lbl.setFont(FontsAndBorders.FONT2);
lbl.setForeground(foreColor);
lbl.setVerticalAlignment(SwingConstants.TOP);
// lbl.setBorder(BorderFactory.createDashedBorder(null));
return lbl;
}
private JLabel getStatsLabel(final String text, final Color foreColor) {
final JLabel lbl = new JLabel(text);
lbl.setHorizontalAlignment(SwingConstants.CENTER);
lbl.setBorder(BorderFactory.createDashedBorder(null));
lbl.setFont(FontsAndBorders.FONT0);
lbl.setForeground(foreColor);
return lbl;
}
}
}

View File

@ -0,0 +1,44 @@
package magic.ui.widget;
import java.awt.Color;
import java.awt.Font;
import javax.swing.JLabel;
import magic.ui.widget.TexturedPanel;
import net.miginfocom.swing.MigLayout;
@SuppressWarnings("serial")
public class DeckComboPanel extends TexturedPanel {
private final DecksComboBox decksComboBox;
public DeckComboPanel(final String deckGenerator) {
this.decksComboBox = new DecksComboBox(deckGenerator);
setBorder(FontsAndBorders.BLACK_BORDER);
setBackground(FontsAndBorders.MAGSCREEN_BAR_COLOR);
setLayout(new MigLayout("center, center"));
setOpaque(false);
add(getDeckLabel());
add(decksComboBox , "w 140!");
}
private JLabel getDeckLabel() {
final JLabel lbl = new JLabel("Random Deck:");
lbl.setFont(new Font("dialog", Font.PLAIN, 16));
lbl.setForeground(Color.WHITE);
return lbl;
}
/**
* @return
*/
public String getDeckGenerator() {
return decksComboBox.getSelectedItem();
}
}

View File

@ -0,0 +1,134 @@
package magic.ui.widget;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.Vector;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import magic.data.DeckGenerators;
import magic.data.IconImages;
import magic.model.MagicColor;
@SuppressWarnings("serial")
public class DecksComboBox extends JComboBox<String> implements ListCellRenderer<String> {
private static final String SEPARATOR = "----";
private String lastSelected;
public DecksComboBox(final String colors) {
setRenderer(this);
final Vector<String> items = new Vector<String>();
items.add("bug");
items.add("bur");
items.add("buw");
items.add("bgr");
items.add("bgw");
items.add("brw");
items.add("ugw");
items.add("ugr");
items.add("urw");
items.add("grw");
items.add("***");
items.add("bu");
items.add("bg");
items.add("br");
items.add("bw");
items.add("ug");
items.add("ur");
items.add("uw");
items.add("gr");
items.add("gw");
items.add("rw");
items.add("**");
items.add("b");
items.add("u");
items.add("g");
items.add("r");
items.add("w");
items.add("*");
items.add("@");
if (DeckGenerators.getInstance().getNrGenerators() > 0) {
items.add(SEPARATOR);
for(final String generatorName : DeckGenerators.getInstance().getGeneratorNames()) {
items.add(generatorName);
}
}
setModel(new DefaultComboBoxModel<String>(items));
setSelectedItem(colors);
lastSelected = colors;
this.setFocusable(false);
addActionListener(this);
}
@Override
public String getSelectedItem() {
return getItemAt(getSelectedIndex());
}
@Override
public Component getListCellRendererComponent(
final JList<? extends String> list,
final String selectedVal,
final int index,
final boolean isSelected,
final boolean cellHasFocus) {
if(selectedVal.equals(SEPARATOR)) {
return new javax.swing.JSeparator(javax.swing.JSeparator.HORIZONTAL);
} else if(DeckGenerators.getInstance().getGeneratorNames().contains(selectedVal)) {
final JPanel panel=new JPanel(new GridLayout(1,1));
panel.setBorder(FontsAndBorders.EMPTY_BORDER);
if (isSelected) {
panel.setBackground(Color.LIGHT_GRAY);
}
final JLabel label = new JLabel(selectedVal, JLabel.CENTER);
label.setFont(FontsAndBorders.FONT1);
panel.add(label);
return panel;
} else {
final JPanel panel=new JPanel(new GridLayout(1,3));
for (int i=0;i<selectedVal.length();i++) {
final char ch = selectedVal.charAt(i);
final ImageIcon icon;
switch (ch) {
case '*': icon=IconImages.ANY; break;
case '@': icon=IconImages.FOLDER; break;
default: icon=MagicColor.getColor(ch).getIcon(); break;
}
panel.add(new JLabel(icon));
}
panel.setBorder(FontsAndBorders.EMPTY_BORDER);
if (isSelected) {
panel.setBackground(Color.LIGHT_GRAY);
}
return panel;
}
}
public void actionPerformed(final ActionEvent e) {
final String tempItem = getSelectedItem();
if (SEPARATOR.equals(tempItem)) {
// don't select separator
setSelectedItem(lastSelected);
} else {
lastSelected = tempItem;
}
}
}

View File

@ -0,0 +1,160 @@
package magic.ui.widget;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import net.miginfocom.swing.MigLayout;
import magic.MagicUtility;
import magic.data.DuelConfig;
import magic.model.player.HumanPlayer;
import magic.model.player.PlayerProfile;
import magic.ui.MagicFrame;
import magic.ui.screen.interfaces.IPlayerProfileConsumer;
import magic.ui.widget.TexturedPanel;
@SuppressWarnings("serial")
public class DuelPlayerPanel
extends TexturedPanel
implements IPlayerProfileConsumer {
private final MagicFrame frame;
private PlayerProfilePanel playerProfilePanel;
private PlayerProfile playerProfile;
// CTR
public DuelPlayerPanel(final MagicFrame frame, final PlayerProfile playerProfile) {
this.frame = frame;
this.playerProfile = playerProfile;
this.playerProfilePanel = getPlayerProfilePanel();
setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
setBackground(FontsAndBorders.MAGSCREEN_BAR_COLOR);
doMigLayout();
addMouseListener(getMouseAdapter());
}
private MouseAdapter getMouseAdapter() {
return new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
MagicUtility.setBusyMouseCursor(true);
selectNewProfile();
mouseExited(e);
MagicUtility.setBusyMouseCursor(false);
}
@Override
public void mouseEntered(MouseEvent e) {
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
setBorder(BorderFactory.createLineBorder(Color.YELLOW, 2));
setBackground(FontsAndBorders.MENUPANEL_COLOR);
}
@Override
public void mouseExited(MouseEvent e) {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
setBackground(FontsAndBorders.MAGSCREEN_BAR_COLOR);
}
};
}
private void doMigLayout() {
removeAll();
setLayout(new MigLayout("flowy, gapy 10"));
add(playerProfilePanel, "w 100%, h 70!");
add(getStatisticsPanel(), "w 100%, h 100%");
}
private JPanel getStatisticsPanel() {
final JPanel panel = new JPanel(new MigLayout("insets 0 6 0 0"));
panel.setOpaque(false);
final JTextArea textArea = new JTextArea(playerProfile.getStats().toString());
textArea.setEditable(false);
textArea.setFocusable(false);
textArea.setTabSize(16);
textArea.setBackground(new Color(0,0,0,1));
textArea.setBorder(null);
textArea.setForeground(Color.LIGHT_GRAY);
textArea.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) { DuelPlayerPanel.this.dispatchEvent(e); }
@Override
public void mouseEntered(MouseEvent e) { DuelPlayerPanel.this.dispatchEvent(e); }
@Override
public void mouseExited(MouseEvent e) { DuelPlayerPanel.this.dispatchEvent(e); }
});
panel.add(textArea, "w 100%, h 100%");
// MagicUtility.setDebugBorder(panel);
return panel;
}
public PlayerProfile getPlayerProfile() {
return playerProfile;
}
public void selectNewProfile() {
if (playerProfile instanceof HumanPlayer) {
frame.showSelectHumanPlayerScreen(this, playerProfile);
} else {
frame.showSelectAiProfileScreen(this, playerProfile);
}
}
/* (non-Javadoc)
* @see magic.ui.screen.duel.IPlayerProfileConsumer#setPlayerProfile(magic.model.player.PlayerProfile)
*/
@Override
public void setPlayerProfile(PlayerProfile selectedPlayerProfile) {
if (selectedPlayerProfile != null) {
playerProfile = selectedPlayerProfile;
if (selectedPlayerProfile instanceof HumanPlayer) {
DuelConfig.getInstance().setPlayerOneProfile(selectedPlayerProfile);
} else {
DuelConfig.getInstance().setPlayerTwoProfile(selectedPlayerProfile);
}
DuelConfig.getInstance().save();
}
playerProfilePanel = new PlayerProfilePanel(playerProfile);
doMigLayout();
}
private PlayerProfilePanel getPlayerProfilePanel() {
final PlayerProfilePanel panel = new PlayerProfilePanel(playerProfile);
panel.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) { DuelPlayerPanel.this.dispatchEvent(e); }
@Override
public void mouseEntered(MouseEvent e) { DuelPlayerPanel.this.dispatchEvent(e); }
@Override
public void mouseExited(MouseEvent e) { DuelPlayerPanel.this.dispatchEvent(e); }
});
return panel;
}
private class PlayerProfilePanel extends JPanel {
private PlayerProfile profile;
public PlayerProfilePanel(final PlayerProfile profile) {
this.profile = profile;
setPreferredSize(new Dimension(0, 70));
setOpaque(false);
doMigLayout();
}
private void doMigLayout() {
removeAll();
setLayout(new MigLayout("insets 0 0 0 6, gap 0"));
add(new JLabel(profile.getAvatar().getIcon(2)), "w 70!, h 70!");
add(new PlayerDetailsPanel(profile), "w 100%");
}
}
}

View File

@ -0,0 +1,132 @@
package magic.ui.widget;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.SwingConstants;
import magic.model.player.HumanPlayer;
import net.miginfocom.swing.MigLayout;
@SuppressWarnings("serial")
public class HumanPlayerJList
extends JList<HumanPlayer> {
public HumanPlayerJList() {
setOpaque(false);
setCellRenderer(new HumanPlayerListRenderer());
}
private class HumanPlayerListRenderer extends JPanel implements ListCellRenderer<HumanPlayer> {
private Color foreColor;
private HumanPlayer profile;
public HumanPlayerListRenderer() {
setOpaque(false);
}
@Override
public Component getListCellRendererComponent(
JList<? extends HumanPlayer> list,
HumanPlayer profile,
int index,
boolean isSelected,
boolean cellHasFocus) {
this.profile = profile;
foreColor = isSelected ? Color.YELLOW : Color.WHITE;
final JPanel panel = new JPanel(new MigLayout("insets 0 0 0 6, gap 0"));
panel.setPreferredSize(new Dimension(0, 70));
panel.setOpaque(false);
panel.setForeground(foreColor);
panel.setBorder(isSelected ? BorderFactory.createLineBorder(Color.YELLOW, 1) : null);
panel.add(getAvatarPortrait(), "w 70!, h 70!");
panel.add(getNamePanel(), "w 100%");
// panel.add(getDefaultDuelSettingsPanel(), "w 100%");
panel.add(getMiniStatsPanel());
return panel;
}
// private JPanel getDefaultDuelSettingsPanel() {
// final JPanel panel = new JPanel(new MigLayout("debug, insets 0 20 0 0, flowy"));
// panel.setOpaque(false);
// panel.add(getLabel("Life: " + profile.getPlayerLife()), "w 100%");
// panel.add(getLabel("Hand: " + profile.getHandSize()), "w 100%");
// panel.add(getLabel("Win: " + profile.getGamesToWin()), "w 100%");
// return panel;
// }
// private JLabel getLabel(final String caption) {
// final JLabel lbl = new JLabel(caption);
// lbl.setForeground(foreColor);
// return lbl;
// }
private JLabel getAvatarPortrait() {
return new JLabel(profile.getAvatar().getIcon(2));
}
private JPanel getMiniStatsPanel() {
final JPanel panel = new JPanel(new MigLayout("insets 0, gap 0, wrap 4", "[][30!]"));
panel.setOpaque(false);
panel.setForeground(foreColor);
panel.add(new JLabel());
panel.add(getStatsLabel("P", foreColor), "w 100%");
panel.add(getStatsLabel("W", foreColor), "w 100%");
panel.add(getStatsLabel("L", foreColor), "w 100%");
panel.add(getStatsLabel("Duels", foreColor), "w 60!");
panel.add(getStatsLabel(Integer.toString(profile.getStats().duelsPlayed), foreColor), "w 100%");
panel.add(getStatsLabel(Integer.toString(profile.getStats().duelsWon), foreColor), "w 100%");
panel.add(getStatsLabel(Integer.toString(profile.getStats().duelsPlayed - profile.getStats().duelsWon), foreColor), "w 100%");
panel.add(getStatsLabel("Games", foreColor), "w 60!");
panel.add(getStatsLabel(Integer.toString(profile.getStats().gamesPlayed), foreColor), "w 100%");
panel.add(getStatsLabel(Integer.toString(profile.getStats().gamesWon), foreColor), "w 100%");
panel.add(getStatsLabel(Integer.toString(profile.getStats().gamesPlayed - profile.getStats().gamesWon), foreColor), "w 100%");
return panel;
}
private JPanel getNamePanel() {
final JPanel panel = new JPanel(new MigLayout("insets 0, gap 0, flowy"));
panel.setOpaque(false);
panel.setForeground(foreColor);
panel.add(getPlayerNameLabel(), "w 100%, gapbottom 4");
panel.add(getTimestampLabel());
return panel;
}
private JLabel getTimestampLabel() {
final JLabel lbl = new JLabel("Last played: " + profile.getStats().getLastPlayed());
lbl.setForeground(foreColor);
return lbl;
}
private JLabel getPlayerNameLabel() {
final JLabel lbl = new JLabel(profile.getPlayerName());
lbl.setFont(FontsAndBorders.FONT2);
lbl.setForeground(foreColor);
lbl.setVerticalAlignment(SwingConstants.TOP);
return lbl;
}
private JLabel getStatsLabel(final String text, final Color foreColor) {
final JLabel lbl = new JLabel(text);
lbl.setHorizontalAlignment(SwingConstants.CENTER);
lbl.setBorder(BorderFactory.createDashedBorder(null));
lbl.setFont(FontsAndBorders.FONT0);
lbl.setForeground(foreColor);
return lbl;
}
}
}

View File

@ -2,8 +2,6 @@ package magic.ui.widget;
import magic.data.IconImages;
import magic.model.MagicMessage;
import magic.ui.theme.Theme;
import magic.ui.theme.ThemeFactory;
import net.miginfocom.swing.MigLayout;
import javax.swing.JLabel;
@ -100,8 +98,6 @@ public class MessagePanel extends JPanel {
}
private JLabel getPlayerAvatar() {
final Theme theme = ThemeFactory.getInstance().getCurrentTheme();
final int face = message.getPlayer().getPlayerDefinition().getFace();
return new JLabel(theme.getAvatarIcon(face,1));
return new JLabel(message.getPlayer().getPlayerDefinition().getAvatar().getIcon(1));
}
}

View File

@ -5,7 +5,6 @@ import magic.ui.theme.Theme;
import magic.ui.theme.ThemeFactory;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.border.Border;
import java.awt.BorderLayout;
@ -77,15 +76,14 @@ public class PlayerAvatarPanel extends TexturedPanel {
private void update() {
if (playerDefinition != null) {
final Theme theme=ThemeFactory.getInstance().getCurrentTheme();
final ImageIcon faceIcon=theme.getAvatarIcon(playerDefinition.getFace(),small?2:3);
faceLabel.setIcon(faceIcon);
faceLabel.setIcon(playerDefinition.getAvatar().getIcon(small?2:3));
titleBar.setText(playerDefinition.getName());
if (small) {
titleBar.setVisible(false);
setPreferredSize(new Dimension(72,80));
} else {
new JLabel(faceIcon);
titleBar.setVisible(true);
setPreferredSize(new Dimension(132,150));
}

View File

@ -0,0 +1,74 @@
package magic.ui.widget;
import java.awt.Color;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import magic.model.player.AiPlayer;
import magic.model.player.PlayerProfile;
import net.miginfocom.swing.MigLayout;
@SuppressWarnings("serial")
public class PlayerDetailsPanel extends JPanel {
private final Color foreColor;
private final PlayerProfile profile;
// CTR
public PlayerDetailsPanel(final PlayerProfile profile, final Color foreColor) {
this.profile = profile;
this.foreColor = foreColor;
setOpaque(false);
setForeground(foreColor);
setLayout(new MigLayout("insets 0, gap 0, flowy"));
layoutComponents();
}
public PlayerDetailsPanel(final PlayerProfile profile) {
this(profile, Color.WHITE);
}
private void layoutComponents() {
add(getPlayerTypeLabel(), "w 100%");
add(getPlayerNameLabel(), "w 100%");
add(getPlayerPropertiesLabel(), "w 100%");
}
private JLabel getPlayerTypeLabel() {
final JLabel lbl = new JLabel();
lbl.setFont(FontsAndBorders.FONT0);
lbl.setForeground(foreColor);
if (profile instanceof AiPlayer) {
final AiPlayer player = (AiPlayer)profile;
lbl.setText("AI : " + player.getAiType());
}
return lbl;
}
private JLabel getPlayerNameLabel() {
final JLabel lbl = new JLabel(profile.getPlayerName());
lbl.setFont(FontsAndBorders.FONT3);
lbl.setForeground(foreColor);
lbl.setVerticalAlignment(SwingConstants.TOP);
return lbl;
}
private JLabel getPlayerPropertiesLabel() {
JLabel lbl = new JLabel();
if (profile instanceof AiPlayer) {
lbl = getAiPlayerProperties();
}
return lbl;
}
private JLabel getAiPlayerProperties() {
final AiPlayer player = (AiPlayer)profile;
final JLabel lbl = new JLabel("Level: " + player.getAiLevel() + " Extra Life: " + player.getExtraLife());
lbl.setFont(FontsAndBorders.FONT0);
lbl.setForeground(foreColor);
return lbl;
}
}